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

Was ist neu in Symfony?

Was ist neu in Symfony?

PHP Usergroup Münster

B50a40d1c576ef0aa065cbc5d4d6dec9?s=128

Christian Flothmann

February 26, 2020
Tweet

Transcript

  1. Was ist neu in Symfony? PHP-Usergroup Münster, 26.02.2020

  2. Christian Flothmann christian.flothmann@sensiolabs.de @xabbuh @xabbuh

  3. None
  4. 4.4 Deprecations Bugfixes Bugfixes Features Features Deprecations 5.0 What are

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

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

    protected function execute(InputInterface $input, OutputInterface $output) { // ... return 0; } Console
  8. 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
  9. 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
  10. 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
  11. 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
  12. 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
  13. 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
  14. Deprecated passing arguments to Request::isMethodSafe() Contributed by dFayet in #31658

    // Symfony 4.3 $request->isMethodSafe(true); // throws BadMethodCallException $request->isMethodSafe(false); // Symfony 4.4 $request->isMethodSafe(false); // deprecated // use $request->isMethodSafe(); $request->isMethodCachable(); HttpFoundation
  15. 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
  16. 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
  17. 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
  18. Debug Component deprecated Use the new ErrorHandler Component instead!

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

    the Symfony CLI instead!
  20. Type Declarations and Return Types https://symfony.com/blog/symfony-type-declarations-return-types https://github.com/symfony/symfony/issues/32179

  21. BC-Breaks Symfony 4.4 from 4.3 to 4.4

  22. - [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)
  23. 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

  24. Features/Improvements

  25. 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
  26. 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
  27. 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
  28. 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
  29. 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
  30. 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()
  31. 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']
  32. 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
  33. 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']
  34. 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; } } }
  35. Service Container Linter DependencyInjection Contributed by alcalyn, GuilhemN and nicolas-grekas

    in #33015 $ bin/console lint:container
  36. 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: $someProperty: ~ Invalid definition for service "App\SomeNamespace\SomeService": argument 1 of "App\SomeNamespace\SomeService::__construct" accepts "int", "NULL" passed.
  37. 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'
  38. Mailer Integration Contributed by fabpot in #32912 WebProfilerBundle

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

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

  41. 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
  42. Notification Emails Contributed by fabpot in #33605 Mime

  43. 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 # ...
  44. 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); } }
  45. 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'
  46. 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

  47. New Components

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

    manage errors and ease debugging PHP code. $ composer require symfony/error-handler
  49. # 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);
  50. # 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);
  51. Class Loading Debugger use Symfony\Component\ErrorHandler\DebugClassLoader; DebugClassLoader::enable();

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

  53. 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));
  54. 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.'); }
  55. Catching PHP Function Errors and turning them into Exceptions $content

    = ErrorHandler::call('file_get_contents', $filename);
  56. 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; });
  57. { "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
  58. 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'
  59. 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 }} }
  60. 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; } }
  61. Custom HTML error pages based on Twig keep working as

    before. templates/bundles/TwigBundle/Exception/error500.html.twig
  62. 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.
  63. Notifier Component Symfony 5.0 experimental

  64. send messages via a unified API https://speakerdeck.com/fabpot/symfony-notifier

  65. String Component Symfony 5.0 experimental

  66. use function Symfony\Component\String\u; $text = u('This is a déjà-vu situation.')

    ->trimEnd('.') ->replace('déjà-vu', 'jamais-vu') ->append('!'); // $text = 'This is a jamais-vu situation!'
  67. https://speakerdeck.com/nicolasgrekas/symfony-string-flexible-handling-of-unicode

  68. Questions?

  69. Thank you! https://speakerdeck.com/xabbuh

  70. None