-
Notifications
You must be signed in to change notification settings - Fork 9.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Replace Zend_Mail (ZF1) with Zend\Mail (ZF2) #8608
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
.
/** | ||
* @param string $charset | ||
*/ | ||
public function __construct($charset = 'utf-8') | ||
{ | ||
parent::__construct($charset); | ||
$this->encoding = $charset; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Method name must begin with verb, I suggest createHtmlMimeFromString
.
{ | ||
return $this->messageType == self::TYPE_TEXT ? $this->getBodyText() : $this->getBodyHtml(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
@@ -6,7 +6,8 @@ | |||
*/ | |||
namespace Magento\Framework\Mail; | |||
|
|||
class Transport extends \Zend_Mail_Transport_Sendmail implements \Magento\Framework\Mail\TransportInterface | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Useless new line and phpcs
does not enforce it yet.
@@ -6,7 +6,8 @@ | |||
*/ | |||
namespace Magento\Framework\Mail; | |||
|
|||
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do aggregation instead of inheritance.
@@ -20,8 +21,8 @@ class Transport extends \Zend_Mail_Transport_Sendmail implements \Magento\Framew | |||
*/ | |||
public function __construct(\Magento\Framework\Mail\MessageInterface $message, $parameters = null) | |||
{ | |||
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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!