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

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?

    View Slide

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

    View Slide

  3. Symfony 5.1 Status
    • In development
    • Release: End of May 2020
    • End of support: January 2021

    View Slide

  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.

    View Slide

  5. Deprecations

    View Slide

  6. Deprecation(s)

    View Slide

  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']

    View Slide

  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;
    }

    View Slide

  9. What's New?

    View Slide

  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();

    View Slide

  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"

    View Slide

  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/

    View Slide

  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)

    View Slide

  14. Service Container

    View Slide

  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;
    // ...
    }

    View Slide

  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
    // }
    // ]

    View Slide

  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('...');
    // ...
    }
    }

    View Slide

  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']

    View Slide

  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: ~

    View Slide

  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

    View Slide

  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.

    View Slide

  22. Routing

    View Slide

  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

    View Slide

  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/'

    View Slide

  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
    {
    // ...
    }

    View Slide

  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()
    {
    // ...
    }
    }

    View Slide

  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
    }

    View Slide

  28. Validator

    View Slide

  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(),
    ];
    }
    }

    View Slide

  30. namespace App\Dto;
    // ...
    use App\Validator\MatchesPasswordRequirements;
    class ChangePasswordDto
    {
    /**
    * @MatchesPasswordRequirements
    */
    private $newPassword;
    // ...
    }

    View Slide

  31. /**
    * @var string
    *
    * @Assert\Sequentially({
    * @Assert\Type("string"),
    * @Assert\Length(min="4"),
    * @Assert\Regex("[a-z]"),
    * @SomeCustomConstraintWithHeavyExternalCalls(),
    * })
    */
    public $someProperty;

    View Slide

  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'];

    View Slide

  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;
    }

    View Slide

  34. Security

    View Slide

  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');

    View Slide

  36. Access decision based on voter priority
    Contributed by Andreas Schempp
    # config/packages/security.yaml
    security:
    access_decision_manager:
    strategy: priority
    # ...

    View Slide

  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

    View Slide

  38. "Microapplications"

    View Slide

  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));
    }
    }

    View Slide

  40. $app = new MySymfonyApp('dev', true);
    $request = Request::createFromGlobals();
    $response = $app->handle($request);
    $response->send();
    $app->terminate($request, $response);

    View Slide

  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();

    View Slide

  42. Miscellaneous
    Changes

    View Slide

  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' }
    # ...

    View Slide

  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('[email protected]');
    $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!');
    }

    View Slide

  45. Thanks for watching!
    Thanks to all of you who make Symfony .
    $kernel->terminate($request, $response);

    View Slide

  46. View Slide