How I Fixed: \Swift_Message::newInstance() not found

I had a recent requirement to overwrite the Mailer  class provided as part of FOSUserBundle.

There’s a protected method in this class as follows:

    /**
     * @param string       $renderedTemplate
     * @param array|string $fromEmail
     * @param array|string $toEmail
     */
    protected function sendEmailMessage($renderedTemplate, $fromEmail, $toEmail)
    {
        // Render the email, use the first line as the subject, and the rest as the body
        $renderedLines = explode("\n", trim($renderedTemplate));
        $subject = array_shift($renderedLines);
        $body = implode("\n", $renderedLines);

        $message = \Swift_Message::newInstance()
            ->setSubject($subject)
            ->setFrom($fromEmail)
            ->setTo($toEmail)
            ->setBody($body);

        $this->mailer->send($message);
    }

Seems fairly straightforward.

Notice that PhpStorm sees nothing wrong with this method:

Being the lazy dev, I started by copy / pasting the entire contents of this class to form the basis of my own Mailer  implementation. Cue confusion:

I’ve used this \Swift_Message::newInstance()  code before, so I know it works. A quick check of the Symfony docs, and the SwiftMailer docs both seemed to confirm that what I was trying to do was correct:

(I checked the docs for Symfony 3.2, 3.3, and 3.4)

I thought it was just PhpStorm being a bit weird, but then I ran my code and saw things like this:

Attempted to call an undefined method named “newInstance” of class “Swift_Message”.

Diving through the code did indeed seem to show no references to newInstance .

Quite odd.

Anyway, sending an email – whilst important – wasn’t super urgent, so I commented out the code and added it to my GitLab issues list.

Whilst browsing Twitter later that evening I noticed:

I then remembered that being hasty to try new and shiny things was probably the cause of my problems.

Sure enough it turned out I’m using dev-master of SwiftMailer in my project. A quick glance of the changelog:

6.0.0 (2017-05-19)
------------------

 * added Swift_Transport::ping()
 * removed Swift_Mime_HeaderFactory, Swift_Mime_HeaderSet, Swift_Mime_Message, Swift_Mime_MimeEntity,
   and Swift_Mime_ParameterizedHeader interfaces
 * removed Swift_MailTransport and Swift_Transport_MailTransport
 * removed Swift_Encoding
 * removed the Swift_Transport_MailInvoker interface and Swift_Transport_SimpleMailInvoker class
 * removed the Swift_SignedMessage class
 * removed newInstance() methods everywhere
 * methods operating on Date header now use DateTimeImmutable object instead of Unix timestamp;
   Swift_Mime_Headers_DateHeader::getTimestamp()/setTimestamp() renamed to getDateTime()/setDateTime()
 * bumped minimum version to PHP 7.0

This looks like the culprit:

removed newInstance() methods everywhere

Fixing this is really simple:

$message = \Swift_Message::newInstance()
    ->setSubject('My important message subject')
    ->setFrom($this->supportEmail)
    ->setTo($user->getEmailCanonical())
    ->setBody($body, 'text/html')
;

becomes:

$message = (new \Swift_Message('My important subject here'))
    ->setFrom($this->mailingFromAddress, $this->mailingFromName)
    ->setTo($user->getEmailCanonical())
    ->setBody($body, 'text/html')
;

And as is often the case, when the provided objects / methods are used properly, things do work 🙂

Update – There is already an open PR to fix this in the docs: https://github.com/swiftmailer/swiftmailer/issues/925