---
title: Live Blogging From SymfonyLive London 2019
tags:
    - conference
    - symfony
    - symfonylive
    - php
---
Inspired by [Matt Stauffer](https://twitter.com/stauffermatt)'s [live blogging of the keynote](https://mattstauffer.com/blog/introducing-laravel-vapor) at Laracon US, I’m going to do the same for the sessions that I’m attending at [SymfonyLive London 2019](https://london2019.live.symfony.com)...

## Keynote (Back to the basics)

**Embrace the Linux philosophy**

* How we grow the Symfony ecosystem. Built abstracts.
* HttpFoundation, HttpKernel
* Moved to infrastructure
* A few abstractions on top of PHP. Improved versions of PHP functions (`dump` and `var_dump`)
* Started a add higher level abstractions (e.g. Mailer), built on the lower ones.
* Recently worked on PHPUnit assertions. Mailer in Symony 4.4. Can test if an email is sent or queued

**Building flexible high-level abstractions on top of low-level ones**

### What's next?

* Mailer announced in London last year. New component.
* System emails? e.g. new customer, new invoice.
* Symfony Mailer = Built-in responsive, flexible, and generic system emails
    - Twig with TwigExtraBundle
    - Twig `inky-extra` package (Twig 1.12+)
    - Zurb Foundation for Emails CSS stylesheet
    - Twig `cssinliner-extra` package (Twig 1.12+)
    - Optimised Twig layouts
* `SystemEmail` class extends templated email
* Can set importance, 
* Customisable
* Always trying to keep flexible, so things can be overidden and customised

### Sending SMS messages

* new `Texter` and `SmsMessage` class for sending SMS messages
* Same abstraction as emails, but for SMS messages
* Based on HttpClient + Symfony Messenger and third-party providers (Twilio and Nexmo) `twilio://` and `nemxo://`
* Can set via transport `$sms->setTransport('nexmo')`
* Extend the `SystemEmail` and do what you want
* Failover

### Sending Messages

* Create `ChatMessage`
* Telegram and Slack
* `$message->setTransport('telegram')`, `$bus->dispatch($message)`
* Send to Slack **and** Telegram
* `SlackOptions` and `TelegramOptions` for adding emojis etc
* Common transport layer `TransportInterface`, `MessageInterface`
* Failover - e.g. if Twilio is down, send to Telegram

### New component - SymfonyNotifier

* Channels - email, SMS, chat
* Transport, slack, telegram, twilio
* Create a notification, arguments are message and transports (array)
* Receiver
* Customise notifications, `InvoiceNotification` extends `Notification`. `getChannels`
    * Override default rendering
    * `ChatNotificationInterface` - `asChatMessage()`
* Semantic configuration
    * `composer req twilio-notifier telegram-notifier`
* Channels
    - Mailer
    - Chatter
    - Texter
    - Browser
    - Pusher (iOS, Android, Desktop native notifications)
    - Database (web notification centre)
    - **A unified way to notify Users via a unified Transport layer**
* Each integration is only 40 lines of code

### What about a SystemNotification?

* Autoconfigured channels
* `new SystemNotification`, `Notifier::getSystemReceivers`
* Importance, automatically configures channels
* Different channels based on importance
* `ExceptionNotification` - get email with stack trace attached

Notifier
* send messages via a unified api
* send to one or many receivers
* Default configu or custom one


### How can we leverage this new infrastructure?

* `Monolog NotifierHandler` - triggered on `Error` level logs
* Uses notified channel configuration
* Converts Error level logs to importance levels
* Configurablelike other Notifications
* 40 lines of code
* Failed Messages Listener - 10 lines of glue code

* **Experimental component in 5.0**
* Can't in in 4.4 as it's a LTS version
* First time an experimental component is added
* Stable in 5.1

## Queues, busses and the Messenger component (Tobias Nyholm)

* Stack is top and buttom - Last-in, first-out
* Queue is back and front - last in, first out

### 2013

* Using Symfony, used 40 or 50 bundles in a project - too much information!
* Used to copy and paste, duplicate a lot of code
* Testing your controllers - controllers as services?
* Controllers are 'comfortable'
* Tried adding `CurrentUserProvider` service to core, should be passed as an argument. Cannot test.
* 'Having Symfony all over the place wasn't the best thing' - when to framework (Matthias Noback)
    - Hexagonal architecture
    - Keep your kernel away from infrastructure. Let the framework handle the infrastructure.
* Controller -> Command -> Command Bus -> `CommandHandler`

#### What did we win?

* Can leverage Middleware with a command bus
* Queues as a service (RabbitMQ)
* Work queue - one producer, multiple consumers
* Queues should be durable - messages are also stored on disk, consumers should acknowledge a message once a message is handled
* Publish/subscribe
    - Producer -> Fanout/direct with routing (multiple queues) -> multiple consumers
* Topics - wildcards

### 2016

* New intern. Understand everything, 'just PHP'. Plain PHP application, not 'scary Symfony'

### Symfony Messenger

* `composer req symfony/messager` - best MessageBus implementation
* Message -> Message bus -> Message handler
* Message is a plain PHP class
* Handler is a normal PHP class which is invokable
* `messenger:message_hander` tag in config
* Autowire with `MessageHandlerInterface`
* What if it takes 20 seconds to send a message? Use asynchronous.
* Transports as middleware (needs sender, receiver, configurable with DSN, encode/decode). `MESSENGER_DSN` added to `.env`
* Start consumer with `bin/console messager:consume-messages`. Time limit with `--time-limit 300`
* PHP Enqueue - production ready, battle-tested messaging solution for PHP

### Issues

* Transformers, takes an object and transforms into an array - `FooTransformer implements TransformerInterface`.
* Don't break other apps by changing the payload.

#### Multiple buses

* Command bus, query bus, event bus
* Separate actions from reactions

#### Envelope

* Stamps for metadata - has the item been on the queue already?

#### Failures

* Requeue, different queue or same queue after a period of time
* Failed queue 1 every minute, failed queue 2 every hour - temporary glitches or a bug?

#### Creating entities

* What if two users registered at the same tiem? Use uuids rather than IDs.
* Symfony validation - can be used on messages, not just forms.

* Cache everything
    - Option 1: HTTP request -> Thin app (gets responses from Redis) -> POST to queue. Every GET request would warm cache
    - Option 2: HTTP request -> Thin app -> return 200 response -> pass to workers

* Tip: put Command and CommandHandlers in the same directory

## HttpClient (Nicolas Grekas)

* new symfony component, released in may
* Httpclient contracts, separate package that contains interfaces
    * Symfony
    * PHP-FIG
    * Httplug
* `HttpClient::create()`. `$client->get()`
* JSON decoded with error handling
* Used on symfony.com website (#1391). Replaces Guzzle `Client` for `HttpClientInterface`
* Object is stateless, Guzzle is not. Doesn't handle cookies, cookies are state
* Remove boilerplate - use `toArray()`
* Options as third argument - array of headers, similar to Guzzle

### What can we do with the Response?
* `getStatusCode(): int`
* `getHeaders(): array`
* `getContent(): string`
* `toArray(): array`
* `cancel(): void`
* `getInfo(): array` - metadata
* Everything is lazy!
* 80% of use-cases covered

### What about PSR-18?
* Decorator/adapter to change to PSR compatible
* Same for Httplug

### What about the remaining 20%?
* Options are part of the abstraction, not the implementation

#### Some of the options

* `timeout` - control inactivity periods
* `proxy` - get through a http proxy
* `on_progress` - display a progress bar / build a scoped client
* `base_url` - resolve relative URLS / build a scoped client
* `resolve` - protect webhooks against calls to internal endpoints
* `max_redirects` - disable or limit redirects

* Robust and failsafe by default

* Streamable uploads - `$mimeParts->toIterable()`.
* donwload a file

    ```php
    foreach ($client->stream($response) as $chunk) {
        // ... 
    }
    ```

- Responses are lazy, requests are concurrent
- Asychronus requests. Reading in network order
```
foreach ($client->stream($responses) as $response => $chunk) {
    if ($chunk->isLast()) {
        // a $response completed
    } else {
        // a $response's got network activity or timeout
    }
}
```

* 379 request completed in 0.4s!
* `Stream` has second argument, max number of seconds to wait before yielding a timeout chunk
* `ResponseInterface::getInfo()` - get response headers, redirect count and URL, start time, HTTP method and code, user data and URL
    * `getInfo('debug')` - displays debug information

### The components

* `NativeHttpClient` and `CurlHttpClient`
     - both provide
         + 100% contracts
         + secure directs
         + extended (time) info
         + transparent HTTP compression and (de)chunking
         + automatic HTTP proxy configuration via env vars
#### `NativeHttpClient`
- is most portable, works for everyone
- based on HTTP stream wrapper with fixed redirect logic
- blocking until response headers arrive

#### `CurlHttpClient`
-  Requires ext-curl with fixed redirection logic
-  Multiplexing response headers and bodies
-  Leverages HTTP/2 and PUSH when available
- Keeps connections open also between synchronous requests, no DNS resolution so things are faster

#### Decorators

- ScopingHttpClient - auto-configure options based on request URL
- MockHttpClient - for testing, doesn't make actual HTTP requests
- CachingHttpClient - adds caching on a HTTP request
- Psr18Client
- HttplugClient
- TraceableHttpClient

### Combining
#### FrameworkBundle/Autowiring

```yml
framework:
    http_client:
        max_host_connections: 4
        deault_options:
            # ....
    scoped_client:
        # ...
```
#### HttpBrowser

* HttpClient + DomCrawler + CssSelector + HttpKernel + BrowserKit
* RIP Goutte!

### Coming in 4.4...

- `max_duration`
- `buffer` based on a callable
- `$chunk->isInformational()`
- `$response->toStream()`
- Async-compatible extensibility, when decoration is not enough

`composer req symfony/http-client`

## Symfony Checker is coming (Valentine Boineau)

* Static analysis tool for Symfony
    - Does a method exist?
    - Is it deprecated?
* insight.symfony.com
* @symfonyinsight
* Released soon

### Differences
* Specialise in Symfony - can see more relevant things
* Different interface to other services

## Feeling unfulfilled by SPA promises? Go back to Twig (Dan Blows)

A way on the front-end JS, CSS, images at the beginning of the request, sends a HTTP request (XHR/AJAX) to the back-end

### Why SPAs?
- A way on the front-end JS, CSS, images at the beginning of the request, sends a HTTP request (XHR/AJAX) to the back-end
- no full page refresh
- Supposed to be much quicker
- 'Right tool for the job' - JS on the front-end, PHP on the back-end
- Division of responsibility == faster development
- Reusable API - Api -> Mobile App and SPA - easy to add another consumer
- Easier to debug?

### Why not SPAs?
- Lots of HTTP requests (400 to load the initial page on one project) == slow front end
- Blurred responsibilities == tightly coupled teams
- harder to debug, bugs fall between systems and teams. Huge gap between front-end and back-end, passing responsibilites.
- You can fix these problems in SPAs, but is it worth it?
    + Examples of good SPAs - Trello, Flickr

### Using Twig as an alternative to an SPA?

#### Faster UI - Try and figure out where the problem is.

If you're trying to speed things up, find out where the problem is.

* Browser tools
* Web Debug Toolbar
* Blackfire
* Optimise and monitor

#### Speed up Twig

- Speeding up Symfony
- ext/twig (PHP5 only, not PHP 7)
- Store compiled templates in Opcache, make sure it's enabled
- Render assets though the webserver (assetic not running all the time)

#### Edge side includes

- Component cached differently to the rest of the page
- Varnish/Nginx
- `render_esi`
- News block that caches frequently, rest of the page

#### HTTP/2 with Weblink

- slow finding CSS files to load - 'push' over CSS files, doesn't need to wait
- `preload()` - https://symfony.com/doc/current/web_link.html

#### Live updating pages
- Instantly update when sports results are updated, news articles are added
- Mercure - https://github.com/symfony/mercure
- LiveTwig - whole block or whole section, and live update `render_live`
- Turbolinks - replace whole body, keeps CSS and JS in memory. Merges new stuff in. `helthe/turbolinks`
- ReactPHP - shares kernel between requests

### Writing better code with Twig

- Keep templates simple. Avoid spaghetti code, only about UI. HTML or small amounts of Twig.
- Avoid delimeter chains
    - Bad:`blog_post.authors.first.user_account.email_address`
    - Good `{{ blog_post.authors_email_address }}`
    - Less brittle, slow
* Filters
    - Use filters to be precise
    - Custom filters
    - Avoid chains. Can cause odd results. Create a new filter in PHP
* Functions
    - Write your own functions
    - Simpler templates
    - Get data, can use boolean statements
* Components
    - Break a page into components rather than one large page
    - `include()`
    - Use `only` to only pass that data. less tightenly coupled.
    * `render` calls the whole of Symfony, boots Kernel, can be expensive and slow
    * Loosely couple templates and controllers
        - Keep responses simple
        - What makes sense
        - if you need extra data in the template, get it in the template
    * View models
        - Mixed results
        - `BlogPostViewModel`
        - Can result in boilerplate code
        - Can be useful if the view model is different to the Entity
    * DRY
        - "Don't repeat yourself"

+ Faster development
    * Separate UI tests from back-end tests. Different layers for different teams. People don't need to run everything if they are only changing certain things.
- Help your front end
    + Webpack - Encore
    + Type hinting in functions and filters, easier to debug
    + Logging
    + Friendly exceptions - help front-end devs by returning meaningful, readbale errors
    + Web Debug Toolbar and Profiler, provide training for toolbar and profilers
    + Twig-friendly development environment - Twig support in IDEs and text editors

SPAs are sometimes teh right solution. Why do they want to use it, can the same benefits be added with Twig?

3 most important points:

- Profile, identidy, optimise, monitor
- Loosely couple templates to your app code
- Help your front ends - put your front end developers first
- You don't need to use a SPA for single pages, use JavaScript for that one page. It doesn't need to be all or nothing.

## BDD Your Symfony Application (Kamil Kokot)

* Applying BDD to Sylius
* 2 years since release of Sylius (Symfony 2 alpha)
* The business part is more important than the code part

### What is BDD?
* Behaviour driven development. Combines TDD and DDD, into an agile methodology
* Encourages communication and creates shared understanding
* Living, executable documentation that non-programmers understand. Always correct.
* Feature file
    - Feature
    - Scenario - example of the behaviour for this feature. Simple, atomic.
    - In order to...
    - Who gets the benefit?

## Migrating to Symfony one route at a time (Steve Winter)

## Closing Keynote: The fabulous World of Emojis and other Unicode symbols (Nicolas Grekas)