714 lines
23 KiB
Markdown
714 lines
23 KiB
Markdown
|
---
|
|||
|
title: Live Blogging From SymfonyLive London 2019
|
|||
|
date: 2019-09-13
|
|||
|
tags:
|
|||
|
- conference
|
|||
|
- php
|
|||
|
- symfony
|
|||
|
- symfonylive
|
|||
|
---
|
|||
|
|
|||
|
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
|
|||
|
|
|||
|
```yaml
|
|||
|
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. (e.g.
|
|||
|
I need a product in order to add it to a cart)
|
|||
|
- In order to...
|
|||
|
- Who gets the benefit?
|
|||
|
|
|||
|
### BDD in practice
|
|||
|
|
|||
|
- Feature: booking flight tickets
|
|||
|
- Scenario: booking flight ticket for one person
|
|||
|
- Given there are the following flights...
|
|||
|
- When I visit '/flight/LTN-WAW'
|
|||
|
- Then I should be on '/flight/LTN-WAW'
|
|||
|
- Add I should see "Your flight has been booked." in "#result"
|
|||
|
- In the BDD way - what is the business logic? What is the value for this
|
|||
|
scenario? What is the reason 'why', and who benefits from this?
|
|||
|
- We just need to know that there are 5 seats left on a flight
|
|||
|
- Talk and communicate about how the feature is going to work - not just
|
|||
|
developers
|
|||
|
- BDD aids communication
|
|||
|
- Questions we can ask
|
|||
|
- Can we get a different outcome when the context changes?
|
|||
|
- When there was only one seat available
|
|||
|
- When there were no available seats
|
|||
|
- Can we get the same outcome when the event changes? Can we change 'When' and
|
|||
|
'Then stays the same'
|
|||
|
- When it is booked for an adult and a child
|
|||
|
- When it is booked for an adult
|
|||
|
- Does anything else happen that is not mentioned?
|
|||
|
- Generate an invoice if a seat is booked
|
|||
|
- a pilot would like to get a notification that a seat was booked.
|
|||
|
* Figuring out the rules
|
|||
|
- Adults are 15+ years old
|
|||
|
- Children are 2-14 years old
|
|||
|
- Infants and children can only travel with an adult
|
|||
|
- We don't allow for overbooking
|
|||
|
- Translating rules into examples
|
|||
|
- Add a new scenario for each rule - e.g. don't allow over booking
|
|||
|
- "And the flight should be no longer available..."
|
|||
|
|
|||
|
### Behat
|
|||
|
|
|||
|
- Used to automate and execute BDD tests, also SpecDDD
|
|||
|
- maps steps to PHP code
|
|||
|
- Given a context, when an event, then an outcome
|
|||
|
- Domain Context, API context
|
|||
|
- class implements `Context`, annotations for `@Given`, `@When`, `@Then`. allows
|
|||
|
for arguments and regular expressions
|
|||
|
- Suites: change what code is executed, and what scenarios are executed. context
|
|||
|
and tags
|
|||
|
- FriendsOfBehat SymfonyExtension - integrates Behat with Symfony
|
|||
|
- Contexts registered as Symfony services - inject dependencies, service as a
|
|||
|
context in Behat. Need to be 'public' for it to work
|
|||
|
- Reduces boilerplate code. Supports autowiring.
|
|||
|
- Zero configuration
|
|||
|
|
|||
|
### Domain context
|
|||
|
|
|||
|
- `Given` verb matches `@Given` annotation. Same for `When` and `Then`.
|
|||
|
- Transformers, type hint name string, return Client instance
|
|||
|
|
|||
|
### API context
|
|||
|
|
|||
|
- inject `FlightBookingService` and `KernelBrowser`
|
|||
|
- Use `$this->kernelBrowser->request()`
|
|||
|
- Use `assert()` function wuthin `@Then`
|
|||
|
|
|||
|
### Back to reality - how it's done with Sylius
|
|||
|
|
|||
|
- Business part applies to all context. Start talking about what needs to be
|
|||
|
done, start communicating
|
|||
|
- Implement contexts for UI and API
|
|||
|
- 12716 steps, 1175 scenarios, 8 min 8 sec, 2.4 scenarios /sec
|
|||
|
- 12x faster than JS (17 min 48 sec, 0.19 scenario / sec)
|
|||
|
- Treat test CI environment like production
|
|||
|
|
|||
|
- Turn off debug settings, add caching
|
|||
|
- Enable OPcache
|
|||
|
|
|||
|
- Write features in a natural way
|
|||
|
- Too many setup steps - merge steps. less visual debt. e.g. Create currency,
|
|||
|
zone and locale when creating a store
|
|||
|
- Avoid scenarios that are too detailed. You should specify only what's
|
|||
|
important to this scenario.
|
|||
|
|
|||
|
## Migrating to Symfony one route at a time (Steve Winter)
|
|||
|
|
|||
|
- New client with an old application, built in an old version of another
|
|||
|
framework with unusual dependency management, no tests, no version control and
|
|||
|
deploying via FTP. Done over a ~3 month period.
|
|||
|
|
|||
|
- Subscription based index of suppliers
|
|||
|
- New requirements to implement by the client
|
|||
|
- Our requirements: Needed a deployment process, make it testable, fix the build
|
|||
|
chain
|
|||
|
- Solution attempt 1: Migrate to a new version of the current framework
|
|||
|
- Minor template and design changes were fine
|
|||
|
- Modifiy features, add new dependencies.
|
|||
|
- Solution attempt 2: Upgrade to the latest version - same outcome due to
|
|||
|
multiple BC breaks (no semver), lots of manual steps
|
|||
|
- Solution attempt 3: Symfony!
|
|||
|
- Semver! Backwards compatibility promise
|
|||
|
- Symfony app to run in parallel, Apache proxy rules and minor changes to the
|
|||
|
legacy app, added data transfer mechanisms
|
|||
|
- Anything new done in Symfony
|
|||
|
- Installed on the same server with it's own vhost but not publicly accessible
|
|||
|
- Deployed independently of legacy app
|
|||
|
|
|||
|
### Apache proxy rules
|
|||
|
|
|||
|
Proxy `/public` to symfony app
|
|||
|
|
|||
|
### Legacy app
|
|||
|
|
|||
|
- Shared cookie for single login between apps - user account details (name etc),
|
|||
|
session details (login time)
|
|||
|
|
|||
|
### Added functionality
|
|||
|
|
|||
|
- Built in Symfony
|
|||
|
- new proxy rules for new routes
|
|||
|
- Add menu links to legacy app menu
|
|||
|
- How do we show how many reminders are active?
|
|||
|
- Symfony based API called from the front-end
|
|||
|
|
|||
|
### Migrating routes
|
|||
|
|
|||
|
- Rebuilt or extend in Symfony app
|
|||
|
- Test and deploy, then update the apache config to add new proxy rules
|
|||
|
|
|||
|
### A gotcha
|
|||
|
|
|||
|
- Legacy app uses CSRF
|
|||
|
- Needed to track the token, added to shared cookie and pass through to the
|
|||
|
Symfony side
|
|||
|
|
|||
|
### Storing data
|
|||
|
|
|||
|
- Both apps using the same data with different credentials
|
|||
|
- Some shared tables, some tables are specific to each app
|
|||
|
|
|||
|
### Remaining challenges
|
|||
|
|
|||
|
- User session management, still handled by legacy app
|
|||
|
- Templating/CSS - two versions of everything
|
|||
|
- Next step: move all CSS to Symfony
|
|||
|
|
|||
|
### Summary
|
|||
|
|
|||
|
- Add Symfony app, Apache proxy rules for routes
|
|||
|
- User transfer mechanisms
|
|||
|
- New functionality added in Symfony
|
|||
|
|
|||
|
### Is this right for you?
|
|||
|
|
|||
|
It depends. Fine for a 'modest' size. Use a real proxy for larger scale apps,
|
|||
|
use different servers with database replication.
|
|||
|
|
|||
|
## Closing Keynote: The fabulous World of Emojis and other Unicode symbols (Nicolas Grekas)
|
|||
|
|
|||
|
- ASCII. Still used today. Map between the first 128 numbers to characters. OK
|
|||
|
for UK and US.
|
|||
|
- 256 numbers in Windows-1252 (character sets). Each country had their own set.
|
|||
|
- It's legacy. 0.2% for Windows-1252. 88.8% for UTF-8 (Feb 2017)
|
|||
|
- Unicode: 130k characters, 135 scripts (alphabets)
|
|||
|
- Validation errors using native alphabet - e.g. invalid last name when
|
|||
|
submitting a form
|
|||
|
- 17 plans, each square is 255 code points
|
|||
|
- Emojis are characters, not images
|
|||
|
- Gliph is a visual representation of a character
|
|||
|
- From code points to bytes
|
|||
|
- UTF-8: 1,2,3 or 4 bytes
|
|||
|
- UTF16: 2 or 4 bytes
|
|||
|
- UTF-32: 4 bytes
|
|||
|
- UTF-8 is compatible with ASCII
|
|||
|
- Case sensitivity - 1k characters are concerned. One uppercase letter, two
|
|||
|
lower case variants. Turkish exception (similar looking letters that are
|
|||
|
different letters with different meanings). Full case folding.
|
|||
|
- Collations - ordering is depends on the language. 'ch' in Spanish is a single
|
|||
|
character.
|
|||
|
- Single number in unicode to represent accents. Combining characters.
|
|||
|
- Composed (NFC) and decomposed (NFD) forms - normalisation for comparison
|
|||
|
- Grapheme clusters - multiple characters, but one letter as you write it
|
|||
|
(separate characters for letters and accent)
|
|||
|
- Emjois - combining characters. e.g. Combine face with colour. Different codes
|
|||
|
and character names. Also applies to ligatures. A way to combine several
|
|||
|
images together into one single visual representation.
|
|||
|
|
|||
|
### unicode fundamentals
|
|||
|
|
|||
|
- uppercase, lowercase, folding
|
|||
|
- compositions, ligatures
|
|||
|
- comparistions - normalisations and collations
|
|||
|
- segmentation: characters, words, sentences and hyphens
|
|||
|
- locales: cultural conventions, translitterations
|
|||
|
- identifiers & security, confusables
|
|||
|
- display: direction, width
|
|||
|
|
|||
|
### unicode in practice
|
|||
|
|
|||
|
- MySQL - `utf*_*`. `SET NAMES utf8mb4` for security and storing emojis. Cannot
|
|||
|
store emojis with `utf8`
|
|||
|
|
|||
|
### in php
|
|||
|
|
|||
|
- `mb_*()`
|
|||
|
- `iconv_*()`
|
|||
|
- `preg_*()`
|
|||
|
- `grapheme_*()` `normalizer_*()`
|
|||
|
- `symfony/polyfill-*` - pure PHP implementation
|
|||
|
- Made a component - **symfony/string** -
|
|||
|
https://github.com/symfony/symfony/pull/33553
|
|||
|
- Object orientated api for strings. Immutable value objects
|
|||
|
- `AbstractString`
|
|||
|
- `GraphemeString`
|
|||
|
- `Utf8String`
|
|||
|
- `BinaryString`
|
|||
|
|
|||
|
* AbstractString - Methods to serialize, get length, to binary or grapheme or
|
|||
|
utf8
|
|||
|
- Methods for starts with, ends with, is empty, join, prepend, split, trim,
|
|||
|
title etc
|