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
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
Was this useful?
About me
I'm an Acquia-certified Drupal Triple Expert with 17 years of experience, an open-source software maintainer and Drupal core contributor, public speaker, live streamer, and host of the Beyond Blocks podcast.