Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Symfony 5.2

Fabien Potencier
September 23, 2020

Symfony 5.2

What's new in Symfony 5.2

Fabien Potencier

September 23, 2020
Tweet

More Decks by Fabien Potencier

Other Decks in Technology

Transcript

  1. 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');
  2. 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(' '));
  3. 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(); } }
  4. Default Command vs Single Command Applications #!/usr/bin/env php <?php use

    Symfony\Component\Console\SingleCommandApplication; require __DIR__.'/vendor/autoload.php'; (new SingleCommandApplication()) ->setCode( function (InputInterface $input, OutputInterface $output) { // add here the code of your console command... } ) ->run(); #!/usr/bin/env php <?php use Dbu\SnakeBundle\Command\SnakeCommand; use Symfony\Component\Console\Application; require __DIR__.'/vendor/autoload.php'; $app = new Application(); $app->add(new SnakeCommand()); $app->setDefaultCommand('game:snake'); $app->run(); 5.1
  5. 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
  6. $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
  7. $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
  8. 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); ]);
  9. 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
  10. 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
  11. 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
  12. 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...
  13. { "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": "[email protected]", "name": "" } ] } ] }, "body": null, "message": null } Mailer: Incremental improvements Better serialization, lightweight payload and no binaries https://github.com/symfony/symfony/pull/37847
  14. $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
  15. 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
  16. 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
  17. 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
  18. 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
  19. 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
  20. 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
  21. 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
  22. 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]
  23. 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
  24. 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
  25. 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. [email protected]: > [email protected] 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
  26. --- 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
  27. Security Bootstrap a new project the fast way $ symfony

    make:migration $ symfony console doctrine:migrations:migrate -n
  28. &

  29. 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
  30. 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 ) {
  31. 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
  32. 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