$30 off During Our Annual Pro Sale. View Details »

What's New in Symfony 5.1?

What's New in Symfony 5.1?

Marco Petersen

May 19, 2020
Tweet

More Decks by Marco Petersen

Other Decks in Programming

Transcript

  1. What's New in Symfony 5.1?

  2. ! Marco Petersen " Software Developer @ SensioLabs # @ocrampete16

  3. Symfony 5.1 Status • In development • Release: End of

    May 2020 • End of support: January 2021
  4. LTS vs Latest Release • Try and keep up with

    the latest release! • New features are added in minor releases. • Major version jumps (eg. 4.4 ➡ 5.0) only remove deprecated APIs.
  5. Deprecations

  6. Deprecation(s)

  7. The Inflector Component • converts between singular and plural forms

    in English • moved to the String component // before use Symfony\Component\Inflector\Inflector; Inflector::singularize('alumni'); // 'alumnus' Inflector::pluralize('person'); // ['persons', 'people'] // after use Symfony\Component\String\Inflector\EnglishInflector; $inflector = new EnglishInflector(); $result = $inflector->singularize('teeth'); // ['tooth'] $result = $inflector->pluralize('person'); // ['persons', 'people']
  8. namespace Symfony\Component\String\Inflector; interface InflectorInterface { // the returned values are

    arrays because in some cases, there // are multiple valid singulars/plurals for a given word public function singularize(string $plural): array; public function pluralize(string $singular): array; }
  9. What's New?

  10. Uid Component Contributed by Grégoire Pineau and Nicolas Grekas use

    Symfony\Component\Uid\Uuid; use Symfony\Component\Uid\Ulid; // generating a random UUID type 4 (all UUID types are supported) $uuid = Uuid::v4(); // generating a UUID Type 6 (which is not part of the standard, but it's // supported by the component because it's popular enough) $uuid = Uuid::v6(); // generating a ULID (there's only one type of them) $ulid = new Ulid();
  11. // checking if some UUID is null use Symfony\Component\Uid\NilUuid; if

    ($uuid instanceof NilUuid) { // ... } // comparing UUIDs $uuid1 = Uuid::v1(); $uuid4 = Uuid::v4(); $uuid1->equals($uuid4); // false // converting to different formats $ulid = Ulid::fromString('01E439TP9XJZ9RPFH3T1PYBCR8'); $ulid->toBinary(); // string(16) "..." (binary contents can't be printed) $ulid->toBase32(); // string(26) "01E439TP9XJZ9RPFH3T1PYBCR8" $ulid->toBase58(); // string(22) "1BKocMc5BnrVcuq2ti4Eqm" $ulid->toRfc4122(); // string(36) "0171069d-593d-97d3-8b3e-23d06de5b308"
  12. Async AWS Support Contributed by Jérémy Derussé and Tobias Nyholm

    • https://async-aws.com/ • an unofficial SDK for AWS • asynchronous by default (uses the Symfony HTTP Client) • Symfony 5.1 now uses it by default if it is installed: $ composer require async-aws/<package>
  13. New and Improved Integrations By various contributors • Lock: MongoDB

    integration • Cache: Couchbase adapter, SodiumMarshaller for encryption, LRU for ArrayCache • Mailer: improved Mailgun integration • Messenger: AWS SQS, PostgreSQL & improved Redis integration • Notifier: Mattermost & RocketChat (chat), Firebase (push), OVH Cloud & Sinch & Free Mobile (SMS)
  14. Service Container

  15. Support for typed properties in PropertyInfo Contributed by Kévin Dunglas

    use Symfony\Component\HttpFoundation\Request; class SomeClass { public int $id; protected string $name; private ?bool $logResult; public Request $request; // ... }
  16. $info = $propertyInfo->getTypes(SomeClass::class, 'logResult'); // $info = [ // class

    Symfony\Component\PropertyInfo\Type (6) { // private $builtinType => string(4) "bool" // private $nullable => bool(true) // private $class => NULL // private $collection => bool(false) // private $collectionKeyType => NULL // private $collectionValueType => NULL // } // ]
  17. Autowire public typed properties Contributed by Sébastien Morel use Twig\Environment;

    class SomeServiceClass { /** @required */ public Environment $twig; public function someMethod() { $this->twig->render('...'); // ... } }
  18. Simpler service decoration Contributed by Nicolas Grekas # config/services.yaml services:

    App\Mailer: ~ # Before App\SpecialMailer: decorates: App\Mailer arguments: ['@App\SpecialMailer.inner'] # After App\SpecialMailer: decorates: App\Mailer arguments: ['@.inner']
  19. Stack decorators Contributed by Nicolas Grekas services: # before App\Mailer\Mailer:

    ~ App\Mailer\RateLimitedMailer: decorates: App\Mailer\Mailer arguments: [20] # mails per second App\Mailer\LoggingMailer: decorates: App\Mailer\Mailer # after App\Mailer\Mailer: stack: - App\Mailer\LoggingMailer: ~ - App\Mailer\RateLimitedMailer: arguments: [20] - App\Mailer\Mailer: ~
  20. Abstract service arguments Contributed by Islam Israfilov services: # before

    Symfony\Bundle\MakerBundle\Generator: $rootNamespace: ~ # defined in MakerPass # after Symfony\Bundle\MakerBundle\Generator: $rootNamespace: !abstract defined in MakerPass
  21. Deprecate public services into private services Contributed by Thomas Calvet

    services: foo: # ... public: true tags: - { name: 'container.private', package: 'foo/bar', 'version': '1.2' } Since foo/bar 1.2: Accessing the "foo" service directly from the container is deprecated, use dependency injection instead.
  22. Routing

  23. Different hosts per locale Contributed by Olivier Dolbeau # config/routes/annotations.yaml

    controllers: resource: '../../src/Controller/' type: annotation host: fr: www.example.fr en: www.example.com
  24. Simpler Request Context Contributed by Benjamin Lévêque and Nicolas Grekas

    # Before parameters: router.request_context.scheme: 'https' router.request_context.host: 'example.org' router.request_context.base_url: 'my/path' # After framework: router: default_uri: 'https://example.org/my/path/'
  25. Route annotations priority Contributed by Nicolas Grekas /** * @Route("/{some_parameter}",

    name="route1") */ public function someMethod(): Response { // ... } /** * @Route("/foo", priority=10, name="route2") */ public function anotherMethod(): Response { // ... }
  26. Stateless Routes Contributed by Mathias Arlaud // src/Controller/MainController.php namespace App\Controller;

    use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\Routing\Annotation\Route; class MainController extends AbstractController { /** * @Route("/", name="homepage", stateless=true) */ public function homepage() { // ... } }
  27. Env vars in route conditions Contributed by Ahmed Tailouloute /**

    * @Route("/new-feature", condition="env('bool:IS_FEATURE_ENABLED') === true") */ public function __invoke() { // this route will only execute when the value of the // IS_FEATURE_ENABLED env var is TRUE }
  28. Validator

  29. Reusable constraint sets Contributed by Maxime Steinhausser use Symfony\Component\Validator\Constraints\Compound; /**

    * @Annotation */ class MatchesPasswordRequirements extends Compound { protected function getConstraints(array $options): array { return [ new NotBlank(), new Type('string'), new Length(['min' => 12]), new NotCompromisedPassword(), ]; } }
  30. namespace App\Dto; // ... use App\Validator\MatchesPasswordRequirements; class ChangePasswordDto { /**

    * @MatchesPasswordRequirements */ private $newPassword; // ... }
  31. /** * @var string * * @Assert\Sequentially({ * @Assert\Type("string"), *

    @Assert\Length(min="4"), * @Assert\Regex("[a-z]"), * @SomeCustomConstraintWithHeavyExternalCalls(), * }) */ public $someProperty;
  32. AtLeastOneOf validator Contributed by Przemysław Bogusz /** * @Assert\AtLeastOneOf({ *

    @Assert\Length(min=5), * @Assert\EqualTo("bar") * }) */ public $name = 'foo'; /** * @Assert\AtLeastOneOf({ * @Assert\All({@Assert\GreaterThanOrEqual(10)}), * @Assert\Count(20) * }) */ public $numbers = ['3', '5']; /** * @Assert\All({ * @Assert\AtLeastOneOf({ * @Assert\GreaterThanOrEqual(5), * @Assert\LessThanOrEqual(3) * }) * }) */ public $otherNumbers = ['4', '5'];
  33. Hostname Validator Contributed by Dmitrii Poddubnyi // src/Entity/ServerSettings.php namespace App\Entity;

    use Symfony\Component\Validator\Constraints as Assert; class ServerSettings { /** * @Assert\Hostname(message="The server name must be a valid hostname.") */ protected $name; }
  34. Security

  35. Simpler security attributes Contributed by Jules Pietri and Wouter De

    Jong // BEFORE $this->isGranted('IS_AUTHENTICATED_REMEMBERED') && !$this->isGranted('IS_AUTHENTICATED_FULLY'); $this->isGranted('IS_AUTHENTICATED_ANONYMOUSLY') && !$this->isGranted('IS_AUTHENTICATED_REMEMBERED') && !$this->isGranted('IS_AUTHENTICATED_FULLY'); $this->isGranted('ROLE_PREVIOUS_ADMIN'); // AFTER $this->isGranted('IS_REMEMBERED'); $this->isGranted('IS_ANONYMOUS'); $this->isGranted('IS_IMPERSONATOR');
  36. Access decision based on voter priority Contributed by Andreas Schempp

    # config/packages/security.yaml security: access_decision_manager: strategy: priority # ...
  37. Simpler logout customization Contributed by Wouter De Jong # config/services.yaml

    services: # ... App\EventListener\MyCustomLogoutListener: tags: - name: 'kernel.event_listener' event: 'Symfony\Component\Security\Http\Event\LogoutEvent' dispatcher: security.event_dispatcher.main
  38. "Microapplications"

  39. Improved Microkernel Contributed by Nicolas Grekas class MySymfonyApp extends Kernel

    { use MicroKernelTrait; protected function configureContainer(ContainerConfigurator $container): void { $container->services() ->load('App\\', '../src') ->set(Foo::class)->factory([$this, 'createFoo']); } public function createFoo(Bar $bar) { return new Foo($bar); } protected function configureRoutes(RoutingConfigurator $routes): void { $routes->add('home', '/')->controller([$this, 'helloAction']); } public function helloAction(Foo $foo) { return new Response('Hello '.get_class($foo)); } }
  40. $app = new MySymfonyApp('dev', true); $request = Request::createFromGlobals(); $response =

    $app->handle($request); $response->send(); $app->terminate($request, $response);
  41. Single command applications Contributed by Grégoire Pineau use Symfony\Component\Console\Input\InputArgument; use

    Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\SingleCommandApplication; (new SingleCommandApplication()) ->setName('My Super Command') ->setVersion('1.0.0') ->setHelp('This command allows you to...') ->addArgument('foo', InputArgument::OPTIONAL, 'The directory') ->addOption('bar', null, InputOption::VALUE_REQUIRED) ->setCode(function (InputInterface $input, OutputInterface $output) { // ... }) ->run();
  42. Miscellaneous Changes

  43. Configurable PHP Preloading Contributed by Nicolas Grekas services: twig: class:

    Twig\Environment # ... tags: - { name: 'container.preload', class: 'Twig\Cache\FilesystemCache' } - { name: 'container.preload', class: 'Twig\Extension\CoreExtension' } - { name: 'container.preload', class: 'Twig\Extension\EscaperExtension' } - { name: 'container.preload', class: 'Twig\Extension\OptimizerExtension' } # ...
  44. Simpler login in tests Contributed by Wouter De Jong public

    function testVisitingWhileLoggedIn() { $client = static::createClient(); // get or create the user somehow (e.g. creating some users only // for tests while loading the test fixtures) $userRepository = static::$container->get(UserRepository::class); $testUser = $userRepository->findOneByEmail('jane.doe@example.com'); $client->loginUser($testUser); // user is now logged in, so you can test protected resources $client->request('GET', '/profile'); $this->assertResponseIsSuccessful(); $this->assertSelectorTextContains('h1', 'Hello Username!'); }
  45. Thanks for watching! Thanks to all of you who make

    Symfony . $kernel->terminate($request, $response);
  46. None