Symfony2, Twig i SwiftMailer czyli rzecz o obrazkach w mailu

Ongiś pisanie maili w HTML-u było naruszeniem netykiety, ale obecnie zdecydowana większość odbiorców jak i nadawców woli otrzymywać maile w HTML-u. Generowanie i wysyłanie takowych w aplikacji opartej na Symfony2 jest banalnie proste dzięki Twigowi i Swift Mailerowi. Nieco mniej przyjemnie zaczyna się robić, kiedy w treści maili ma pojawić się grafika.

Możliwości są dwie i każda rodzi pewne problemy:

  1. Linkowanie do plików na zdalnym serwerze. Niestety funkcja url() w Twigu akceptuje tylko ścieżki zdefiniowane w routingu, nie można nią linkować do grafik. Z kolei znacznik image obsługiwany przez Assetica domyślnie generuje relatywne URL-e, a poza tym jest trochę nieporęczny w użyciu.
  2. Osadzenie plików w wiadomości. Tu problem natury programistycznej polega na tym, że żeby osadzić grafikę w wiadomości trzeba skorzystać z metody Swift_Message::embed(), do której nie mamy dostępu z poziomu Twiga.

Wszystkie powyższe problemy można rozwiązać tworząc rozszerzenie do Twiga.

namespace MDurys\MailBundle\Twig;

use Symfony\Component\DependencyInjection\ContainerInterface;

class MailExtension extends \Twig_Extension
{
    private $kernel;

    private $host;

    private $imageCache;

    private $messageCache;

    public function __construct(ContainerInterface $container)
    {
        $context = $container->get('router')->getContext();
        $this->host = $context->getScheme() . '://' . $context->getHost();
        $this->kernel = $container->get('kernel');
    }

    public function getFunctions()
    {
        return array(
            new \Twig_SimpleFunction('mail_embed', array($this, 'mailEmbed')),
            new \Twig_SimpleFunction('mail_url', array($this, 'mailUrl')),
        );
    }

    public function mailEmbed(\Swift_Message $message, $file)
    {
        if (!isset($this->messageCache[$message->getId()][$file]))
        {
            if (!isset($this->imageCache[$file]))
            {
                $this->imageCache[$file] = \Swift_Image::fromPath($this->kernel->locateResource($file));
            }
            $this->messageCache[$message->getId()][$file] = $message->embed($this->imageCache[$file]);
        }
        return $this->messageCache[$message->getId()][$file];
    }

    public function mailUrl($file)
    {
        return $this->host . $file;
    }

    public function getName()
    {
        return 'mdurys_mail_extension';
    }
}

Rozszerzenie udostępnia dwie funkcje Twiga: mail_embed() i mail_url(), które odpowiednio umożliwiają osadzenie obrazka w wiadomości i wygenerowanie abosultnego URL-a do zasobu. Osadzane obrazki są cacheowane, więc jeśli dany obrazek jest wykorzystywany kilka razy w danej wiadomości to zostanie osadzony tylko raz, a jeśli obrazek zostanie osadzony w kilku wiadomościach to proces konwersji na obiekt Swift_Image zostanie wykonany tylko raz.

Aby móc z tego rozszerzenia korzystać należy je uaktywnić w services.yml bundla. Ważne jest, żeby otagować usługę jako „twig.extension”.

services:
  mdurys.twig.mail_extension:
    class: MDurys\MailBundle\Twig\MailExtension
    arguments: [ "@service_container" ]
    tags:
      - { name: twig.extension }

Jeśli chcemy osadzić obrazek w wiadomości to podczas renderowania szablonu trzeba przekazać obiekt wiadomości.

$message = \Swift_Message::newInstance();
$htmlPart = $this->renderView(
    'MailBundle:Test:email.html.twig',
    array('message' => $message)
    );
$message
    ->setFrom('mail@example.com')
    ->setTo('test@fexample.com')
    ->setSubject('Mail z obrazkami')
    ->setBody($htmlPart, 'text/html');
$this->get('mailer')->send($message);

W szablonie Twiga wystarczy wywołać funkcję mail_embed() przekazując jej jako parametry obiekt wiadomości i lokalizację pliku.

<img src="{{ mail_embed(message, '@MDurysMailBundle/Resources/public/images/smiley.gif') }}" width="16" height="16" alt=":-)" />

Linkowanie do zewnętrznych zasobów jest prostsze i sprowadza się do wywołania funkcji mail_url() w szablonie:

<img src="{{ mail_url('/bundles/mdurysmail/images/big_logo.jpg') }}" width="600" height="240" alt="Big Logo" />

Jeden komentarz do “Symfony2, Twig i SwiftMailer czyli rzecz o obrazkach w mailu”

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *