Replace Zend_Mail (ZF1) with Zend\Mail (ZF2)#8608
Replace Zend_Mail (ZF1) with Zend\Mail (ZF2)#8608magento-team merged 13 commits intomagento:developfrom schmengler:zend-mail-2
Conversation
True, true... One integration test is failing, another one caused fatal error :) Check Travis CI. Note that refactoring should be performed in such a way that all existing customizations relying on Will share my thoughts on the code a bit later. |
I've seen it, but could not look into the details yet. I tried to take care not to change the I'm waiting for your feedback on the code now! |
| use Zend\Mime\Part; | ||
|
|
||
| /** | ||
| * @todo composition instead of inheritance for better testability |
There was a problem hiding this comment.
Do it now and expose only necessary public methods.
Otherwise people may rely on Zend implementation rather then on narrowed interface and we will continue to have problems like Fatal Error with absent getBodyHtml.
| public function __construct($charset = 'utf-8') | ||
| { | ||
| parent::__construct($charset); | ||
| $this->encoding = $charset; |
There was a problem hiding this comment.
Rename constructor argument accordingly and use setEncoding method of \Zend\Mail\Message instead (currently $this->getHeaders()->setEncoding($encoding); is missed).
| * @return $this | ||
| */ | ||
| public function setBody($body) | ||
| public function setMessageType($type) |
There was a problem hiding this comment.
Please preserve order of methods to simplify checking of correspondence during review (getBody -> getBody, setBody -> setBody etc).
| { | ||
| return $this->messageType == self::TYPE_TEXT ? $this->getBodyText() : $this->getBodyHtml(); | ||
| if (is_string($body) && $this->messageType === MessageInterface::TYPE_HTML) { | ||
| $body = self::htmlMimeFromString($body); |
There was a problem hiding this comment.
Method name must begin with verb, I suggest createHtmlMimeFromString.
| public function getBody() | ||
| public function setBody($body) | ||
| { | ||
| return $this->messageType == self::TYPE_TEXT ? $this->getBodyText() : $this->getBodyHtml(); |
There was a problem hiding this comment.
Calls of getBodyHtml must be fixed all over the code, this is why we saw Fatal Error on Travis. Integration tests do not use mocks usually.
| namespace Magento\Framework\Mail; | ||
|
|
||
| class Transport extends \Zend_Mail_Transport_Sendmail implements \Magento\Framework\Mail\TransportInterface | ||
|
|
There was a problem hiding this comment.
Useless new line and phpcs does not enforce it yet.
|
|
||
| class Transport extends \Zend_Mail_Transport_Sendmail implements \Magento\Framework\Mail\TransportInterface | ||
|
|
||
| class Transport extends \Zend\Mail\Transport\Sendmail implements \Magento\Framework\Mail\TransportInterface |
There was a problem hiding this comment.
Do aggregation instead of inheritance.
| { | ||
| if (!$message instanceof \Zend_Mail) { | ||
| throw new \InvalidArgumentException('The message should be an instance of \Zend_Mail'); | ||
| if (!$message instanceof \Zend\Mail\Message) { |
There was a problem hiding this comment.
I don't think we should keep classes inherited from Zend classes in the system.
Just create necessary instance of \Zend\Mail\Message in sendMessage method instead.
|
|
||
| /** | ||
| * @todo composition instead of inheritance for better testability | ||
| * - add a ZendMailDecorator interface with getZendMail() method for usage in \Magento\Framework\Mail\Transport |
There was a problem hiding this comment.
Please no. To me it looks like \Zend\Mail\Message has all necessary setters already.
| * @todo composition instead of inheritance for better testability | ||
| * - add a ZendMailDecorator interface with getZendMail() method for usage in \Magento\Framework\Mail\Transport | ||
| * @todo get rid of temporal coupling (setMessageType() + setBody()) | ||
| * - deprecate setMessageType(), implement a HtmlMessage decorator instead |
There was a problem hiding this comment.
I don't think such decorator would be really valuable. Do we have some needed cases not covered with current text/html types implementation?
There was a problem hiding this comment.
The problem with the current implementation is that you have to call setMessageType() before setBody(). I'm now considering changing the MessageInterface interface. As it should be used via TransportBuilder, it should not have serious impact.
- The current signatures
setBody(mixed $body)andmixed getBody()are not meaningful. Either "mixed" must be replaced with "string" or we are leaking the zend abstraction. - The interface does not allow multitype mails (this is the needed case not covered. Something that Magento always has been lacking of)
One idea is, replacing setMessageType(), setBody() and getBody() with:
setBodyHtml(string $html)setBodyText(string $text)string getBodyText()string getBodyHtml()
This allows text mails, HTML mails, and multitype mails, does not require calling them in any specific order and does not reveal anything of the underlying Zend mail component.
There was a problem hiding this comment.
Another advantage is that this resembles the old zf1 implementation, so 3rd party code is actually less likely to break even though we have to change an @api interface
|
@schmengler, thanks for your efforts, implementation in general looks quite clean and minimalistic (just does what is really necessary). Please make sure all builds are green before next review iteration. |
|
Hi @schmengler |
|
@okorshenko yes as soon as I find some time for it |
|
@schmengler thank you. Please let us know when you will be ready. Thank you |
Conflicts: composer.lock
|
Because it's hidden now in the "outdated" review, here again my concerns about the message interface: The problem with the current implementation is that you have to call
One idea is, replacing
This allows text mails, HTML mails, and multitype mails, does not require calling them in any specific order and does not reveal anything of the underlying Zend mail component. Another advantage is that this resembles the old zf1 implementation, so 3rd party code is actually less likely to break even though we have to change an I already added one method |
|
And while we are at it, shouldn't instead of ? I don't understand, why the "Transport" implementation receives the message in the constructor. I'd rather have the transport instance reusable for different messages. With the current implementation we have the |
The transport now can take any implementation of the message interface as argument
- updated composer.lock file
|
Hi @schmengler |
- Introduced new interface MailMessageInterface and deprecated MessageInterface to keep backward compatibility - get rid of temporal coupling (setMessageType() + setBody()) - deprecated setMessageType(), setBody() and getBody() - implemented setBodyHtml(), setBodyText(), getBodyHtml() and getBodyText() - changed usage in \Magento\Framework\Mail\Template\TransportBuilder::prepareMessage()
- removed methods getBodyHtml() and getBodyText(). Use method getBody()
- fixed integration tests
|
What about getHeaders and setHeaders for \Magento\Mail\Message? I want to set headers like a in-reply-to, message-id, references etc. |
|
Is there a reason why this has been included into 2.2.8? |
|
@klein0r yep, backward compatibility is the reason. |
…fix-10272023 Cia 2.4.7 beta3 develop bugfix 10272023
This PR probably needs more work, at least more testing, I cannot believe that it is so easy.
Opening for review and acceptance tests. If it's working I plan to refactor the code a bit (see TODO comments) - feedback appreciated!