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

What's new in Symfony 4.4/5.0

What's new in Symfony 4.4/5.0

069a861584701a8b5f72a838bd7e0f2e?s=128

Jan Schädlich

January 06, 2020
Tweet

More Decks by Jan Schädlich

Other Decks in Programming

Transcript

  1. None
  2. Jan Schädlich jan.schaedlich@sensiolabs.de @jschaedl @janschaedlich

  3. Looking for a Job? https://sensiolabs.de/jobs/96454

  4. Agenda Deprecations Improvements New Components

  5. None
  6. 4.4 Deprecations Bugfixes Bugfixes Features Features Deprecations 5.0 What are

    the Differences?
  7. Deprecations Symfony 4.4 from 4.3 to 4.4 Code will be

    removed in Symfony 5.0
  8. Non-int return value in Command::execute() Contributed by jschaedl in #33775

    namespace App\Command; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; class CreateUserCommand extends Command { protected static $defaultName = 'app:create-user'; // ... protected function execute(InputInterface $input, OutputInterface $output) { // ... } } Console
  9. Non-int return value in Command::execute() Contributed by jschaedl in #33775

    protected function execute(InputInterface $input, OutputInterface $output) { // ... return 0; } Console
  10. Deprecated tag !tagged in favor of !tagged_iterator Contributed by jschaedl

    in #31321 # Before services: App\Handler: tags: ['app.handler'] App\HandlerCollection: arguments: [!tagged app.handler] # After services: App\Handler: tags: ['app.handler'] App\HandlerCollection: arguments: [!tagged_iterator app.handler] DependencyInjection
  11. Deprecated short factories/configurators YAML syntax Contributed by nicolas-grekas in #31543

    # Before services: my_service: factory: factory_service:method # After services: my_service: factory: ['@factory_service', method] DependencyInjection
  12. Deprecate int/float for string input in NumberType Contributed by xabbuh

    in #32130 use Symfony\Component\Form\Extension\Core\Type\NumberType; $form = $this->factory->create(NumberType::class, 2.99, [ 'input' => 'string', 'scale' => 2, ]); Form
  13. Deprecated HeaderBag::get() returning an array Contributed by Simperfit in #32122

    // Symfony 4.3 namespace Symfony\Component\HttpFoundation; class HeaderBag implements \IteratorAggregate, \Countable { /** * Returns a header value by name. * * @param string $key The header name * @param string|null $default The default value * @param bool $first Whether to return the first value or all header values * * @return string|string[]|null The first header value or default value if $first is true, * an array of values otherwise */ public function get($key, $default = null, $first = true) {...} } HttpFoundation
  14. Deprecated HeaderBag::get() returning an array Contributed by Simperfit in #32122

    namespace Symfony\Component\HttpFoundation; class HeaderBag implements \IteratorAggregate, \Countable { // Symfony 4.4, using argument $first is deprecated /** * @return string|string[]|null The first header value or default value if $first is * true, an array of values otherwise */ public function get($key, $default = null) {…} // Symfony 5.0 /** * @return string|null The first header value or default value */ public function get(string $key, string $default = null) {...} } HttpFoundation
  15. Deprecated HeaderBag::get() returning an array Contributed by Simperfit in #32122

    class HeaderBag implements \IteratorAggregate, \Countable { // Symfony 4.4 public function all(/*string $key = null*/) {…} // Symfony 5.0 public function all(string $key = null) {...} } HttpFoundation
  16. Deprecated passing arguments to Request::isMethodSafe() Contributed by dFayet in #31658

    // Symfony 4.3 namespace Symfony\Component\HttpFoundation; class Request /** * Checks whether or not the method is safe. * * @param bool $andCacheable Adds the additional condition that the * method should be cacheable. True by default. * * @return bool */ public function isMethodSafe(/* $andCacheable = true */) {...} } HttpFoundation
  17. Deprecated passing arguments to Request::isMethodSafe() Contributed by dFayet in #31658

    // Symfony 4.3 $request->isMethodSafe(true); // throws BadMethodCallException $request->isMethodSafe(); // throws BadMethodCallException $request->isMethodSafe(false); // Symfony 4.4 $request->isMethodSafe(false); // deprecated // use $request->isMethodSafe(); $request->isMethodCachable(); HttpFoundation
  18. Deprecated returning non-boolean values from checkCredentials() Contributed by derrabus in

    #33308 # Symfony 4.3 # Guard\AuthenticatorInterface.php /** * Returns true if the credentials are valid. * * If any value other than true is returned, authentication will * fail. You may also throw an AuthenticationException if you wish * to cause authentication to fail. * * The *credentials* are the return value from getCredentials() * * @param mixed $credentials * @return bool * @throws AuthenticationException */ public function checkCredentials($credentials, UserInterface $user); Security
  19. Deprecated returning non-boolean values from checkCredentials() Contributed by derrabus in

    #33308 # Symfony 4.4 # Guard\AuthenticatorInterface.php /** * Returns true if the credentials are valid. * * If false is returned, authentication will fail. You may also throw * an AuthenticationException if you wish to cause authentication to fail. * * The *credentials* are the return value from getCredentials() * * @param mixed $credentials * @return bool * @throws AuthenticationException */ public function checkCredentials($credentials, UserInterface $user); Security
  20. Deprecated isGranted() on more than one attribute Contributed by wouterj

    in #33584 // Before if ($this->authorizationChecker->isGranted(['ROLE_USER', 'ROLE_ADMIN'])) { // ... } // After if ($this->authorizationChecker->isGranted( new Expression("is_granted('ROLE_USER') or is_granted(‘ROLE_ADMIN')")) ) {} // or if ($this->authorizationChecker->isGranted('ROLE_USER') || $this->authorizationChecker->isGranted('ROLE_ADMIN')) {} Security
  21. Debug Component deprecated Use the new ErrorHandler Component instead!

  22. WebServer Bundle $ curl -sS https://get.symfony.com/cli/installer | bash deprecated Use

    the Symfony CLI instead!
  23. └── MyBundle/ ├── config/ ├── public/ ├── src/ │ └──

    MyBundle.php ├── templates/ └── translations class MyBundle extends Bundle { public function getPath(): string { return \dirname(__DIR__); } } Added new Bundle directory convention consistent with standard skeleton HttpKernel
  24. Type Declarations and Return Types https://symfony.com/blog/symfony-type-declarations-return-types https://github.com/symfony/symfony/issues/32179

  25. BC-Breaks Symfony 4.4 from 4.3 to 4.4

  26. - [HttpClient] Added method cancel() to ResponseInterface. - [Mailer] Changed

    the DSN to use for disabling delivery (using the NullTransport) from smtp://null to null://null (host doesn't matter). - [Mailer] Renamed class SmtpEnvelope to Envelope and DelayedSmtpEnvelope to DelayedEnvelope. - [Mailer] Added a required string $transport argument to MessageEvent::__construct. - [Messenger] Removed SendersLocatorInterface::getSenderByAlias added in 4.3. - [Messenger] Removed $retryStrategies argument from Worker::__construct. - [Messenger] Changed arguments of ConsumeMessagesCommand::__construct. - [Messenger] Removed $senderClassOrAlias argument from RedeliveryStamp::__construct. - [Messenger] Removed UnknownSenderException. - [Messenger] Removed WorkerInterface. - [Messenger] Removed $onHandledCallback of Worker::run(array $options = [], callable $onHandledCallback = null). - [Messenger] Removed StopWhenMemoryUsageIsExceededWorker in favor of StopWorkerOnMemoryLimitListener. - [Messenger] Removed StopWhenMessageCountIsExceededWorker in favor of StopWorkerOnMessageLimitListener. - [Messenger] Removed StopWhenTimeLimitIsReachedWorker in favor of StopWorkerOnTimeLimitListener. - [Messenger] Removed StopWhenRestartSignalIsReceived in favor of StopWorkerOnRestartSignalListener. - [Mime] Removed NamedAddress, use Address instead (which supports a name now)
  27. There is even more https://github.com/symfony/symfony/blob/master/UPGRADE-4.4.md https://github.com/symfony/symfony/blob/master/UPGRADE-5.0.md

  28. Pause?

  29. Improvements

  30. Improved Type Constraint Contributed by jschaedl in #31351 // src/Entity/Author.php

    use Symfony\Component\Validator\Constraints as Assert; class Author { /** * @Assert\Type("Ramsey\Uuid\UuidInterface") */ protected $id; /** * @Assert\Type("string") */ protected $firstName; // ... } Validator
  31. Improved Type Constraint Contributed by jschaedl in #31351 // src/Entity/Author.php

    use Symfony\Component\Validator\Constraints as Assert; class Author { // ... /** * @Assert\Type(type={"alpha", "digit"}) */ protected $accessCode; // ... } Validator
  32. Week Form Type Contributed by dFayet in #32061 $builder->add('startDateTime', WeekType::class,

    [ // use this if you store week numbers as strings ('2011-W17') 'input' => 'string', // use this if you store week numbers as arrays (e.g. [2011, 17]) 'input' => 'array', // renders two <select> to select the year and week number 'widget' => 'choice', // renders two <input type="text"> to write the year and week number 'widget' => 'text', // renders a <input type="week"> which is properly rendered by most browsers 'widget' => 'single_text', ]); Form
  33. PHP Assertions for Email Messages Contributed by fabpot in #32930

    // tests/Controller/DefaultControllerTest.php use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; class DefaultControllerTest extends WebTestCase { public function testSomething() { $client = static::createClient(); $client->request('GET', '/newsletter-signup'); // ... $this->assertEmailCount(2); $this->assertEmailIsQueued($this->getMailerEvent(0)); $email = $this->getMailerMessage(0); $this->assertEmailHeaderSame($email, 'To', 'fabien@symfony.com'); $this->assertEmailTextBodyContains($email, 'Welcome to Symfony!'); $this->assertEmailAttachementCount($email, 1); } } FrameworkBundle
  34. PHP Assertions for Email Messages Contributed by fabpot in #32930

    FrameworkBundle $this->assertEmailCount() $this->assertQueuedEmailCount() $this->assertEmailIsQueued() $this->assertEmailIsNotQueued() $this->assertEmailAttachementCount() $this->assertEmailTextBodyContains() $this->assertEmailTextBodyNotContains() $this->assertEmailHtmlBodyContains() $this->assertEmailHtmlBodyNotContains() $this->assertEmailHasHeader() $this->assertEmailNotHasHeader() $this->assertEmailHeaderSame() $this->assertEmailHeaderNotSame() $this->assertEmailAddressContains()
  35. Simpler Event Listeners Contributed by derrabus in #33851 EventDispatcher use

    Symfony\Component\HttpKernel\Event\RequestEvent; final class MyRequestListener { public function __invoke(RequestEvent $event): void { // ... } } services: App\EventListener\MyRequestListener: tags: - - { name: kernel.event_listener, event: kernel.request } + - { name: kernel.event_listener } # config/services.yaml services: App\EventListener\: resource: ../src/EventListener/* tags: ['kernel.event_listener']
  36. Allow Binding Tagged Services Contributed by lyrixx in #33623 services:

    _instanceof: App\Foo\Rule\RuleInterface: tags: ['app.foo.rule'] _defaults: bind: iterable $rules: !tagged_iterator app.foo.rule # ... DependencyInjection
  37. Improved YAML Syntax for Method Calls Contributed by lyrixx in

    #33623 services: App\Service\MessageGenerator: # ... calls: - method: setLogger arguments: - '@logger' DependencyInjection Contributed by nicolas-grekas in #33779. services: App\Service\MessageGenerator: # ... calls: - setLogger: ['@logger']
  38. Priorities for Tagged Services Contributed by lyrixx in #33623 services:

    _instanceof: App\Handler: tags: - { name: 'app.handler', priority: 20 } App\HandlerCollection: arguments: [!tagged_iterator app.handler] DependencyInjection services: # ... App\HandlerCollection: arguments: [!tagged_iterator app.handler, default_priority_method: 'calculateServicePriority'] final class MyService { public static function getDefaultPriority(): int { return 0; } } }
  39. Mailer Integration Contributed by fabpot in #32912 WebProfilerBundle

  40. HttpClient Integration Contributed by tyx and jeremyFreeAgent in #33015 WebProfilerBundle

  41. Clear Ajax Requests Contributed by Matts in #31876 WebProfilerBundle

  42. Service Container Linter DependencyInjection Contributed by alcalyn, GuilhemN and nicolas-grekas

    in #33015 $ bin/console lint:container
  43. Service Container Linter DependencyInjection Contributed by alcalyn, GuilhemN and nicolas-grekas

    in #33015 namespace App\SomeNamespace; class SomeService { public function __construct(int $someProperty = 7) { // ... } } services: App\SomeNamespace\SomeService: ~ Invalid definition for service "App\SomeNamespace\SomeService": argument 1 of "App\SomeNamespace\SomeService::__construct" accepts "int", "NULL" passed.
  44. Service Container Linter DependencyInjection Contributed by alcalyn, GuilhemN and nicolas-grekas

    in #33015 namespace App\SomeNamespace; class SomeService { public function setSomeItems( SomeClass $item, SomeClass …$items ) { // ... } } Invalid definition for service "App\SomeNamespace\SomeService": argument 2 of "App\SomeNamespace\SomeService::setSomeItems" accepts "App\SomeNamespace\SomeClass", "App\AnotherNamespace\SomeDifferentClass" passed. services: foo: class: App\SomeNamespace\SomeClass bar: class: App\AnotherNamespace\SomeDifferentClass App\SomeNamespace\SomeService: calls: - method: setSomeItems arguments: - '@foo' - '@bar'
  45. Notification Emails Contributed by fabpot in #33605 use Symfony\Bridge\Twig\Mime\NotificationEmail; $email

    = (new NotificationEmail()) ->from('fabien@example.com') ->to('fabien@example.org') ->subject('My first notification email via Symfony') ->markdown(<<<EOF There is a **problem** on your website, you should investigate it right now. Or just wait, the problem might solves itself automatically, we never know. EOF ) ->action('More info?', 'https://example.com/') ->importance(NotificationEmail::IMPORTANCE_HIGH) ; Mime
  46. Notification Emails Contributed by fabpot in #33605 Mime

  47. Lazy Firewalls Contributed by nicolas-grekas in #33676 # config/packages/security.yaml security:

    # ... firewalls: main: pattern: ^/ anonymous: ~ # ... Security # config/packages/security.yaml security: # ... firewalls: main: pattern: ^/ anonymous: lazy # ...
  48. Added Support for Alpha-3 Codes Contributed by creiner in #33791

    use Symfony\Component\Form\Extension\Core\Type\CountryType; // ... $builder->add('country', CountryType::class, [ 'alpha3' => true, // ISO 3166-1, e.g deu ]); Form
  49. Password Migrations Contributed by nicolas-grekas in #31594, #31597 and #31843

    # config/packages/security.yaml security: # ... encoders: App\Entity\User: algorithm: auto cost: 14 Security use Symfony\Component\Security\Core\User\PasswordUpgraderInterface; class UserRepository extends EntityRepository implements PasswordUpgraderInterface { public function upgradePassword(UserInterface $user, string $newEncodedPassword): void { // this code is only an example; the exact code will depend on $user->setPassword($newEncodedPassword); $this->getEntityManager()->flush($user); } }
  50. Password Hashing Contributed by chalas_r in #34020 and #34139 security:

    # ... encoders: App\Entity\User: algorithm: 'argon2i' algorithm: 'argon2id' algorithm: 'auto' algorithm: 'bcrypt' algorithm: 'sodium' Security # config/packages/security.yaml security: # ... encoders: App\Entity\User: algorithm: 'argon2i' migrate_from: 'bcrypt'
  51. Preloading Symfony Applications in PHP 7.4

  52. OPCache Preloading in Practice ; php.ini opcache.preload=/path/to/the/preload.php

  53. OPCache Preloading in Symfony ; php.ini opcache.preload=/path/to/project/var/cache/prod/App_KernelProdContainer.preload.php

  54. OPCache Preloading in Symfony namespace Symfony\Component\HttpKernel; abstract class Kernel implements

    KernelInterface, RebootableInterface, TerminableInterface { /** * Gets the classes to list in the preloading script. * * When a class is listed, all its parent classes or interfaces are automatically listed too. * Service classes are also automatically preloaded and don't need to be listed explicitly. */ public function getClassesToPreload(): array { //... } }
  55. OPCache Preloading in Symfony namespace Symfony\Component\HttpKernel\DependencyInjection; abstract class Extension extends

    BaseExtension { /** * Adds classes to list in the preloading script. * * When a class is listed, all its parent classes or interfaces are automatically listed too. * Service classes are also automatically preloaded and don't need to be listed explicitly. */ public function addClassesToPreload(array $preloadedClasses): void { //... } }
  56. There is even more https://symfony.com/blog/category/living-on-the-edge/5.0-4.4 https://symfony.com/blog/symfony-4-4-curated-new-features https://symfony.com/blog/symfony-5-0-curated-new-features

  57. Pause?

  58. New Components

  59. ErrorHandler Component Symfony 4.4 The ErrorHandler component provides tools to

    manage errors and ease debugging PHP code. $ composer require symfony/error-handler
  60. # public/index.php <?php use App\Kernel; // Before use Symfony\Component\Debug\Debug; require

    dirname(__DIR__).'/config/bootstrap.php'; if ($_SERVER['APP_DEBUG']) { umask(0000); Debug::enable(); } // ... $kernel = new Kernel($_SERVER['APP_ENV'], (bool) $_SERVER['APP_DEBUG']); $request = Request::createFromGlobals(); $response = $kernel->handle($request); $response->send(); $kernel->terminate($request, $response);
  61. # public/index.php <?php use App\Kernel; // After use Symfony\Component\ErrorHandler\Debug; require

    dirname(__DIR__).'/config/bootstrap.php'; if ($_SERVER['APP_DEBUG']) { umask(0000); Debug::enable(); } // ... $kernel = new Kernel($_SERVER['APP_ENV'], (bool) $_SERVER['APP_DEBUG']); $request = Request::createFromGlobals(); $response = $kernel->handle($request); $response->send(); $kernel->terminate($request, $response);
  62. Class Loading Debugger use Symfony\Component\ErrorHandler\DebugClassLoader; DebugClassLoader::enable();

  63. Turning PHP Errors into Exeptions use Symfony\Component\ErrorHandler\ErrorHandler; ErrorHandler::register();

  64. Catching PHP Function Errors and turning them into Exceptions data

    = json_decode(file_get_contents($filename), true); $data['read_at'] = date($datetimeFormat); file_put_contents($filename, json_encode($data));
  65. Catching PHP Function Errors and turning them into Exceptions $content

    = @file_get_contents($filename); if (false === $content) { throw new \RuntimeException('Could not load file.'); } $data = @json_decode($content, true); if (null === $data) { throw new \RuntimeException('File does not contain valid JSON.'); } $datetime = @date($datetimeFormat); if (false === $datetime) { throw new \RuntimeException('Invalid datetime format.'); }
  66. Catching PHP Function Errors and turning them into Exceptions $content

    = ErrorHandler::call('file_get_contents', $filename);
  67. Catching PHP Function Errors and turning them into Exceptions $data

    = ErrorHandler::call(static function () use ($filename, $datetimeFormat) { // if any code executed inside this anonymous function fails, // a PHP exception will be thrown, even if the code // uses the '@' PHP silence operator $data = json_decode(file_get_contents($filename), true); $data['read_at'] = date($datetimeFormat); file_put_contents($filename, json_encode($data)); return $data; });
  68. { "title": "Not Found", "status": 404, "detail": "Sorry, the page

    you are looking for could not be found" } Error pages for non-HTML formats templates/bundles/TwigBundle/Exception/error403.json.twig Request Format JSON XML ATOM TXT RFC 7807 deprecated
  69. Deprecated error templates for non-html formats Contributed by yceruto in

    #31398 # If you were not using this option previously, set it to `null` twig: exception_controller: null # If you were using this option previously, set it to `null` # and use `framework.error_controller` instead # Before twig: exception_controller: 'App\Controller\MyExceptionController' # After twig: exception_controller: null framework: error_controller: 'App\Controller\MyExceptionController'
  70. How to customize error pages for non-HTML formats? // templates/bundles/TwigBundle/Exception/error.json.twig

    { "type": "https://example.com/error", "title": "{{ status_text }}", "status": {{ status_code }} }
  71. How to customize error pages for non-HTML formats? class ProblemJsonNormalizer

    implements NormalizerInterface { public function normalize($exception, $format = null, array $context = []) { return [ 'type' => 'https://example.com/error', 'title' => $exception->getStatusText(), 'status' => $exception->getStatusCode(), ]; } public function supportsNormalization($data, $format = null) { return 'json' === $format && $data instanceof FlattenException; } }
  72. Custom HTML error pages based on Twig keep working as

    before. templates/bundles/TwigBundle/Exception/error500.html.twig
  73. Error preview pages - # config/routes/dev/twig.yaml + # config/routes/dev/framework.yaml _errors:

    - resource: '@TwigBundle/Resources/config/routing/errors.xml' + resource: '@FrameworkBundle/Resources/config/routing/errors.xml' prefix: /_error The error page preview feature keeps working as before, but some files have changed their location.
  74. Notifier Component Symfony 5.0 experimental https://www.meetup.com/de-DE/sfughh/events/xqdjjrybcdbgb/

  75. String Component Symfony 5.0 experimental https://www.meetup.com/de-DE/sfughh/events/xqdjjrybcdbgb/

  76. Questions?

  77. None
  78. Thank you! https://speakerdeck.com/jschaedl