Slide 1

Slide 1 text

What's New in Symfony 5.1?

Slide 2

Slide 2 text

! Marco Petersen " Software Developer @ SensioLabs # @ocrampete16

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

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.

Slide 5

Slide 5 text

Deprecations

Slide 6

Slide 6 text

Deprecation(s)

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

What's New?

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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/

Slide 13

Slide 13 text

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)

Slide 14

Slide 14 text

Service Container

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

Autowire public typed properties Contributed by Sébastien Morel use Twig\Environment; class SomeServiceClass { /** @required */ public Environment $twig; public function someMethod() { $this->twig->render('...'); // ... } }

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

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.

Slide 22

Slide 22 text

Routing

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

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 }

Slide 28

Slide 28 text

Validator

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

Security

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

"Microapplications"

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

Miscellaneous Changes

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

No content