Slide 1

Slide 1 text

Symfony 5.2 Fabien Potencier @fabpot Icons made by Eucalyp from www.flaticon.com

Slide 2

Slide 2 text

Console 240M downloads ❤

Slide 3

Slide 3 text

Console Colors True color support via Hex CSS colors https://github.com/symfony/symfony/pull/36802 $color = new Color('black', 'white'); echo $color->apply("foo"); $color = new Color('#000000', '#ffffff');

Slide 4

Slide 4 text

private function rainbowColor(): Color { ++$this->color; if (256 === $this->color) { $this->color = 1; } $h = (int) ($this->color / 43); $f = (int) ($this->color - 43 * $h); $t = (int) ($f * 255 / 43); $q = 255 - $t; if ($h == 0) { return new Color('', sprintf('#FF%02x00', $t)); } elseif ($h == 1) { return new Color('', sprintf('#%02xFF00', $q)); } elseif ($h == 2) { return new Color('', sprintf('#00FF%02x', $t)); } elseif ($h == 3) { return new Color('', sprintf('#00%02xFF', $q)); } elseif ($h == 4) { return new Color('', sprintf('#%02x00FF', $t)); } elseif ($h == 5) { return new Color('', sprintf('#FF00%02x', $q)); } } Console Rainbows https://github.com/symfony/symfony/pull/36802 $output->write($this->rainbowColor()->apply(' '));

Slide 5

Slide 5 text

https://symfony.com/blog/new-in-symfony-5-1-cursor-control namespace App\Command; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Cursor; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; class SomeCommand extends Command { protected static $defaultName = 'app:some-command'; protected function execute(InputInterface $input, OutputInterface $output) { // ... $cursor = new Cursor($output); // argument for left/right is "number of columns" (1 by default) // argument for top/bottom is "number of rows" (1 by default) $cursor->moveUp(2)->moveRight(); $cursor->moveDown(); // move to an arbitrary (column, row) position $cursor->moveToPosition(7, 15); // you can show/hide the cursor, save/restore its position, etc. $cursor->savePosition()->hide(); } }

Slide 6

Slide 6 text

Snake a Symfony Console Game https://github.com/dbu/snake-bundle

Slide 7

Slide 7 text

Default Command vs Single Command Applications #!/usr/bin/env php setCode( function (InputInterface $input, OutputInterface $output) { // add here the code of your console command... } ) ->run(); #!/usr/bin/env php add(new SnakeCommand()); $app->setDefaultCommand('game:snake'); $app->run(); 5.1

Slide 8

Slide 8 text

https://github.com/fabpot/snake-bundle/tree/rainbow-time

Slide 9

Slide 9 text

Console Signals $game = new Game(80, 24); $app = new Application(); $app->add(new SnakeCommand($game)); $app->setDefaultCommand('game:snake'); $app->getSignalRegistry()->register(SIGUSR1, function ($signal) use ($game) { $game->cheat(); }); $app->run(); https://github.com/symfony/symfony/pull/33729 https://github.com/symfony/symfony/pull/37827 pkill -USR1 -f "php ./snake" https://github.com/fabpot/snake-bundle/tree/rainbow-time

Slide 10

Slide 10 text

Translation Created 10 years ago ❤

Slide 11

Slide 11 text

$invitation = '{organizer_gender, select, female {{organizer_name} has invited you for her party!} male {{organizer_name} has invited you for his party!} other {{organizer_name} have invited you for their party!} }'; // prints "Ryan has invited you for his party!" echo $translator->trans($invitation, [ 'organizer_name' => 'Ryan', 'organizer_gender' => 'male', ]); Translation: Standard ICU message format https://github.com/symfony/symfony/pull/37371

Slide 12

Slide 12 text

Translation: Pseudo localization translator https://github.com/symfony/symfony/pull/36016

Slide 13

Slide 13 text

$message = new Translatable('Symfony is great!'); $message = t('Symfony is great!'); Translatable::trans($translator, $message); Translation: Translatable objects https://github.com/symfony/symfony/pull/37670

Slide 14

Slide 14 text

Form Mapping data using callback functions https://github.com/symfony/symfony/pull/37968 $builder->add('name', TextType::class, [ 'getter' => fn(Person $person, FormInterface $form): string => $person->firstName().' '.$person->lastName(); 'setter' => fn(Person &$person, ?string $name, FormInterface $form): void => $person->rename($name); ]);

Slide 15

Slide 15 text

HttpClient

Slide 16

Slide 16 text

HttpClient RetryableHttpClient use Symfony\Component\HttpClient\RetryableHttpClient; $client = new RetryableHttpClient(HttpClient::create()); framework: http_client: retry_failed: # backoff_service: app.custom_backoff # decider_service: app.custom_decider http_codes: [429, 500] max_retries: 2 delay: 1000 multiplier: 3 max_delay: 500 https://github.com/symfony/symfony/pull/38182

Slide 17

Slide 17 text

HttpClient EventSourceHttpClient https://github.com/symfony/symfony/pull/36692

Slide 18

Slide 18 text

Experimental Components get better!

Slide 19

Slide 19 text

Uid: Better framework integration https://symfony.com/components/Uid Support in Serializer (via a dedicated Normalizer) - Just works Uid Doctrine types and generators Help needed - https://github.com/symfony/symfony/issues/36102 Uid constraint and more 5.1

Slide 20

Slide 20 text

Notifier: Still experimental We need your feedback!

Slide 21

Slide 21 text

Notifier: Many new providers 5.2 all 5.1 + Esendex GoogleChat Infobip LinkedIn Mobyt Smsapi Zulip 5.1 all 5.0 + Firebase FreeMobile Mattermost OvhCloud RocketChat Sinch 5.0 Nexmo Slack Telegram Twilio

Slide 22

Slide 22 text

Providers are now more widespread Notifier Esendex * Firebase FreeMobile GoogleChat * Infobip * LinkedIn * Mattermost Mobyt * Nexmo OvhCloud RocketChat Sinch Slack Smsapi * Telegram Twilio Zulip * Messenger AmazonSqs Amqp Beanstalkd * Doctrine Redis Mailer Amazon Google Mailchimp Mailgun Mailjet * Postmark Sendgrid to be continued...

Slide 23

Slide 23 text

Mailer: Incremental improvements More semantic configuration framework: mailer: dsn: '%env(MAILER_DSN)%' headers: from: 'company@example.com' bcc: 'me@example.com' https://github.com/symfony/symfony/pull/36736

Slide 24

Slide 24 text

{ "htmlTemplate": "email.html.twig", "textTemplate": "email.txt.twig", "context": { "foo": "bar" }, "text": null, "textCharset": null, "html": null, "htmlCharset": null, "attachments": [ { "body": "Some Text file", "name": "test.txt", "content-type": null, "inline": false } ], "headers": { "to": [ { "addresses": [ { "address": "you@example.com", "name": "" } ] } ] }, "body": null, "message": null } Mailer: Incremental improvements Better serialization, lightweight payload and no binaries https://github.com/symfony/symfony/pull/37847

Slide 25

Slide 25 text

$dkimSigner = new DkimSigner($pk, 'example.com', 'sf'); $signedEmail = $dkimSigner->sign($email); Mailer: Incremental improvements DKIM support Switch from Swiftmailer https://github.com/symfony/symfony/pull/37165

Slide 26

Slide 26 text

Less code More automation

Slide 27

Slide 27 text

Skeleton code simplification public/index.php use App\Kernel; use Symfony\Component\Dotenv\Dotenv; use Symfony\Component\ErrorHandler\Debug; use Symfony\Component\HttpFoundation\Request; require dirname(__DIR__).'/vendor/autoload.php'; (new Dotenv())->bootEnv(dirname(__DIR__).'/.env'); if ($_SERVER['APP_DEBUG']) { umask(0000); Debug::enable(); } if ($trustedProxies = $_SERVER['TRUSTED_PROXIES'] ?? false) { Request::setTrustedProxies(explode(',', $trustedProxies), Request::HEADER_X_FORWARDED_ALL ^ Request::HEADER_X_FORWARDED_HOST); } if ($trustedHosts = $_SERVER['TRUSTED_HOSTS'] ?? false) { Request::setTrustedHosts([$trustedHosts]); } $kernel = new Kernel($_SERVER['APP_ENV'], (bool) $_SERVER['APP_DEBUG']); $request = Request::createFromGlobals(); $response = $kernel->handle($request); $response->send(); $kernel->terminate($request, $response); framework: trusted_proxies: '127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16' # or trusted_proxies: '%env(TRUSTED_PROXIES)%' # that's the defaults already trusted_headers: ['x-forwarded-all', '!x-forwarded-host', '!x-forwarded-prefix'] https://github.com/symfony/symfony/pull/37357

Slide 28

Slide 28 text

Skeleton code simplification HTTP Cache in public/index.php framework: http_cache: true No more PHP to enable PHP HTTP caching ❤ https://github.com/symfony/symfony/pull/37351

Slide 29

Slide 29 text

Upgrade your project composer sync-recipes --force

Slide 30

Slide 30 text

New Components

Slide 31

Slide 31 text

Semaphore Component A semaphore allows N processes to access a resource A lock allows only 1 process to access a resource https://github.com/symfony/symfony/pull/35780

Slide 32

Slide 32 text

Lock Component Single Write / Multiple Readers $aliceLock = $factory->createLock('invoice'); $bobLock = $factory->createLock('invoice'); $oscarLock = $factory->createLock('invoice'); $aliceLock->acquireRead(); // true $bobLock->acquireRead(); // true $oscarLock->acquire(); // false https://github.com/symfony/symfony/pull/37752

Slide 33

Slide 33 text

RateLimiter Component use Symfony\Component\RateLimiter\Storage\InMemoryStorage; use Symfony\Component\RateLimiter\Limiter; $limiter = new Limiter([ 'id' => 'login', 'strategy' => 'token_bucket', // or 'fixed_window' 'limit' => 10, 'rate' => ['interval' => '15 minutes'], ], new InMemoryStorage()); // blocks until 1 token is free to use for this process $limiter->reserve(1)->wait(); // ... execute the code // only claims 1 token if it's free at this moment if ($limiter->consume(1)) { // ... execute the code } RateLimiter Lock ??? Cache https://github.com/symfony/symfony/pull/37546

Slide 34

Slide 34 text

Security reinvented

Slide 35

Slide 35 text

Security Authenticators 4 main ideas VerifyAuthenticatorCredentialsEvent LoginSuccessEvent LoginFailureEvent PUBLIC_ACCESS vs ROLE_ANONYMOUS

Slide 36

Slide 36 text

Security Login Throttling RateLimiter Lock Login Throttling Cache Security Authenticators 5.1 3.3 3.1 5.2 5.2 security: firewalls: default: # default limits to 5 login attempts per minute, # the number can be configured via "max_attempts" login_throttling: ~ # define your own RateLimiter login_throttling: limiter: login https://github.com/symfony/symfony/pull/38204

Slide 37

Slide 37 text

Security Authenticators unlock a lot of features Magic login link authentication https://github.com/symfony/symfony/pull/38177 2fa authentication https://github.com/scheb/2fa Help needed - https://github.com/symfony/symfony/issues/30914 Sudo mode and more

Slide 38

Slide 38 text

Security Bootstrap a new project the fast way $ symfony new --version=next demo $ composer req maker profiler orm validator form security $ vi docker-compose.yml $ docker-compose up -d $ symfony server:start -d $ symfony open:local version: '3' services: database: image: postgres:12-alpine environment: POSTGRES_USER: main POSTGRES_PASSWORD: main POSTGRES_DB: main ports: [5432] mailer: image: schickling/mailcatcher ports: [1025, 1080]

Slide 39

Slide 39 text

The name of the security user class (e.g. User) [User]: > Do you want to store user data in the database (via Doctrine)? (yes/no) [yes]: > Enter a property name that will be the unique "display" name for the user (e.g. email, username, uuid) [email]: > Will this app need to hash/check user passwords? Choose No if passwords are not needed or will be checked/hashed by some other system (e.g. a single sign-on server). Does this app need to hash/check user passwords? (yes/no) [yes]: > $ symfony console make:user

Slide 40

Slide 40 text

What style of authentication do you want? [Empty authenticator]: [0] Empty authenticator [1] Login form authenticator > 1 The class name of the authenticator to create (e.g. AppCustomAuthenticator): > AppAuthenticator Choose a name for the controller class (e.g. SecurityController) [SecurityController]: > Do you want to generate a '/logout' URL? (yes/no) [yes]: > $ symfony console make:auth

Slide 41

Slide 41 text

Creating a registration form for App\Entity\User Do you want to add a @UniqueEntity validation annotation on your User class to make sure duplicate accounts aren't created? (yes/no) [yes]: > Do you want to send an email to verify the user's email address after registration? (yes/no) [yes]: > [WARNING] We're missing some important components. Don't forget to install these after you're finished. composer require symfonycasts/verify-email-bundle symfony/mailer What email address will be used to send registration confirmations? e.g. mailer@your-domain.com: > demo@example.com What "name" should be associated with that email address? e.g. "Acme Mail Bot": > Demo Bot Do you want to automatically authenticate the user after registration? (yes/no) [yes]: > $ symfony console make:registration-form

Slide 42

Slide 42 text

--- a/src/Security/AppAuthenticator.php +++ b/src/Security/AppAuthenticator.php @@ -96,8 +96,7 @@ class AppAuthenticator extends AbstractFormLoginAuthenticator implements Passwor return new RedirectResponse($targetPath); } - // For example : return new RedirectResponse($this->urlGenerator->generate('some_route')); - throw new \Exception('TODO: provide a valid redirect inside '.__FILE__); + return new RedirectResponse($this->urlGenerator->generate('app_login')); } protected function getLoginUrl() $ symfony console make:registration-form

Slide 43

Slide 43 text

Security Bootstrap a new project the fast way $ symfony make:migration $ symfony console doctrine:migrations:migrate -n

Slide 44

Slide 44 text

https://127.0.0.1:8000/register $ symfony open:local:webmail

Slide 45

Slide 45 text

https://127.0.0.1:8000/logout https://127.0.0.1:8000/login

Slide 46

Slide 46 text

2FA / MFA https://github.com/scheb/2fa

Slide 47

Slide 47 text

&

Slide 48

Slide 48 text

PHP 8 Attributes use Symfony\Component\Routing\Attribute\Route; class ActionPathController { #[Route('/{name}', name: 'hello')] public function action() { } } class AutowireSetter { #[Required] public function setFoo(Foo $foo): void { } } https://github.com/symfony/symfony/pull/37545 https://github.com/symfony/symfony/pull/37474

Slide 49

Slide 49 text

PHP 8 Attributes We need your help https://github.com/symfony/symfony/issues/38096 https://github.com/symfony/symfony/pull/38162 Add support for Constraints Think of new possibilities Replace SensioFrameworkExtraBundle public function searchAction( #[RequestQuery] string $q, #[RequestQuery] int $page = 1 ) {

Slide 50

Slide 50 text

Speed improvements

Slide 51

Slide 51 text

Cache + Messenger = framework: cache: pools: test.cache: early_expiration_message_bus: messenger.default_bus messenger: routing: 'Symfony\Component\Cache\Messenger\EarlyExpirationMessage': amqp https://github.com/symfony/symfony/pull/30572

Slide 52

Slide 52 text

PHP 7.4 preloading opcache.preload=/app/src/.preload.php

Slide 53

Slide 53 text

Some fun again French Inflector use Symfony\Component\String\Inflector\FrenchInflector; $inflector = new FrenchInflector(); $result = $inflector->singularize('dents'); // ['dent'] $result = $inflector->singularize('souris'); // ['souris'] $result = $inflector->singularize('messieurs'); // ['monsieur'] $result = $inflector->pluralize('cinquante'); // ['cinquante'] $result = $inflector->pluralize('pou'); // ['poux'] $result = $inflector->pluralize('cheval'); // ['chevaux'] https://github.com/symfony/symfony/pull/36929

Slide 54

Slide 54 text

https://symfony.com/sponsor Support Symfony Thank you!