From 83f57709ed4078a2c7c941be69a92924967af356 Mon Sep 17 00:00:00 2001
From: Piotr Potrebka <piotr.potrebka@wpdesk.net>
Date: Wed, 1 Feb 2023 11:50:43 +0100
Subject: [PATCH] feat: email abstract

---
 src/Abstracts/EmailAbstract.php  |  23 ++++
 src/Abstracts/EmailInterface.php |  10 ++
 src/Mailer.php                   | 177 +++++++++----------------------
 3 files changed, 86 insertions(+), 124 deletions(-)

diff --git a/src/Abstracts/EmailAbstract.php b/src/Abstracts/EmailAbstract.php
index d0d8730..274c336 100644
--- a/src/Abstracts/EmailAbstract.php
+++ b/src/Abstracts/EmailAbstract.php
@@ -58,6 +58,20 @@ abstract class EmailAbstract implements EmailInterface {
      */
     abstract public function get_id(): string;
 
+    /**
+     * @return string
+     */
+    public function get_from(): string {
+        return '';
+    }
+
+    /**
+     * @return string
+     */
+    public function get_from_name(): string {
+        return '';
+    }
+
     /**
      * @return bool
      */
@@ -274,5 +288,14 @@ abstract class EmailAbstract implements EmailInterface {
         return $this->content;
     }
 
+    /**
+     * @param string $string
+     *
+     * @return array|string|string[]
+     */
+    protected function replace_placeholders( string $string ): string {
+        return (string) str_replace( array_keys( $this->placeholders ), array_values( $this->placeholders ), $string );
+    }
+
 
 }
diff --git a/src/Abstracts/EmailInterface.php b/src/Abstracts/EmailInterface.php
index c82a432..35e9469 100644
--- a/src/Abstracts/EmailInterface.php
+++ b/src/Abstracts/EmailInterface.php
@@ -11,6 +11,16 @@ interface EmailInterface {
      */
     public function get_id(): string;
 
+    /**
+     * @return string
+     */
+    public function get_from(): string;
+
+    /**
+     * @return string
+     */
+    public function get_from_name(): string;
+
     /**
      * Is enable.
      *
diff --git a/src/Mailer.php b/src/Mailer.php
index cc1d146..f8b5e02 100644
--- a/src/Mailer.php
+++ b/src/Mailer.php
@@ -2,13 +2,14 @@
 
 namespace WPDesk\Library\WPEmail;
 
+use Exception;
+use WP_Error;
 use WPDesk\Library\WPEmail\Abstracts\EmailInterface;
 use WPDesk\Library\WPEmail\Helpers\HTML;
 use WPDesk\View\Renderer\Renderer;
 use WPDesk\View\Renderer\SimplePhpRenderer;
 use WPDesk\View\Resolver\ChainResolver;
 use WPDesk\View\Resolver\DirResolver;
-use WPDesk\View\Resolver\Resolver;
 
 class Mailer {
 
@@ -17,52 +18,29 @@ class Mailer {
      */
     private $emails = [];
 
-    /**
-     * @var string
-     */
-    private $from;
-
-    /**
-     * @var string
-     */
-    private $from_name;
-
     /**
      * @var Renderer
      */
     private $renderer;
 
     /**
-     * @var array
-     */
-    protected $placeholders = [];
-
-    /**
-     * @param string     $from
-     * @param string     $from_name
-     * @param Resolver[] $dir_resolvers
+     * @param array $dirs
      */
     public function __construct(
-        string $from = 'wordpress@wordpress.org',
-        string $from_name = 'WordPress',
-        array $dir_resolvers = []
+        array $dirs = []
     ) {
-        $this->from      = $from;
-        $this->from_name = $from_name;
-        $this->set_renderer( $this->init_renderer( $dir_resolvers ) );
+        $this->set_renderer( $this->init_renderer( $dirs ) );
     }
 
     /**
-     * @param array $dir_resolvers
+     * @param array $dirs
      *
      * @return Renderer
      */
-    private function init_renderer( array $dir_resolvers ): Renderer {
+    private function init_renderer( array $dirs = [] ): Renderer {
         $resolver = new ChainResolver();
-        foreach ( $dir_resolvers as $dir_resolver ) {
-            if ( $dir_resolver instanceof Resolver ) {
-                $resolver->appendResolver( $dir_resolver );
-            }
+        foreach ( $dirs as $dir ) {
+            $resolver->appendResolver( new DirResolver( $dir ) );
         }
         $resolver->appendResolver( new DirResolver( __DIR__ ) );
 
@@ -94,99 +72,59 @@ class Mailer {
         return $this->emails;
     }
 
-
-    /**
-     * Set placeholders.
-     *
-     * @param array $placeholders
-     *
-     * @return self
-     */
-    public function set_placeholders( array $placeholders = [] ): self {
-        $this->placeholders = array_merge( $this->placeholders, $placeholders );
-
-        return $this;
-    }
-
-    /**
-     * Get defined placeholders.
-     *
-     * @return string[]
-     */
-    public function get_placeholders(): array {
-        return $this->placeholders;
-    }
-
-    /**
-     * WordPress callback for setting the from email
-     *
-     * @param string $email
-     *
-     * @return string
-     */
-    public function from_filter( string $email ): string {
-        if ( ! empty( $this->from ) && is_email( $this->from ) ) {
-            $email = $this->from;
-        }
-
-        return $email;
-    }
-
-
-    /**
-     * WordPress callback for setting the from name
-     *
-     * @param string $name
-     *
-     * @return string
-     */
-    public function from_name_filter( string $name ): string {
-        if ( ! empty( $this->from_name ) ) {
-            $name = html_entity_decode( sanitize_text_field( $this->from_name ) );
-        }
-
-        return $name;
-    }
-
-    /**
-     * Add filters before fire wp_mail.
-     *
-     * @return void
-     */
-    protected function before_wp_mail() {
-        add_filter( 'wp_mail_from', array( $this, 'from_filter' ) );
-        add_filter( 'wp_mail_from_name', array( $this, 'from_name_filter' ) );
-    }
-
+    /** @return void */
     public function send() {
-        $this->before_wp_mail();
         foreach ( $this->get_emails() as $email ) {
-            $subject = $this->replace_placeholders( $email->get_subject() );
-            if ( $email->get_is_enable() ) {
-                wp_mail(
-                    $email->get_recipients(), $subject, $this->get_body( $email ), $email->get_headers(), $email->get_attachments()
+            add_filter(
+                'wp_mail_from',
+                $from_cb = static function () use ( $email ) {
+                    return $email->get_from();
+                }
+            );
+            add_filter(
+                'wp_mail_from_name',
+                $from_name_cb = static function () use ( $email ) {
+                    return $email->get_from_name();
+                }
+            );
+            add_action( 'wp_mail_failed', [ $this, 'catch_error' ] );
+
+            try {
+                $success = wp_mail(
+                    $email->get_recipients(),
+                    $email->get_subject(),
+                    $this->get_email_template( $email ),
+                    $email->get_headers(),
+                    $email->get_attachments()
                 );
+                if ( ! $success ) {
+                    throw new MailerException( 'Count not send the mail with wp_mail()' );
+                }
+            } catch ( Exception $e ) {
+                if ( $e instanceof MailerException ) {
+                    throw $e;
+                }
+
+                throw new MailerException( sprintf( 'wp_mail() failure. Original error: %s', $e->getMessage() ), 0, $e );
+            } finally {
+                remove_action( 'wp_mail_failed', [ $this, 'catch_error' ], 99999 );
+                remove_filter( 'wp_mail_from', $from_cb );
+                remove_filter( 'wp_mail_from_name', $from_name_cb );
             }
         }
-        $this->after_wp_mail();
     }
 
-    protected function get_body( EmailInterface $email ): string {
-        $content = $this->replace_placeholders( $email->get_content() );
-        $output  = $this->renderer->render( 'html/email-header', [ 'heading' => $email->get_heading(), 'logo' => '' ] );
-        $output  .= $this->renderer->render( 'html/' . $email->get_id(), [ 'content' => $content ] );
-        $output  .= $this->renderer->render( 'html/email-footer', [ 'footer' => '' ] );
-
-        return $this->css_inline( $output );
+    /** @return void */
+    public function catch_error( WP_Error $error ) {
+        throw MailerException::with_wp_error( $error );
     }
 
-    /**
-     * @param string $string
-     *
-     * @return array|string|string[]
-     */
-    protected function replace_placeholders( string $string ): string {
-        return (string) str_replace( array_keys( $this->placeholders ), array_values( $this->placeholders ), $string );
+    protected function get_email_template( EmailInterface $email ): string {
+        $output = $this->renderer->render( 'html/email-header', [ 'heading' => $email->get_heading(), 'logo' => '' ] );
+        $output .= $this->renderer->render( 'html/' . $email->get_id(), [ 'content' => $email->get_content() ] );
+        $output .= $this->renderer->render( 'html/email-footer', [ 'footer' => '' ] );
+
+        return $this->css_inline( $output );
     }
 
     /**
@@ -200,14 +138,5 @@ class Mailer {
         return HTML::style_inline( $content, $styles );
     }
 
-    /**
-     * Remove filters after fire wp_mail.
-     *
-     * @return void
-     */
-    protected function after_wp_mail() {
-        remove_filter( 'wp_mail_from', array( $this, 'from_filter' ) );
-        remove_filter( 'wp_mail_from_name', array( $this, 'from_name_filter' ) );
-    }
 
 }
-- 
GitLab