[SymfonyLive Paris] Quoi de neuf depuis 1 an ?

[SymfonyLive Paris] Quoi de neuf depuis 1 an ?

Il y a un peu plus d'un an, en novembre 2015 la version 3.0 est sortie. Beaucoup de choses se sont passées depuis ! 71 blog posts pour vous tenir au courant de toutes les nouveautés, plus de 1300 pull requests, 2 nouvelles versions… Je suis sûre que vous avez dû manquer un petit quelque chose ! Nous allons revoir ensemble ce qui est arrivé ; passer en revue les fonctionnalités que vous auriez râtées ou les redécouvrir.

34ade09dd3d11004ca8ee4174fd3d6a2?s=128

Sarah KHALIL

March 31, 2017
Tweet

Transcript

  1. 2.
  2. 3.
  3. 4.

    Oh nice, ça fait belle lurette que je mate plus

    trop le blog sur symfony.com Pinaise j’vais enfin pouvoir marquer comme lues toutes mes notifs Github !
  4. 7.
  5. 8.
  6. 9.

    • 4 nouvelles versions mineures : 3.0, 3.1, 3.2 et

    et et 3.3 • Une pelleté de releases : ± 70 versions 1 928 mergées 3455 ouvertes
  7. 10.

    • 4 nouvelles versions mineures : 3.0, 3.1, 3.2 et

    et et 3.3 • Une pelleté de releases : ± 70 versions 1 928 mergées 3455 ouvertes
  8. 11.
  9. 12.
  10. 13.
  11. 14.
  12. 15.
  13. 19.
  14. 20.
  15. 23.

    On en a fini avec SYMFONY__ • SYMFONY__ ne sera

    plus interprété en version 4.x • Il faut utiliser : %env()% (à partir de 3.2.x) # app/config/parameters.yml parameters: database_host: '%env(DATABASE_HOST)%' env(DATABASE_HOST): localhost
  16. 24.

    On en a fini avec SYMFONY__ • SYMFONY__ ne sera

    plus interprété en version 4.x • Il faut utiliser : %env()% (à partir de 3.2.x) # app/config/parameters.yml parameters: database_host: '%env(DATABASE_HOST)%' env(DATABASE_HOST): localhost Valeur par défaut
  17. 25.

    cache:clear avec warmup • Version 4 : Faire en sorte

    qu’il soit possible de générer le cache complet pour exécuter l’application sur un système « read-only ». • Le warmup exécuté au moment du cache clear n’est pas aussi fiable que la commande cache:warmup.
  18. 26.

    cache:clear avec warmup • Version 4 : Faire en sorte

    qu’il soit possible de générer le cache complet pour exécuter l’application sur un système « read-only ». • Le warmup exécuté au moment du cache clear n’est pas aussi fiable que la commande cache:warmup. $ ./bin/console cache:clear (--env=prod|dev) Avant
  19. 27.

    cache:clear avec warmup • Version 4 : Faire en sorte

    qu’il soit possible de générer le cache complet pour exécuter l’application sur un système « read-only ». • Le warmup exécuté au moment du cache clear n’est pas aussi fiable que la commande cache:warmup. $ ./bin/console cache:clear (--env=prod|dev) Avant $ ./bin/console cache:clear --no-warmup (--env=prod|dev) $ ./bin/console cache:warmup (--env=prod|dev) Après
  20. 28.

    Console.EXCEPTION • console.EXCEPTION : exception lancée dans Command::execute(). • Pour

    le reste, tout est traité dans un bloc try catch dans la méthode Command::doRunCommand(). • Impossible d’overrider la manière de gérer les exceptions dans ces cas là. • Désormais, un nouvel évènement est lancé, console.ERROR après ce try catch.
  21. 30.

    X-Status-Code use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent; use Symfony\Component\HttpFoundation\Response; public function onKernelException(GetResponseForExceptionEvent $event) {

    $exception = $event->getException(); // 500 is the original status code; but the end user will get a 404 $response = new Response('...', 500, ['X-Status-Code' => 404]); // ... $event->setResponse($response); } Avant
  22. 31.

    X-Status-Code use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent; use Symfony\Component\HttpFoundation\Response; public function onKernelException(GetResponseForExceptionEvent $event) {

    $exception = $event->getException(); // 500 is the original status code; but the end user will get a 404 $response = new Response('...', 500, ['X-Status-Code' => 404]); // ... $event->setResponse($response); } Avant use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent; use Symfony\Component\HttpFoundation\Response; public function onKernelException(GetResponseForExceptionEvent $event) { $exception = $event->getException(); $response = new Response('...', 404); // ... $event->allowCustomResponseCode(); $event->setResponse($response); } Après
  23. 32.

    Composant ClassLoader • Composer a pris le relais ! •

    Si vous utilisez PHP 7 (et la version 3.3), vous pouvez dores et déjà tester en supprimant la ligne dans votre front controller. $kernel->loadClassCache();
  24. 34.

    Autowiring services: rot13_transformer: class: AppBundle\Rot13Transformer twitter_client: class: AppBundle\TwitterClient autowire: true

    namespace AppBundle; class Rot13Transformer implements TransformerInterface { // … } namespace AppBundle; class TwitterClient { private $transformer; public function __construct(TransformerInterface $transformer) { $this->transformer = $transformer; } // … }
  25. 35.

    %

  26. 36.
  27. 37.

    services: rot13_transformer: class: AppBundle\Rot13Transformer another_transformer: class: AppBundle\AnotherTransformer autowiring_types: AppBundle\TransformerInterface twitter_client:

    class: AppBundle\TwitterClient autowire: true namespace AppBundle; class Rot13Transformer implements TransformerInterface { // … } namespace AppBundle; class TwitterClient { private $transformer; public function __construct(TransformerInterface $transformer) { $this->transformer = $transformer; } // … } namespace AppBundle; class AnotherTransformer implements TransformerInterface { // … } Autowiring
  28. 38.

    services: rot13_transformer: class: AppBundle\Rot13Transformer another_transformer: class: AppBundle\AnotherTransformer autowiring_types: AppBundle\TransformerInterface twitter_client:

    class: AppBundle\TwitterClient autowire: true namespace AppBundle; class Rot13Transformer implements TransformerInterface { // … } namespace AppBundle; class TwitterClient { private $transformer; public function __construct(TransformerInterface $transformer) { $this->transformer = $transformer; } // … } namespace AppBundle; class AnotherTransformer implements TransformerInterface { // … } Autowiring Implémentation par défaut
  29. 41.

    autowiring-types services: rot13_transformer: class: AppBundle\Rot13Transformer another_transformer: class: AppBundle\AnotherTransformer autowiring_types: AppBundle\TransformerInterface

    twitter_client: class: AppBundle\TwitterClient autowire: true Avant services: rot13_transformer: class: AppBundle\Rot13Transformer another_transformer: class: AppBundle\AnotherTransformer alias: rot13_transformer public: false twitter_client: class: AppBundle\TwitterClient autowire: true Après
  30. 42.

    autowiring-types Implémentation par défaut services: rot13_transformer: class: AppBundle\Rot13Transformer another_transformer: class:

    AppBundle\AnotherTransformer autowiring_types: AppBundle\TransformerInterface twitter_client: class: AppBundle\TwitterClient autowire: true Avant services: rot13_transformer: class: AppBundle\Rot13Transformer another_transformer: class: AppBundle\AnotherTransformer alias: rot13_transformer public: false twitter_client: class: AppBundle\TwitterClient autowire: true Après
  31. 43.

    Insensibilité à la casse des identifiants de services services: MyService:

    class: AppBundle\RandomClass services: myService: class: AppBundle\AnotherClass ≠
  32. 46.
  33. 47.
  34. 48.

    Récupérer les flash messages plus facilement (1/3) {% if app.session

    is not null and app.session.started %} {% for label, messages in app.session.flashbag.all %} {% for message in messages %} <div class="alert alert-{{ label }}"> {{ message }} </div> {% endfor %} {% endfor %} {% endif %} {% for label, messages in app.flashes %} {% for message in messages %} <div class="alert alert-{{ label }}"> {{ message }} </div> {% endfor %} {% endfor %} Avant Après 1/20
  35. 49.

    {% if app.session is not null and app.session.started %} {%

    for message in app.session.flashbag.get('notice') %} <div class="alert alert-notice"> {{ message }} </div> {% endfor %} {% endif %} {% for message in app.flashes('notice') %} <div class="alert alert-notice"> {{ message }} </div> {% endfor %} Avant Après Récupérer les flash messages plus facilement (2/3) 1/20
  36. 50.

    {% for label, messages in app.flashes(['warning', 'error']) %} {% for

    message in messages %} <div class="alert alert-{{ label }}"> {{ message }} </div> {% endfor %} {% endfor %} Récupérer les flash messages plus facilement (3/3) 1/20
  37. 51.

    Le username des utilisateurs in memory ne sont plus normalisés

    Avant foo-bar@gmail.com devenait foo_bar@gmail.com Après foo-bar@gmail.com reste foo-bar@gmail.com 2/20
  38. 52.

    Symfony\Bundle\FrameworkBundle\Controller\Controller • On encourage à utiliser le Symfony\Bundle\FrameworkBundle\Controller\AbstractController. • Fournit

    les même helpers que le Controller, mais ne donne plus accès au container via la méthode get(). • Encourager la déclaration explicite des dépendances dans son Controller. 3/20
  39. 53.

    Workflow : Guard expression transitions: journalist_approval: guard: "is_fully_authenticated() and has_role('ROLE_JOURNALIST')

    or is_granted('POST_EDIT', subject)" from: wait_for_journalist to: approved_by_journalist publish: guard: "subject.isPublic()" from: approved_by_journalist to: published 4/20
  40. 57.

    Plus besoin d’activer les bundles un à un Le but

    : installer les bundles / composants dont on a besoin. 8/20
  41. 58.

    Plus besoin d’activer les bundles un à un Le but

    : installer les bundles / composants dont on a besoin. Avant 1. Tout est là (composants/bundles) 2. Activer les fonctionnalités un à un en config 8/20
  42. 59.

    Plus besoin d’activer les bundles un à un Le but

    : installer les bundles / composants dont on a besoin. Avant 1. Tout est là (composants/bundles) 2. Activer les fonctionnalités un à un en config Installer ce dont on a besoin Après 8/20
  43. 60.

    Plus besoin d’activer les bundles un à un Le but

    : installer les bundles / composants dont on a besoin. Avant 1. Tout est là (composants/bundles) 2. Activer les fonctionnalités un à un en config Installer ce dont on a besoin Après NB : Une nouvelle classe Symfony\Bundle\Fullstack pour vérifier si tout symfony est installé (plutôt que le mode composant par composant) 8/20
  44. 62.

    use Symfony\Component\Cache\Adapter\FilesystemAdapter; $cache = new FilesystemAdapter(); // sauvegarder un élément

    en cache $numProducts = $cache->getItem('stats.num_products'); $numProducts->set(4711); $cache->save($numProducts); // sauvegarder un élément en cache $cache->set('stats.num_products', 4711); Avant Après simple cache 9/20 Implémentation de la PSR-16 (1/2)
  45. 63.

    use Symfony\Component\Cache\Adapter\FilesystemAdapter; $cache = new FilesystemAdapter(); // sauvegarder un élément

    en cache $numProducts = $cache->getItem('stats.num_products'); $numProducts->set(4711); $cache->save($numProducts); // sauvegarder un élément en cache $cache->set('stats.num_products', 4711); Avant Après // récupérer un élément du cache $numProducts = $cache->getItem('stats.num_products'); if (!$numProducts->isHit()) { // ... item does not exist in the cache } else { $total = $numProducts->get(); } // récupérer un élément du cache if (!$cache->has('stats.num_products')) { // ... item does not exist in the cache } else { $total = $cache->get('stats.num_products'); } simple cache 9/20 Implémentation de la PSR-16 (1/2)
  46. 64.

    use Symfony\Component\Cache\Adapter\FilesystemAdapter; $cache = new FilesystemAdapter(); // sauvegarder un élément

    en cache $numProducts = $cache->getItem('stats.num_products'); $numProducts->set(4711); $cache->save($numProducts); // sauvegarder un élément en cache $cache->set('stats.num_products', 4711); Avant Après // récupérer un élément du cache $numProducts = $cache->getItem('stats.num_products'); if (!$numProducts->isHit()) { // ... item does not exist in the cache } else { $total = $numProducts->get(); } // récupérer un élément du cache if (!$cache->has('stats.num_products')) { // ... item does not exist in the cache } else { $total = $cache->get('stats.num_products'); } // supprimer un élément du cache $cache->deleteItem('stats.num_products'); // supprimer un élément du cache $cache->delete('stats.num_products'); simple cache 9/20 Implémentation de la PSR-16 (1/2)
  47. 67.

    Log automatique des erreurs console • Le listener se repose

    sur le standard PSR-3 pour la sortie. • Il suffit de configurer monolog pour adapter la sortie. 11/20
  48. 69.

    FQCN comme id de service services: app.manager.user: class: AppBundle\EventListener\UserManager tags:

    ['kernel.event_subscriber'] services: AppBundle\EventListener\UserManager: tags: ['kernel.event_subscriber'] use AppBundle\EventListener\UserManager; // ... public function editAction() { $this->get(UserManager::class)->save($user); } Avant Après use AppBundle\EventListener\UserManager; // ... public function editAction() { $this->get('app.manager.user')->save($user); } 12/20
  49. 70.

    La vie sans bundle Kernel::build() Enregistrer de la configuration Enregistrer

    les compiler pass Plus besoin d’enregistrer une classe de bundle 13/20
  50. 71.

    Importer un ensemble de fichiers de configuration imports: - {

    resource: "*.yml" } - { resource: "common/**/*.xml" } - { resource: "/etc/myapp/*.{yml,xml}" } - { resource: "bundles/*/{xml,yaml}/services.{yml,xml}" } glob pattern 14/20
  51. 72.

    Arguments nommés use Doctrine\ORM\EntityManager; use Psr\Log\LoggerInterface; namespace Acme; class NewsletterManager

    { private $logger; private $apiKey; public function __construct(LoggerInterface $logger, $apiKey) { $this->logger = $logger; $this->apiKey = $apiKey; } } services: newsletter_manager: class: Acme\NewsletterManager arguments: $apiKey: "%mandrill_api_key%" autowire: true 15/20
  52. 76.

    Implémentation de la PSR-11 Symfony\Component\DependencyInjection\ContainerInterface étend la Psr\Container\ContainerInterface get() &

    has() 2 nouvelles Exceptions : ContainerExceptionInterface & NotFoundExceptionInterface 16/20
  53. 77.

    Déclaration de service : Configuration par défaut pour tout un

    fichier services: _defaults: public: false autowire: true foo: class: Foo 17/20
  54. 78.

    Remplacement des wildcards pour les méthodes lors de l’autowiring services:

    _defaults: public: false autowire: ['set*'] foo: class: Foo Avant Après services: _defaults: public: false autowire: true foo: class: Foo Et class Foo { //… /** * @required */ public function setBar(Bar $bar) { // devrait être appelé } } https://github.com/symfony/symfony/pull/21763 bonus
  55. 84.
  56. 86.

    Composant Lock Gestion avancée du lock dans de nombreux systèmes

    (fichiers, redis, memcache). Ping Fabien Bourigault !
  57. 87.

    Composant Lock Gestion avancée du lock dans de nombreux systèmes

    (fichiers, redis, memcache). Ping Fabien Bourigault !
  58. 88.

    Composant Dotenv • On se doute un peu de ce

    qu’il fait ;) • « Superb error messages to easily spot any issue »
  59. 91.

    Symfony Demo 1.0.0 • Référence en matière de bonnes pratiques

    • Fork pour reproduire les bugs • Benchmark de performances • Montrer ce qui est possible avec http://symfony.com/blog/symfony-demo-1-0-0-released
  60. 92.

    Introduction des features expérimentales • Pour assurer la rétrocompatibilité (BC

    break promise) • Certaines features • @experimental http://symfony.com/blog/experimental-features
  61. 97.
  62. 102.