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

Jan Schädlich

January 06, 2020
Tweet

More Decks by Jan Schädlich

Other Decks in Programming

Transcript

  1. 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
  2. Non-int return value in Command::execute() Contributed by jschaedl in #33775

    protected function execute(InputInterface $input, OutputInterface $output) { // ... return 0; } Console
  3. 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
  4. 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
  5. 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
  6. 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
  7. 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
  8. 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
  9. 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
  10. 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
  11. 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
  12. 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
  13. 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
  14. └── 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
  15. - [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)
  16. 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
  17. 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
  18. 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
  19. 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', '[email protected]'); $this->assertEmailTextBodyContains($email, 'Welcome to Symfony!'); $this->assertEmailAttachementCount($email, 1); } } FrameworkBundle
  20. 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()
  21. 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']
  22. 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
  23. 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']
  24. 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; } } }
  25. 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.
  26. 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'
  27. Notification Emails Contributed by fabpot in #33605 use Symfony\Bridge\Twig\Mime\NotificationEmail; $email

    = (new NotificationEmail()) ->from('[email protected]') ->to('[email protected]') ->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
  28. 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 # ...
  29. 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
  30. 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); } }
  31. 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'
  32. 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 { //... } }
  33. 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 { //... } }
  34. ErrorHandler Component Symfony 4.4 The ErrorHandler component provides tools to

    manage errors and ease debugging PHP code. $ composer require symfony/error-handler
  35. # 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);
  36. # 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);
  37. 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));
  38. 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.'); }
  39. Catching PHP Function Errors and turning them into Exceptions $content

    = ErrorHandler::call('file_get_contents', $filename);
  40. 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; });
  41. { "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
  42. 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'
  43. 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 }} }
  44. 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; } }
  45. Custom HTML error pages based on Twig keep working as

    before. templates/bundles/TwigBundle/Exception/error500.html.twig
  46. 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.