Skip to content
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

Merged
merged 13 commits into from
Jul 12, 2017
Merged

Replace Zend_Mail (ZF1) with Zend\Mail (ZF2) #8608

merged 13 commits into from
Jul 12, 2017

Conversation

schmengler
Copy link
Contributor

@schmengler schmengler commented Feb 19, 2017

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!

@orlangur
Copy link
Contributor

needs more work, at least more testing, I cannot believe that it is so easy

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 Magento_Framework and not Zend_Mail directly work as before (just like integration tests, people will not be happy getting such errors after upgrade).

Will share my thoughts on the code a bit later.

@schmengler
Copy link
Contributor Author

True, true... One integration test is failing, another one caused fatal error :) Check Travis CI.

I've seen it, but could not look into the details yet. I tried to take care not to change the Magento_Framework behavior, and it's possible that tests are only failing because mocks have to be changed.

I'm waiting for your feedback on the code now!

use Zend\Mime\Part;

/**
* @todo composition instead of inheritance for better testability
Copy link
Contributor

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;
Copy link
Contributor

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)
Copy link
Contributor

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);
Copy link
Contributor

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();
Copy link
Contributor

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

Copy link
Contributor

@orlangur orlangur Feb 22, 2017

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
Copy link
Contributor

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) {
Copy link
Contributor

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
Copy link
Contributor

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
Copy link
Contributor

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?

Copy link
Contributor Author

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) and mixed 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.

Copy link
Contributor Author

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

@orlangur
Copy link
Contributor

@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.

@okorshenko okorshenko self-assigned this Feb 26, 2017
@okorshenko okorshenko added this to the February 2017 milestone Feb 26, 2017
@maksek maksek modified the milestones: February 2017, March 2017 Mar 1, 2017
@okorshenko okorshenko added this to the March 2017 milestone Mar 1, 2017
@okorshenko
Copy link
Contributor

Hi @schmengler
Are you going to proceed this with PR?

@schmengler
Copy link
Contributor Author

@okorshenko yes as soon as I find some time for it

@okorshenko
Copy link
Contributor

@schmengler thank you. Please let us know when you will be ready. Thank you

@okorshenko okorshenko removed their assignment Mar 17, 2017
@okorshenko okorshenko removed this from the March 2017 milestone Mar 17, 2017
@schmengler
Copy link
Contributor Author

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 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) and mixed 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.

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

I already added one method getRawMessage() because otherwise it would not be possible to have a Zend transport implementation by only using the message interface and not the underlying Zend message, so the PR will cause a BC break anyways. But IMHO it's a minor one and it is necessary to get the mail interfaces right.

@schmengler
Copy link
Contributor Author

schmengler commented Mar 19, 2017

And while we are at it, shouldn't TransportInterface look like this:

    function sendMessage(MessageInterface $message);

instead of

    function sendMessage()

?

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 TransportBuilder class, which actually builds a message. That would be much simpler and clearer if we did not couple the transport to the message like currently.

@okorshenko okorshenko self-assigned this Jul 6, 2017
@okorshenko
Copy link
Contributor

Hi @schmengler
Just FYI: we stabilized this branch and working on the testing of new changes.

@magento-team magento-team merged commit b7186fc into magento:develop Jul 12, 2017
magento-team pushed a commit that referenced this pull request Jul 12, 2017
 - 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()
magento-team pushed a commit that referenced this pull request Jul 12, 2017
 - removed methods getBodyHtml() and getBodyText(). Use method getBody()
magento-team pushed a commit that referenced this pull request Jul 12, 2017
magento-team pushed a commit that referenced this pull request Jul 12, 2017
magento-team pushed a commit that referenced this pull request Jul 12, 2017
@0m3r
Copy link
Contributor

0m3r commented Dec 19, 2018

What about getHeaders and setHeaders for \Magento\Mail\Message?

I want to set headers like a in-reply-to, message-id, references etc.

@klein0r
Copy link
Contributor

klein0r commented Mar 30, 2019

Is there a reason why this has been included into 2.2.8?

@orlangur
Copy link
Contributor

orlangur commented Apr 1, 2019

@klein0r yep, backward compatibility is the reason.

magento-devops-reposync-svc pushed a commit that referenced this pull request Mar 7, 2024
…fix-10272023

Cia 2.4.7 beta3 develop bugfix 10272023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants