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

[SymfonyCon Berlin] A year of Symfony

[SymfonyCon Berlin] A year of Symfony

Last year, Symfony 3 was out right before the SymfonyCon. A lot happened! 52 blog posts to help you keep up with all new things, 1200+ pull requests, 2 new versions out… Well I'm sure you missed something. Let's review what happened during last year: basically we'll see and/or discover nice new features that appeared since the last SymfonyCon.

Avatar for Sarah KHALIL

Sarah KHALIL

December 03, 2016
Tweet

More Decks by Sarah KHALIL

Other Decks in Technology

Transcript

  1. 57 versions 2.6.x 1 version 2.7.x 14 versions 2.8.x 14

    versions 3.0.x 9 versions 3.1.x 10 versions 3.2.x 4 versions ➡ ➡ ➡ ➡ ➡ ➡ Releases
  2. New way of releasing Symfony • A new minor version

    every 6 months • in november and may, usually at the end of the month • A new major version every 2 years • released at the same time as the last minor version
  3. Getting started: all basics about developing apps with Symfony. Components:

    all about the standalone Symfony libraries. Bundles: commonly used bundles when developing Symfony apps. Reference: Form types, DI tags & Symfony configuration.
  4. Getting started: all basics about developing apps with Symfony. Guides

    and tutorials: Everything else. Components: all about the standalone Symfony libraries. Bundles: commonly used bundles when developing Symfony apps. Reference: Form types, DI tags & Symfony configuration.
  5. Deprecation helper improvements Detection of deprecation are done thanks to

    the PHPUnit bridge. <!-- phpunit.xml --> <phpunit> <!-- ... --> <php> <server name="KERNEL_DIR" value="app/" /> <env name="SYMFONY_DEPRECATIONS_HELPER" value="disabled" /> </php> </phpunit> … 3.1
  6. « disabled » PHPUnit won’t list the deprecations ; avoid

    your test suite failing. Deprecation helper improvements Detection of deprecation are done thanks to the PHPUnit bridge. <!-- phpunit.xml --> <phpunit> <!-- ... --> <php> <server name="KERNEL_DIR" value="app/" /> <env name="SYMFONY_DEPRECATIONS_HELPER" value="disabled" /> </php> </phpunit> … 3.1
  7. « /Passing callable strings .*/ » Will be matched as

    a regular expression against the deprecation message. « disabled » PHPUnit won’t list the deprecations ; avoid your test suite failing. Deprecation helper improvements Detection of deprecation are done thanks to the PHPUnit bridge. <!-- phpunit.xml --> <phpunit> <!-- ... --> <php> <server name="KERNEL_DIR" value="app/" /> <env name="SYMFONY_DEPRECATIONS_HELPER" value="disabled" /> </php> </phpunit> … 3.1
  8. « 10 » Test suite will fail if 10 or

    more deprecations are triggered. « /Passing callable strings .*/ » Will be matched as a regular expression against the deprecation message. « disabled » PHPUnit won’t list the deprecations ; avoid your test suite failing. Deprecation helper improvements Detection of deprecation are done thanks to the PHPUnit bridge. <!-- phpunit.xml --> <phpunit> <!-- ... --> <php> <server name="KERNEL_DIR" value="app/" /> <env name="SYMFONY_DEPRECATIONS_HELPER" value="disabled" /> </php> </phpunit> … 3.1
  9. • Implementation of the PSR-6 - Caching interface standard. •

    Cache arbitrary content in your application. • Symfony components use it to improve their performances. New component: Cache 3.1 class BlogController extends Controller { public function indexAction() { // create a new item and getting it from the cache $cachedCategories = $this->get('cache.app')->getItem('categories'); if (!$cachedCategories->isHit()) { $categories = ... // fetch categories from the database $cachedCategories->set($categories); $this->get('cache.app')->save($cachedCategories); } else { $categories = $cachedCategories->get(); } // ... } } Adapters for common backends Redis, APCu, Memcache…
  10. • Implementation of the PSR-6 - Caching interface standard. •

    Cache arbitrary content in your application. • Symfony components use it to improve their performances. New component: Cache 3.1 class BlogController extends Controller { public function indexAction() { // create a new item and getting it from the cache $cachedCategories = $this->get('cache.app')->getItem('categories'); if (!$cachedCategories->isHit()) { $categories = ... // fetch categories from the database $cachedCategories->set($categories); $this->get('cache.app')->save($cachedCategories); } else { $categories = $cachedCategories->get(); } // ... } } Adapters for common backends Redis, APCu, Memcache…
  11. YAML deprecation 3.1 framework: secret: %secret% framework: secret: '%secret%' parameters:

    my_object: '!php/object:O:27:"AppBundle\Service\MyService":1:{s:1:"b";s:3:"foo";}' parameters: my_object: '!!php/object:O:27:"AppBundle\Service\MyService":1:{s:1:"b";s:3:"foo";}'
  12. Process: Input stream 3.1 use Symfony\Component\Process\Process; $process = new Process('cat');

    $process->setInput('file.txt'); $process->run(); use Symfony\Component\Process\InputStream; $input = new InputStream(); $input->write('foo'); $process = new Process('my_script'); $process->setInput($input); $process-> start(); // ... read process output or do other things $input->write('bar'); // ... read process output or do other things $input->write('qux'); $input-> close(); before Cannot provide more input now
  13. Process: Output stream 3.1 Process::OUT Process::ERR or use Symfony\Component\Process\Process; $process

    = new Process('ls -lsa'); $process->start(); foreach ($process as $type => $data) { if ($process::OUT === $type) { echo $data."\n"; } else { echo "[ERR] ".$data."\n"; } } returns an iterator
  14. Process: Output stream 3.1 Process::OUT Process::ERR or use Symfony\Component\Process\Process; $process

    = new Process('ls -lsa'); $process->start(); foreach ($process as $type => $data) { if ($process::OUT === $type) { echo $data."\n"; } else { echo "[ERR] ".$data."\n"; } } returns an iterator
  15. 3.2

  16. use Symfony\Bundle\FrameworkBundle\Controller\Controller; class DefaultController extends Controller { public function downloadAction()

    { $pdfPath = $this->getParameter('dir.downloads').'/my_file.pdf'; return $this->file($pdfPath, ‘my_new_filename.pdf’, ResponseHeaderBag::DISPOSITION_INLINE); } } New file method helper protected function file($file, $fileName = null, $disposition = ResponseHeaderBag::DISPOSITION_ATTACHMENT) 3.2
  17. YAML supports PHP constants parameters: # this is considered a

    regular string foo: PHP_INT_MAX # this is considered a PHP constant bar: !php/const:PHP_INT_MAX 3.2
  18. Compiler pass improvements 1/2 // in compiler pass before 3.2

    $warmers = array(); foreach ($container->findTaggedServiceIds('kernel.cache_warmer') as $id => $attributes) { $priority = isset($attributes[0]['priority']) ? $attributes[0]['priority'] : 0; $warmers[$priority][] = new Reference($id); } krsort($warmers); $warmers = call_user_func_array('array_merge', $warmers); // since 3.2 $warmers = $this->findAndSortTaggedServices('kernel.cache_warmer', $container); 3.2
  19. New form type: DateInterval 3.2 ->add('remindEvery', DateIntervalType::class, array( 'placeholder' =>

    array('years' => 'Years', 'months' => 'Months', 'days' => 'Days'), 'widget' => 'choice', // customize which text boxes are shown 'with_years' => true, 'with_months' => true, 'with_days' => true, 'with_hours' => false, ))
  20. Tagged cache $cache = new FilesystemAdapter(); $review = $cache->getItem('reviews-'.$reviewId); $review->set('...');

    $review->tag(['reviews', 'products', 'product-'.$productId]); $cache->save($review); //… // the HTML structure of reviews has changed: // invalidate all reviews $cache->invalidateTags('reviews'); // instead of $cache->deleteItem('reviews-'.$reviewId); 3.2
  21. Routing improvement 3.2 // generating a URL with a fragment

    $this->get('router')->generate('user_settings', ['_fragment' => 'password']); /settings#password // route definition /** * @Route("/settings", defaults={"_fragment" = "password"}, name="user_settings") */ public function settingsAction() { ... }
  22. YAML deprecations • No more duplicated keys otherwise you’ll get

    a ParseException 3.2 parameters: foo: bar parameters: key: 'aaa' # ... key: 'bbb' • Always put a space after colon otherwise you’ll get a ParseException
  23. Runtime Environment variable What’s new? • No longer obliged to

    prefix them by SYMFONY__ • The value is resolved at runtime! (the app has the updated value) 3.2 doctrine: dbal: # ... password: "%env(DB_PASSWORD)%" To set default value and avoid not set env variable: parameters: env(DB_PASSWORD): s3cr3t_p4ssw0rd
  24. Console improvements 3.2 $output->writeln('<fg=green;options=bold,underscore>Test</>'); Multiple text style options Hidden commands

    namespace AppBundle\Command; use Symfony\Component\Console\Command\Command; class FooCommand extends Command { protected function configure() { $this ->setName('app:foo') // ... ->setHidden(true) ; } }
  25. Serializer: CSV encoder 3.2 // instantiation, when using it inside

    the Symfony framework $serializer = $container->get('serializer'); $data = [ 'foo' => 'aaa', 'bar' => [ ['id' => 111, 1 => 'bbb'], ['lorem' => 'ipsum'], ] ]; file_put_contents( 'data.csv', $container->get('serializer')->encode($data, 'csv') ); // decoding CSV contents $data = $serializer->decode(file_get_contents('data.csv'), 'csv');
  26. Serializer: YAML encoder 3.2 $obj = new \stdClass(); $obj->bar =

    2; $data = $this->container->get('serializer')->encode( ['foo' => $obj], 'yaml' // these are the default values applied by the encoder ['yaml_inline' => 1, 'yaml_indent' => 4, 'yaml_flags' => 0] ); // $data = ' foo: !php/object:O:8:\"stdClass\":1:{s:3:\"bar\";i:2;}\n'; $data = $this->container->get('serializer')->decode( 'foo: !php/object:O:8:"stdClass":1:{s:3:"bar";i:2;}', 'yaml' ); // $data = ['foo' => $obj];
  27. Translation improvements // Before $this->get('translator') ->transChoice('1 apple|%count% apples', 7, ['%count%'

    => 7]); // After $this->get('translator') ->transChoice('1 apple|%count% apples', 7); 3.2 ./bin/console translation:update en --force --domain=admin
  28. Unicode routing support UTF-8 characters in route paths and requirements

    /** * @Route( * "/category/{name}", * "requirements" = { "name": "䴰ᬨ|بيحرت" } * "options" = { "utf8": true } * ) */ public function categoryAction($name) { // ... } /category/䴰ᬨ, /category/بيحرت 3.2
  29. Unicode routing support UTF-8 characters in route paths and requirements

    /** * @Route( * "/category/{name}", * "requirements" = { "name": "䴰ᬨ|بيحرت" } * "options" = { "utf8": true } * ) */ public function categoryAction($name) { // ... } /category/䴰ᬨ, /category/بيحرت not needed before 4.0 is able to detect UTF-8 3.2
  30. • Implementation of the petri net (Transitions, places…) • Supports

    state machine New component: Workflow https://speakerdeck.com/lyrixx/le-reveil-du-workflow 3.2
  31. • Implementation of the petri net (Transitions, places…) • Supports

    state machine New component: Workflow https://speakerdeck.com/lyrixx/le-reveil-du-workflow https://speakerdeck.com/tucksaun/symfonylive-london-2016-the-workflow-awakens 3.2
  32. • Implementation of the petri net (Transitions, places…) • Supports

    state machine New component: Workflow https://speakerdeck.com/lyrixx/le-reveil-du-workflow https://speakerdeck.com/tucksaun/symfonylive-london-2016-the-workflow-awakens https://speakerdeck.com/saro0h/openclassrooms-workflow-component 3.2
  33. Better support for one command applications 3.2 use Symfony\Component\Console\Application; $command

    = new \FooCommand(); $application = new Application(); $application->add($command); // the second boolean argument tells if this is a single-command app $application->setDefaultCommand($command->getName(), true); // this now executes the 'FooCommand' without passing its name $application->run();
  34. Simpler command testing 3.2 use Symfony\Component\Console\Tester\CommandTester; $commandTester = new CommandTester($command);

    $helper = $command->getHelper('question'); $helper->setInputStream($this->getInputStream("123\nfoo\nbar\n")); protected function getInputStream($input) { $stream = fopen('php://memory', 'r+', false); fputs($stream, $input); rewind($stream); return $stream; } use Symfony\Component\Console\Tester\CommandTester; $commandTester = new CommandTester($command); $commandTester->setInputs(['123', 'foo', 'bar']);