From c0aea1f3a7cca0b871d8ca9a43f8dfc9759dec84 Mon Sep 17 00:00:00 2001 From: Andrew Hill Date: Thu, 26 Nov 2020 15:59:11 +0000 Subject: [PATCH] Remove di for Message preference, update TransportBuilder to handle attachment, update SenderBuilder to use TransportBuilder --- Model/Email/SenderBuilder.php | 469 ++++++++++++++++++++++++++----- Model/Email/TransportBuilder.php | 451 ++++++++++++++++++++++++++++- etc/di.xml | 7 +- 3 files changed, 853 insertions(+), 74 deletions(-) diff --git a/Model/Email/SenderBuilder.php b/Model/Email/SenderBuilder.php index 097af34..9a2a1bd 100644 --- a/Model/Email/SenderBuilder.php +++ b/Model/Email/SenderBuilder.php @@ -6,117 +6,456 @@ namespace Eadesigndev\Pdfgenerator\Model\Email; -use Eadesigndev\Pdfgenerator\Model\Pdfgenerator; -use Magento\Sales\Model\Order\Email\Container\IdentityInterface; -use Magento\Sales\Model\Order\Email\Container\Template; -use Eadesigndev\Pdfgenerator\Helper\Pdf; -use Eadesigndev\Pdfgenerator\Helper\Data; -use Magento\Framework\Stdlib\DateTime\DateTime; -use Magento\Sales\Model\Order\Invoice; - -class SenderBuilder extends \Magento\Sales\Model\Order\Email\SenderBuilder +use Magento\Framework\App\TemplateTypesInterface; +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\Exception\MailException; +use Magento\Framework\Mail\EmailMessageInterface; +use Magento\Framework\Mail\EmailMessageInterfaceFactory; +use Magento\Framework\Mail\AddressConverter; +use Magento\Framework\Mail\Exception\InvalidArgumentException; +use Magento\Framework\Mail\MessageInterface; +use Magento\Framework\Mail\MessageInterfaceFactory; +use Magento\Framework\Mail\MimeInterface; +use Magento\Framework\Mail\MimeMessageInterfaceFactory; +use Magento\Framework\Mail\MimePartInterfaceFactory; +use Magento\Framework\Mail\Template\FactoryInterface; +use Magento\Framework\Mail\Template\SenderResolverInterface; +use Magento\Framework\Mail\TemplateInterface; +use Magento\Framework\Mail\TransportInterface; +use Magento\Framework\Mail\TransportInterfaceFactory; +use Magento\Framework\ObjectManagerInterface; +use Magento\Framework\Phrase; +use Zend\Mime\Mime; +use Zend\Mime\PartFactory; + +/** + * TransportBuilder + * + * @api + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + * @since 100.0.2 + */ +class TransportBuilder extends \Magento\Framework\Mail\Template\TransportBuilder { + /** + * Template Identifier + * + * @var string + */ + protected $templateIdentifier; + + /** + * Template Model + * + * @var string + */ + protected $templateModel; + + /** + * Template Variables + * + * @var array + */ + protected $templateVars; + + /** + * Template Options + * + * @var array + */ + protected $templateOptions; + + /** + * Mail Transport + * + * @var TransportInterface + */ + protected $transport; + + /** + * Template Factory + * + * @var FactoryInterface + */ + protected $templateFactory; + + /** + * Object Manager + * + * @var ObjectManagerInterface + */ + protected $objectManager; + + /** + * Message + * + * @var EmailMessageInterface + */ + protected $message; + + /** + * Sender resolver + * + * @var SenderResolverInterface + */ + protected $_senderResolver; + + /** + * @var TransportInterfaceFactory + */ + protected $mailTransportFactory; + + /** + * Param that used for storing all message data until it will be used + * + * @var array + */ + private $messageData = []; /** - * @var Pdf + * @var EmailMessageInterfaceFactory */ - private $helper; + private $emailMessageInterfaceFactory; /** - * @var Data + * @var MimeMessageInterfaceFactory */ - private $dataHelper; + private $mimeMessageInterfaceFactory; /** - * @var DateTime + * @var MimePartInterfaceFactory */ - private $dateTime; + private $mimePartInterfaceFactory; /** - * SenderBuilder constructor. - * @param Template $templateContainer - * @param IdentityInterface $identityContainer - * @param TransportBuilder $transportBuilder - * @param Pdf $helper - * @param Data $dataHelper - * @param DateTime $dateTime + * @var AddressConverter|null + */ + private $addressConverter; + + protected $attachments = []; + + protected $partFactory; + + /** + * TransportBuilder constructor + * + * @param FactoryInterface $templateFactory + * @param MessageInterface $message + * @param SenderResolverInterface $senderResolver + * @param ObjectManagerInterface $objectManager + * @param TransportInterfaceFactory $mailTransportFactory + * @param MessageInterfaceFactory|null $messageFactory + * @param EmailMessageInterfaceFactory|null $emailMessageInterfaceFactory + * @param MimeMessageInterfaceFactory|null $mimeMessageInterfaceFactory + * @param MimePartInterfaceFactory|null $mimePartInterfaceFactory + * @param addressConverter|null $addressConverter + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( - Template $templateContainer, - IdentityInterface $identityContainer, - TransportBuilder $transportBuilder, - Pdf $helper, - Data $dataHelper, - DateTime $dateTime + FactoryInterface $templateFactory, + MessageInterface $message, + SenderResolverInterface $senderResolver, + ObjectManagerInterface $objectManager, + TransportInterfaceFactory $mailTransportFactory, + MessageInterfaceFactory $messageFactory = null, + EmailMessageInterfaceFactory $emailMessageInterfaceFactory = null, + MimeMessageInterfaceFactory $mimeMessageInterfaceFactory = null, + MimePartInterfaceFactory $mimePartInterfaceFactory = null, + AddressConverter $addressConverter = null ) { - $this->helper = $helper; - $this->dataHelper = $dataHelper; - $this->dateTime = $dateTime; - parent::__construct($templateContainer, $identityContainer, $transportBuilder); + $this->templateFactory = $templateFactory; + $this->objectManager = $objectManager; + $this->_senderResolver = $senderResolver; + $this->mailTransportFactory = $mailTransportFactory; + $this->emailMessageInterfaceFactory = $emailMessageInterfaceFactory ?: $this->objectManager + ->get(EmailMessageInterfaceFactory::class); + $this->mimeMessageInterfaceFactory = $mimeMessageInterfaceFactory ?: $this->objectManager + ->get(MimeMessageInterfaceFactory::class); + $this->mimePartInterfaceFactory = $mimePartInterfaceFactory ?: $this->objectManager + ->get(MimePartInterfaceFactory::class); + $this->addressConverter = $addressConverter ?: $this->objectManager + ->get(AddressConverter::class); + $this->partFactory = $objectManager->get(PartFactory::class); + parent::__construct($templateFactory, $message, $senderResolver, $objectManager, $mailTransportFactory, $messageFactory, $emailMessageInterfaceFactory, $mimeMessageInterfaceFactory, + $mimePartInterfaceFactory, $addressConverter); } /** - * Add attachment to the main mail + * Add cc address + * + * @param array|string $address + * @param string $name + * + * @return $this */ - public function send() + public function addCc($address, $name = '') { - $vars = $this->templateContainer->getTemplateVars(); - $this->checkInvoice($vars); + $this->addAddressByType('cc', $address, $name); - parent::send(); + return $this; } /** - * Add attachment to the css/bcc mail + * Add to address + * + * @param array|string $address + * @param string $name + * + * @return $this + * @throws InvalidArgumentException */ - public function sendCopyTo() + public function addTo($address, $name = '') { - $vars = $this->templateContainer->getTemplateVars(); - $this->checkInvoice($vars); - parent::sendCopyTo(); + $this->addAddressByType('to', $address, $name); + + return $this; } /** + * Add bcc address * - * Check if we need to send the invoice email + * @param array|string $address * - * @param $vars * @return $this + * @throws InvalidArgumentException */ - private function checkInvoice($vars) + public function addBcc($address) { - if (!$this->dataHelper->isEmail()) { - return $this; - } + $this->addAddressByType('bcc', $address); + + return $this; + } + + /** + * Set Reply-To Header + * + * @param string $email + * @param string|null $name + * + * @return $this + * @throws InvalidArgumentException + */ + public function setReplyTo($email, $name = null) + { + $this->addAddressByType('replyTo', $email, $name); + + return $this; + } + + /** + * Set mail from address + * + * @param string|array $from + * + * @return $this + * @throws InvalidArgumentException + * @see setFromByScope() + * + * @deprecated 102.0.1 This function sets the from address but does not provide + * a way of setting the correct from addresses based on the scope. + */ + public function setFrom($from) + { + return $this->setFromByScope($from); + } + + /** + * Set mail from address by scopeId + * + * @param string|array $from + * @param string|int $scopeId + * + * @return $this + * @throws InvalidArgumentException + * @throws MailException + * @since 102.0.1 + */ + public function setFromByScope($from, $scopeId = null) + { + $result = $this->_senderResolver->resolve($from, $scopeId); + $this->addAddressByType('from', $result['email'], $result['name']); + + return $this; + } + + /** + * Set template identifier + * + * @param string $templateIdentifier + * + * @return $this + */ + public function setTemplateIdentifier($templateIdentifier) + { + $this->templateIdentifier = $templateIdentifier; + + return $this; + } + + /** + * Set template model + * + * @param string $templateModel + * + * @return $this + */ + public function setTemplateModel($templateModel) + { + $this->templateModel = $templateModel; + return $this; + } + + /** + * Set template vars + * + * @param array $templateVars + * + * @return $this + */ + public function setTemplateVars($templateVars) + { + $this->templateVars = $templateVars; + + return $this; + } + + /** + * Set template options + * + * @param array $templateOptions + * @return $this + */ + public function setTemplateOptions($templateOptions) + { + $this->templateOptions = $templateOptions; + + return $this; + } - if (!array_key_exists('invoice', $vars)) { - return $this; + /** + * Get mail transport + * + * @return TransportInterface + * @throws LocalizedException + */ + public function getTransport() + { + try { + $this->prepareMessage(); + $mailTransport = $this->mailTransportFactory->create(['message' => clone $this->message]); + } finally { + $this->reset(); } - if ($vars['invoice'] instanceof Invoice) { - $invoice = $vars['invoice']; - $helper = $this->helper; + return $mailTransport; + } - $helper->setInvoice($invoice); + /** + * Reset object state + * + * @return $this + */ + protected function reset() + { + $this->messageData = []; + $this->templateIdentifier = null; + $this->templateVars = null; + $this->templateOptions = null; + return $this; + } + + /** + * Get template + * + * @return TemplateInterface + */ + protected function getTemplate() + { + return $this->templateFactory->get($this->templateIdentifier, $this->templateModel) + ->setVars($this->templateVars) + ->setOptions($this->templateOptions); + } - /** @var Pdfgenerator $template */ - $template = $this->dataHelper->getTemplateStatus($invoice); + /** + * Prepare message. + * + * @return $this + * @throws LocalizedException if template type is unknown + */ + protected function prepareMessage() + { + $template = $this->getTemplate(); + $content = $template->processTemplate(); + switch ($template->getType()) { + case TemplateTypesInterface::TYPE_TEXT: + $part['type'] = MimeInterface::TYPE_TEXT; + break; - if (empty($template->getId())) { - return $this; - } + case TemplateTypesInterface::TYPE_HTML: + $part['type'] = MimeInterface::TYPE_HTML; + break; - $helper->setTemplate($template); + default: + throw new LocalizedException( + new Phrase('Unknown template type') + ); + } + $mimePart = $this->mimePartInterfaceFactory->create(['content' => $content]); + $parts = count($this->attachments) ? array_merge([$mimePart], $this->attachments) : [$mimePart]; + $this->messageData['body'] = $this->mimeMessageInterfaceFactory->create( + ['parts' => $parts] + ); - $pdfFileData = $helper->template2Pdf(); + $this->messageData['subject'] = html_entity_decode( + (string)$template->getSubject(), + ENT_QUOTES + ); + $this->message = $this->emailMessageInterfaceFactory->create($this->messageData); - $date = $this->dateTime->date('Y-m-d_H-i-s'); + return $this; + } - $this->transportBuilder->addAttachment( - $pdfFileData['filestream'], - $pdfFileData['filename'] . $date . '.pdf' + /** + * Handles possible incoming types of email (string or array) + * + * @param string $addressType + * @param string|array $email + * @param string|null $name + * + * @return void + * @throws InvalidArgumentException + */ + private function addAddressByType(string $addressType, $email, ?string $name = null): void + { + if (is_string($email)) { + $this->messageData[$addressType][] = $this->addressConverter->convert($email, $name); + return; + } + $convertedAddressArray = $this->addressConverter->convertMany($email); + if (isset($this->messageData[$addressType])) { + $this->messageData[$addressType] = array_merge( + $this->messageData[$addressType], + $convertedAddressArray ); } + } + + /** + * @param string|null $content + * @param string|null $fileName + * @param string|null $fileType + * @return TransportBuilder + */ + public function addAttachment(?string $content, ?string $fileName, ?string $fileType) + { + $attachmentPart = $this->partFactory->create(); + $attachmentPart->setContent($content) + ->setType($fileType) + ->setFileName($fileName) + ->setDisposition(Mime::DISPOSITION_ATTACHMENT) + ->setEncoding(Mime::ENCODING_BASE64); + $this->attachments[] = $attachmentPart; return $this; } diff --git a/Model/Email/TransportBuilder.php b/Model/Email/TransportBuilder.php index 606f988..9a2a1bd 100644 --- a/Model/Email/TransportBuilder.php +++ b/Model/Email/TransportBuilder.php @@ -6,14 +6,457 @@ namespace Eadesigndev\Pdfgenerator\Model\Email; -use Magento\Framework\Mail\Template\TransportBuilder as TransportBuilderParent; +use Magento\Framework\App\TemplateTypesInterface; +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\Exception\MailException; +use Magento\Framework\Mail\EmailMessageInterface; +use Magento\Framework\Mail\EmailMessageInterfaceFactory; +use Magento\Framework\Mail\AddressConverter; +use Magento\Framework\Mail\Exception\InvalidArgumentException; +use Magento\Framework\Mail\MessageInterface; +use Magento\Framework\Mail\MessageInterfaceFactory; +use Magento\Framework\Mail\MimeInterface; +use Magento\Framework\Mail\MimeMessageInterfaceFactory; +use Magento\Framework\Mail\MimePartInterfaceFactory; +use Magento\Framework\Mail\Template\FactoryInterface; +use Magento\Framework\Mail\Template\SenderResolverInterface; +use Magento\Framework\Mail\TemplateInterface; +use Magento\Framework\Mail\TransportInterface; +use Magento\Framework\Mail\TransportInterfaceFactory; +use Magento\Framework\ObjectManagerInterface; +use Magento\Framework\Phrase; +use Zend\Mime\Mime; +use Zend\Mime\PartFactory; -class TransportBuilder extends TransportBuilderParent +/** + * TransportBuilder + * + * @api + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + * @since 100.0.2 + */ +class TransportBuilder extends \Magento\Framework\Mail\Template\TransportBuilder { + /** + * Template Identifier + * + * @var string + */ + protected $templateIdentifier; + + /** + * Template Model + * + * @var string + */ + protected $templateModel; + + /** + * Template Variables + * + * @var array + */ + protected $templateVars; + + /** + * Template Options + * + * @var array + */ + protected $templateOptions; + + /** + * Mail Transport + * + * @var TransportInterface + */ + protected $transport; + + /** + * Template Factory + * + * @var FactoryInterface + */ + protected $templateFactory; + + /** + * Object Manager + * + * @var ObjectManagerInterface + */ + protected $objectManager; + + /** + * Message + * + * @var EmailMessageInterface + */ + protected $message; + + /** + * Sender resolver + * + * @var SenderResolverInterface + */ + protected $_senderResolver; + + /** + * @var TransportInterfaceFactory + */ + protected $mailTransportFactory; + + /** + * Param that used for storing all message data until it will be used + * + * @var array + */ + private $messageData = []; + + /** + * @var EmailMessageInterfaceFactory + */ + private $emailMessageInterfaceFactory; + + /** + * @var MimeMessageInterfaceFactory + */ + private $mimeMessageInterfaceFactory; + + /** + * @var MimePartInterfaceFactory + */ + private $mimePartInterfaceFactory; + + /** + * @var AddressConverter|null + */ + private $addressConverter; + + protected $attachments = []; + + protected $partFactory; + + /** + * TransportBuilder constructor + * + * @param FactoryInterface $templateFactory + * @param MessageInterface $message + * @param SenderResolverInterface $senderResolver + * @param ObjectManagerInterface $objectManager + * @param TransportInterfaceFactory $mailTransportFactory + * @param MessageInterfaceFactory|null $messageFactory + * @param EmailMessageInterfaceFactory|null $emailMessageInterfaceFactory + * @param MimeMessageInterfaceFactory|null $mimeMessageInterfaceFactory + * @param MimePartInterfaceFactory|null $mimePartInterfaceFactory + * @param addressConverter|null $addressConverter + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * @SuppressWarnings(PHPMD.ExcessiveParameterList) + */ + public function __construct( + FactoryInterface $templateFactory, + MessageInterface $message, + SenderResolverInterface $senderResolver, + ObjectManagerInterface $objectManager, + TransportInterfaceFactory $mailTransportFactory, + MessageInterfaceFactory $messageFactory = null, + EmailMessageInterfaceFactory $emailMessageInterfaceFactory = null, + MimeMessageInterfaceFactory $mimeMessageInterfaceFactory = null, + MimePartInterfaceFactory $mimePartInterfaceFactory = null, + AddressConverter $addressConverter = null + ) { + $this->templateFactory = $templateFactory; + $this->objectManager = $objectManager; + $this->_senderResolver = $senderResolver; + $this->mailTransportFactory = $mailTransportFactory; + $this->emailMessageInterfaceFactory = $emailMessageInterfaceFactory ?: $this->objectManager + ->get(EmailMessageInterfaceFactory::class); + $this->mimeMessageInterfaceFactory = $mimeMessageInterfaceFactory ?: $this->objectManager + ->get(MimeMessageInterfaceFactory::class); + $this->mimePartInterfaceFactory = $mimePartInterfaceFactory ?: $this->objectManager + ->get(MimePartInterfaceFactory::class); + $this->addressConverter = $addressConverter ?: $this->objectManager + ->get(AddressConverter::class); + $this->partFactory = $objectManager->get(PartFactory::class); + parent::__construct($templateFactory, $message, $senderResolver, $objectManager, $mailTransportFactory, $messageFactory, $emailMessageInterfaceFactory, $mimeMessageInterfaceFactory, + $mimePartInterfaceFactory, $addressConverter); + } + + /** + * Add cc address + * + * @param array|string $address + * @param string $name + * + * @return $this + */ + public function addCc($address, $name = '') + { + $this->addAddressByType('cc', $address, $name); + + return $this; + } + + /** + * Add to address + * + * @param array|string $address + * @param string $name + * + * @return $this + * @throws InvalidArgumentException + */ + public function addTo($address, $name = '') + { + $this->addAddressByType('to', $address, $name); + + return $this; + } + + /** + * Add bcc address + * + * @param array|string $address + * + * @return $this + * @throws InvalidArgumentException + */ + public function addBcc($address) + { + $this->addAddressByType('bcc', $address); + + return $this; + } + + /** + * Set Reply-To Header + * + * @param string $email + * @param string|null $name + * + * @return $this + * @throws InvalidArgumentException + */ + public function setReplyTo($email, $name = null) + { + $this->addAddressByType('replyTo', $email, $name); + + return $this; + } + + /** + * Set mail from address + * + * @param string|array $from + * + * @return $this + * @throws InvalidArgumentException + * @see setFromByScope() + * + * @deprecated 102.0.1 This function sets the from address but does not provide + * a way of setting the correct from addresses based on the scope. + */ + public function setFrom($from) + { + return $this->setFromByScope($from); + } + + /** + * Set mail from address by scopeId + * + * @param string|array $from + * @param string|int $scopeId + * + * @return $this + * @throws InvalidArgumentException + * @throws MailException + * @since 102.0.1 + */ + public function setFromByScope($from, $scopeId = null) + { + $result = $this->_senderResolver->resolve($from, $scopeId); + $this->addAddressByType('from', $result['email'], $result['name']); - public function addAttachment($content, $fileName) + return $this; + } + + /** + * Set template identifier + * + * @param string $templateIdentifier + * + * @return $this + */ + public function setTemplateIdentifier($templateIdentifier) + { + $this->templateIdentifier = $templateIdentifier; + + return $this; + } + + /** + * Set template model + * + * @param string $templateModel + * + * @return $this + */ + public function setTemplateModel($templateModel) + { + $this->templateModel = $templateModel; + return $this; + } + + /** + * Set template vars + * + * @param array $templateVars + * + * @return $this + */ + public function setTemplateVars($templateVars) { - $this->message->setBodyAttachment($content, $fileName); + $this->templateVars = $templateVars; + + return $this; + } + + /** + * Set template options + * + * @param array $templateOptions + * @return $this + */ + public function setTemplateOptions($templateOptions) + { + $this->templateOptions = $templateOptions; + + return $this; + } + + /** + * Get mail transport + * + * @return TransportInterface + * @throws LocalizedException + */ + public function getTransport() + { + try { + $this->prepareMessage(); + $mailTransport = $this->mailTransportFactory->create(['message' => clone $this->message]); + } finally { + $this->reset(); + } + + return $mailTransport; + } + + /** + * Reset object state + * + * @return $this + */ + protected function reset() + { + $this->messageData = []; + $this->templateIdentifier = null; + $this->templateVars = null; + $this->templateOptions = null; + return $this; + } + + /** + * Get template + * + * @return TemplateInterface + */ + protected function getTemplate() + { + return $this->templateFactory->get($this->templateIdentifier, $this->templateModel) + ->setVars($this->templateVars) + ->setOptions($this->templateOptions); + } + + /** + * Prepare message. + * + * @return $this + * @throws LocalizedException if template type is unknown + */ + protected function prepareMessage() + { + $template = $this->getTemplate(); + $content = $template->processTemplate(); + switch ($template->getType()) { + case TemplateTypesInterface::TYPE_TEXT: + $part['type'] = MimeInterface::TYPE_TEXT; + break; + + case TemplateTypesInterface::TYPE_HTML: + $part['type'] = MimeInterface::TYPE_HTML; + break; + + default: + throw new LocalizedException( + new Phrase('Unknown template type') + ); + } + $mimePart = $this->mimePartInterfaceFactory->create(['content' => $content]); + $parts = count($this->attachments) ? array_merge([$mimePart], $this->attachments) : [$mimePart]; + $this->messageData['body'] = $this->mimeMessageInterfaceFactory->create( + ['parts' => $parts] + ); + + $this->messageData['subject'] = html_entity_decode( + (string)$template->getSubject(), + ENT_QUOTES + ); + $this->message = $this->emailMessageInterfaceFactory->create($this->messageData); + + return $this; + } + + /** + * Handles possible incoming types of email (string or array) + * + * @param string $addressType + * @param string|array $email + * @param string|null $name + * + * @return void + * @throws InvalidArgumentException + */ + private function addAddressByType(string $addressType, $email, ?string $name = null): void + { + if (is_string($email)) { + $this->messageData[$addressType][] = $this->addressConverter->convert($email, $name); + return; + } + $convertedAddressArray = $this->addressConverter->convertMany($email); + if (isset($this->messageData[$addressType])) { + $this->messageData[$addressType] = array_merge( + $this->messageData[$addressType], + $convertedAddressArray + ); + } + } + + /** + * @param string|null $content + * @param string|null $fileName + * @param string|null $fileType + * @return TransportBuilder + */ + public function addAttachment(?string $content, ?string $fileName, ?string $fileType) + { + $attachmentPart = $this->partFactory->create(); + $attachmentPart->setContent($content) + ->setType($fileType) + ->setFileName($fileName) + ->setDisposition(Mime::DISPOSITION_ATTACHMENT) + ->setEncoding(Mime::ENCODING_BASE64); + $this->attachments[] = $attachmentPart; + return $this; } } diff --git a/etc/di.xml b/etc/di.xml index 0333a9e..6de0f87 100644 --- a/etc/di.xml +++ b/etc/di.xml @@ -10,13 +10,10 @@ type="Eadesigndev\Pdfgenerator\Model\Pdfgenerator" /> - - - +