Slide 1

Slide 1 text

Back to the basics... Fabien Potencier @fabpot

Slide 2

Slide 2 text

Process > proc_open() VarDumper > var_dump() VarExporter > var_export() Finder > *Iterator HttpFoundation > $_GET/$_POST HttpKernel > echo What's next?

Slide 3

Slide 3 text

file_get_contents() no dependencies

Slide 4

Slide 4 text

3) Symfony HTTPClient Do HTTP requests, the powerful way Fabien Potencier @fabpot

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

No content

Slide 11

Slide 11 text

No content

Slide 12

Slide 12 text

No content

Slide 13

Slide 13 text

No content

Slide 14

Slide 14 text

No content

Slide 15

Slide 15 text

No content

Slide 16

Slide 16 text

Great DX - Great Perf - Great Design (auto) proxy configuration DNS cache pre-population 1st class error handling auto-gzip compression timeout management public key pinning progress callback extended info request abort HTTP/2-push IDN support Psr18Client time stats streaming base URI ...

Slide 17

Slide 17 text

379 requests in HTTP/2 0,3 s!

Slide 18

Slide 18 text

No content

Slide 19

Slide 19 text

No content

Slide 20

Slide 20 text

What’s next? Your contrib! TraceableHttpClient, profiler panel, logger integration, mock client, record/replay, raw sockets, cookie jar, ...

Slide 21

Slide 21 text

R.I.P. Goutte Integrates with battle-tested components HttpClient + BrowserKit + DomCrawler + CssSelector + HttpCache

Slide 22

Slide 22 text

No content

Slide 23

Slide 23 text

No content

Slide 24

Slide 24 text

Back to the basics... part 4/n Fabien Potencier @fabpot

Slide 25

Slide 25 text

4) Symfony MIME Everything you need to create beautiful emails Fabien Potencier @fabpot

Slide 26

Slide 26 text

Symfony Mime

Slide 27

Slide 27 text

use Symfony\Component\Mime\Email; $email = (new Email()) ->from('[email protected]') ->to('[email protected]') ->subject('Some subject') ->text('Some text message') ->html('Some HTML message') ->attach('doc.txt') ; The basics

Slide 28

Slide 28 text

$email = (new Email()) ->from('[email protected]') ->to(new Address('[email protected]')) ->addTo(new NamedAddress('[email protected]', 'Fabien')) ->addCc('[email protected]', '[email protected]') ->addCc(...['[email protected]', '[email protected]']) ->subject('Some subject') ->text('Some text') ; from, to, cc, bcc

Slide 29

Slide 29 text

$email = (new Email()) ->from('[email protected]') ->to('[email protected]') ->subject('Some subject') ->text('Some text message') ->html('Some HTML message') ; echo strlen(serialize($email)); Email is a data object Only 2k vs 16k for Swiftmailer

Slide 30

Slide 30 text

Why is it so different
 from Swiftmailer?

Slide 31

Slide 31 text

$email = (new Email()) ->text('Some text message') ->html('Some HTML message') ; $email = (new \Swift_Message()) ->setBody('Some text message') ->addPart('Some HTML message', 'text/html') ; A better data object model 16k serialized 38 objects complex serialization "fixed" headers 2k serialized 7 objects simple serialization "dynamic" headers

Slide 32

Slide 32 text

echo $email->toString(); sleep(2); $email->to('[email protected]'); echo $email->toString(); Fixed vs dynamic headers Different
 set of headers Date, Boundary, Message-ID

Slide 33

Slide 33 text

$email = (new Email()) ->from('[email protected]') ->to('[email protected]') ->subject('Some subject') ->text(fopen('email.txt', 'r')) ->html(fopen('email.html', 'r')) ; echo $email->toString(); foreach ($email->toIterable() as $chunk) { echo $chunk; } String or resources, your choice

Slide 34

Slide 34 text

// Email extends Message use Symfony\Component\Mime\Message; use Symfony\Component\Mime\Part\TextPart; use Symfony\Component\Mime\Header\Headers; $body = new TextPart('Some content'); $headers = (new Headers()) ->addMailboxListHeader('From', ['[email protected]']) ->addMailboxListHeader('To', ['[email protected]']) ->AddTextHeader('Subject', 'Some subject') ; $email = new Message($headers, $body); And you get full control!

Slide 35

Slide 35 text

$txt = new TextPart('Some content'); $html = new TextPart('Some content', 'html'); $body = new AlternativePart($txt, $html); $email = new Message($headers, $body); Get creative

Slide 36

Slide 36 text

A "complete" email multipart/mixed | |------------> multipart/related | | | |------------> multipart/alternative | | | | | ------------> text/plain | | | | | ------------> text/html | | | ------------> image/png | ------------> application/pdf ->text() ->html() ->embed() ->attach()

Slide 37

Slide 37 text

$email = (new Email()) ->from('[email protected]') ->to('[email protected]') ->subject('Some subject') ->setBody($body) ; Mix several approaches

Slide 38

Slide 38 text

$email ->attach('Some content', 'doc.txt', 'text/plain') ->attachFromPath('/path/to/doc.txt') ->attach(fopen('doc.txt', 'r'), 'doc.txt', 'text/plain') ; Attachments

Slide 39

Slide 39 text

$email = (new Email()) ->from('[email protected]') ->to('[email protected]') ->subject('Some subject') ->text('Some text') ->html('The new logo: ') ->embedFromPath('logo-small.jpg', 'logo.jpg') ; Embeds

Slide 40

Slide 40 text

// Email extends Message extends RawMessage use Symfony\Component\Mime\RawMessage; $message = new RawMessage($email->toString()); $message->toString(); Go raw! Serialize an email as a string instead of a PHP object

Slide 41

Slide 41 text

Creating Emails with Twig Twig is perfect for emails aka, Twig is not dead and still very useful :)

Slide 42

Slide 42 text

use Symfony\Bridge\Twig\Mime\Renderer; use Symfony\Bridge\Twig\Mime\TemplatedEmail; use Twig\Environment; use Twig\Loader\FilesystemLoader; use Symfony\Component\Mime\NamedAddress; $twig = new Environment($loader = new FilesystemLoader(__DIR__.'/templates')); $loader->addPath(__DIR__.'/images', 'images'); $email = (new TemplatedEmail()) ->from('[email protected]') ->to(new NamedAddress('[email protected]', 'Fabien')) ->text('Some text content') ->htmlTemplate('simple.html.twig') ->context([ 'city' => 'Lille' ]) ; $renderer = new Renderer($twig); echo $renderer->render($email)->toString(); Native integration with Twig

Slide 43

Slide 43 text

Welcome {{ email.toName }} from {{ city }}!

Native integration with Twig Symfony\Bridge\Twig\Mime\ WrappedTemplatedEmail Twig template name Template context

Slide 44

Slide 44 text

{% do email.attach('@docs/doc.pdf') %}

Welcome {{ email.toName }}!

Native integration with Twig

Slide 45

Slide 45 text

{% do email.priority(5) %}

Welcome {{ email.toName }}!

Native integration with Twig

Slide 46

Slide 46 text

$email = (new TemplatedEmail()) ->from('[email protected]') ->to(new NamedAddress('[email protected]', 'Fabien')) ->textTemplate('simple.txt.twig') ->htmlTemplate('simple.html.twig') ; Native integration with Twig

Slide 47

Slide 47 text

$email = (new TemplatedEmail()) ->from('[email protected]') ->to(new NamedAddress('[email protected]', 'Fabien')) ->template('simple.email.twig') ; Native integration with Twig

Slide 48

Slide 48 text

{% block config %} {% do email.attach('@images/planfaidherbe.jpeg') %} {% endblock %} {% block subject %}Email Subject{% endblock %} {% block text %} Optional text representation {% endblock %} {% block html %}

Welcome {{ email.toName }}!

{% endblock %} Native integration with Twig

Slide 49

Slide 49 text

{% block text %} {% set formula = "2 > 1?" %} {% autoescape false %} {{ formula }} {% endautoescape %} {% endblock %} {% block html %} {% set formula = "2 > 1?" %} {{ formula }} {% endblock %} Native integration with Twig HTML escape by default with the "name" strategy From: [email protected] To: Fabien MIME-Version: 1.0 Date: Thu, 28 Feb 2019 12:10:16 +0100 Message-ID: <[email protected]> Content-Type: multipart/alternative; boundary="_=_symfony_1551352216_9df84f01f42af586d65b48578466206f_= --_=_symfony_1551352216_9df84f01f42af586d65b48578466206f_=_ Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable =20 2 > 1? =20 --_=_symfony_1551352216_9df84f01f42af586d65b48578466206f_=_ Content-Type: text/html; charset=utf-8 Content-Transfer-Encoding: quoted-printable =20 2 > 1? --_=_symfony_1551352216_9df84f01f42af586d65b48578466206f_=_--

Slide 50

Slide 50 text

Tip! If the Text part is empty, the Renderer automatically generates one

Slide 51

Slide 51 text

But HTML in emails is hard Compatibility with email clients Inline CSS Responsive layout …

Slide 52

Slide 52 text

use Twig\CssInliner\CssInlinerExtension; $twig->addExtension(new CssInlinerExtension()); {% filter inline_css %} b { color: red }

Welcome {{ email.toName }}!

{% endfilter %} Inlining CSS

Slide 53

Slide 53 text

{% filter inline_css("@css/email.css") %} b { color: red }

Welcome {{ email.toName }}!

{% endfilter %} Inlining CSS

Slide 54

Slide 54 text

use Twig\Markdown\MarkdownExtension; $twig->addExtension(new MarkdownExtension());

{% filter markdown %} | Version | LTS? | Latest | | ------------- |:-------------:| -------:| | 1.0 | Yes | 1.0.1 | | 2.1 | No | 2.1.33 | {% endfilter %}

Use Markdown to simplify your templates

Slide 55

Slide 55 text

use Twig\Inky\InkyExtension; $twig->addExtension(new InkyExtension()); Use Inky to simplify your HTML https://foundation.zurb.com/emails.html

Slide 56

Slide 56 text

{% filter inky|inline_css(source("@zurb/stylesheets/main.css")) %}

Symfony Connect

Forgot Your Password?

It happens. Click the link below to reset it.

Reset Password

unsubscribe here.

{% endfilter %} Use Inky to simplify your HTML

Slide 57

Slide 57 text

What about sending
 our emails now?

Slide 58

Slide 58 text

Thank you! ❤