Symfony4 Deep Dive

Symfony4 Deep Dive

B50a40d1c576ef0aa065cbc5d4d6dec9?s=128

Christian Flothmann

October 27, 2017
Tweet

Transcript

  1. Symfony4 Deep Dive SensioLabs

  2. License Symfony4 Deep Dive Copyright © 2017 SensioLabs – All

    Rights Reserved Contents are provided for strictly personal use. No part of these contents may be reproduced, stored in a retrieval system, publicly shared or transmitted in any form or by any means. Disclaimer Contents are distributed on an "as is" basis, without warranty. Although every precaution has been taken in the preparation of this work, neither the authors nor SensioLabs shall have any liability to any person or entity with respect to any loss or damage caused or alleged to be caused directly or indirectly by the information contained in this work.
  3. • SSID: GT Conference • Username: SymfonyLive • Password: Berlin2017

    Wifi
  4. SensioLabs Introduction

  5. The Symfony Release Cycle

  6. We are here

  7. • LTS release (3 years of support) • Symfony 3.3

    + additional features + additional deprecations • release: November 2017 Symfony 3.4
  8. • standard release (8 months of support) • Symfony 3.3

    + additional features - deprecated features • release: November 2017 Symfony 4.0
  9. Version Release date End of Maintenance End of Life 2.8

    LTS 11/2015 11/2018 11/2019 3.3 05/2017 01/2018 07/2018 3.4 LTS 11/2017 11/2020 11/2021
  10. Version Release date End of Maintenance End of Life 2.8

    LTS 11/2015 11/2018 11/2019 3.3 05/2017 01/2018 07/2018 4.0 11/2017 07/2018 01/2019
  11. The Symfony Standard Edition

  12. Symfony 2.x/3.x applications were based on the Symfony Standard Edition.

    The Symfony SE is shipped with all Symfony components and different bundles. The Symfony Standard Edition
  13. It ships with code that isn‘t used in all individual

    projects. The Symfony SE is often perceived as being „big“. Removing not needed functionality is a cumbersome task. The Symfony Standard Edition
  14. Symfony Flex

  15. • Flex prefers composition over inheritance. • New project start

    with almost no dependencies. • Only needed features are added by developers. What is Symfony Flex?
  16. • hooks into the Composer workflow • automatically enables Symfony

    bundles • executes predefined recipes when packages are installed • recipes are removed when packages are uninstalled What is Symfony Flex?
  17. Bootstrapping a Symfony application

  18. Using Composer composer create-project \ symfony/framework- standard-edition:3.3.* \ my-app

  19. Using the Symfony Installer symfony new my-app 3.3

  20. Bootstrapping an application using Flex composer create-project \ symfony/skeleton my-app

  21. Initial project size in comparison Symfony 3 Symfony 4

  22. Symfony 3 Symfony 4 Basic directory structure in comparison

  23. Hands on: User Group Radar

  24. Initialize the project composer create-project \ symfony/skeleton:^3.4@beta \ meetup

  25. https://goo.gl/PVGrzA Download example code

  26. Recipes

  27. • The Symfony SE came with ready-to-use bundles and a

    sensible default config. • Adding new components/bundles and configuring them can be a complicated task. • Flex will automatically enable a bundle in all environments. How to add functions to a Flex project?
  28. • description of things to apply when a package is

    installed • maintained by the core team • stored in the symfony/recipes repository • automatically applied when the package is installed What is a recipe?
  29. None
  30. • automatically enable a bundle in some/all environments • provide

    a reasonable default config • set some environment variables • copy files and create directories A recipe can
  31. Applying a recipe during installation $ composer require symfony/console Using

    version ^3.3 for symfony/console ./composer.json has been updated Loading composer repositories with package information Updating dependencies (including require-dev) Package operations: 1 install, 0 updates, 0 removals - Installing symfony/console (v3.3.10): Downloading (100%) Writing lock file Generating autoload files Symfony operations: 1 recipe - Configuring symfony/console (3.3): From github.com/symfony/recipes:master Executing script make cache-warmup [OK] Executing script assets:install --symlink --relative public [OK]
  32. Applying a recipe during installation $ composer require symfony/console Using

    version ^3.3 for symfony/console ./composer.json has been updated Loading composer repositories with package information Updating dependencies (including require-dev) Package operations: 1 install, 0 updates, 0 removals - Installing symfony/console (v3.3.10): Downloading (100%) Writing lock file Generating autoload files Symfony operations: 1 recipe - Configuring symfony/console (3.3): From github.com/symfony/recipes:master Executing script make cache-warmup [OK] Executing script assets:install --symlink --relative public [OK]
  33. Applying a recipe during installation $ composer require symfony/console Using

    version ^3.3 for symfony/console ./composer.json has been updated Loading composer repositories with package information Updating dependencies (including require-dev) Package operations: 1 install, 0 updates, 0 removals - Installing symfony/console (v3.3.10): Downloading (100%) Writing lock file Generating autoload files Symfony operations: 1 recipe - Configuring symfony/console (3.3): From github.com/symfony/recipes:master Executing script make cache-warmup [OK] Executing script assets:install --symlink --relative public [OK]
  34. Aliases

  35. For common problems, Flex decides which is the best package

    to use. Use the alias to let Flex make the choice for you (e.g. admin, orm, etc.). Alternatives can still be installed using their full package name. Flex makes choices for you
  36. Aliases allow to reference packages from the Symfony namespace by

    their base name. Instead of symfony/foo you can just use foo (e.g. form instead of symfony/form). Aliases for Symfony components
  37. Packs

  38. What is a pack? Packs are groups of several packages

    which all contribute to solve common problems. Developers only need to install one package instead of lots of packages.
  39. • Groups packages that are useful during development: • logging

    (Monolog) • profiling (WebProfilerBundle) • testing (PhpUnitBridge) Example: The debug pack
  40. • symfony/monolog-bundle • easycorp/easy-log-handler • symfony/profiler-pack • symfony/phpunit-bridge • symfony/var-dumper

    Example: The debug pack
  41. • debug-pack • profiler-pack • orm-pack • webpack-encore-pack • api-pack

    Popular packs
  42. Contrib recipes

  43. • the core recipes repository is restricted to a limited

    set of packages • maintainers of other bundles cannot add their own recipes • the selection is opionated and the choice is made by the core team • only for MIT licensed packages Limitation of core recipes
  44. • are maintained by the community • can be created

    for MIT and Apache licensed packages • are not enabled by default Contrib recipes
  45. Activating contrib recipes in composer.json { "extra": { "symfony": {

    "id": "01BX217DNRHSWETJFT83M3XDE9", "allow-contrib": false } } }
  46. Activating contrib recipes in composer.json { "extra": { "symfony": {

    "id": "01BX217DNRHSWETJFT83M3XDE9", "allow-contrib": false } } }
  47. Activating contrib recipes in composer.json { "extra": { "symfony": {

    "id": "01BX217DNRHSWETJFT83M3XDE9", "allow-contrib": true } } }
  48. Interactive activation

  49. SensioLabs

  50. SensioLabs Improved Dependency Injection

  51. • will be applied to all services configured in the

    same file • can be overriden per service Default options per file services: _defaults: autowire: true autoconfigure: true public: false
  52. Autoconfiguration based on types Definitions can be modified based on

    parent classes/implemented interfaces. For example, bundles can add tags to definitions based on implemented interfaces.
  53. • the class attribute is optional • if omitted, the

    id will be treated as the FQCN Class based service ids services: AppBundle\Service\ExampleService: ~ # is equivalent to AppBundle\Service\ExampleService: class: AppBundle\Service\ExampleService
  54. • collects PHP classes based on glob patterns and PSR-4-compatible

    namespaces • some files/directories can be excluded PSR-4 based service configuration
  55. PSR-4 based service configuration services: App\: resource: '../src/*' # you

    can exclude directories or files # but if a service is unused, it's removed anyway #exclude: '../src/{Entity,Migrations,Repository,Tests}' exclude: '../src/{Entity}' # refine service definitions AppBundle\Service\ExampleService: arguments: # bind arguments that cannot be autowired $someArgument: 'some_value'
  56. Environment variables Warming up the application cache upfront requires all

    container parameters to be set. Some cloud hosting providers do not make these credentials available. Env var placeholders allow to inject and replace options at runtime.
  57. Usage of environment variables # defining default values for env

    var placeholders parameters: env(DB): 'sqlite://../../var/data.db' doctrine: dbal: url: '%env(DB)%'
  58. • strings may break type hints (e.g. a port number

    is expected to be an integer in PHP code) • to pass structured data (e.g. arrays) you need more env vars • reading from files for security reasons not possible Non-string environment variables
  59. • „bool:“, „int:“, „float:“, „string:“: perform type castings • „resolve:“:

    resolves container parameters • „base64:“, „json:“: decode data • „file:“: reads data from files „const:“ parses PHP constants Supported operators
  60. Full example parameters: # roughly equivalent to # "(int) getenv('DATABASE_PORT')"

    app.connection.port: '%env(int:DATABASE_PORT)%' project_dir: '/foo/bar' env(DB): 'sqlite://%%project_dir%%/var/data.db' db_dsn: '%env(resolve:DB)%' env(SECRETS_FILE): '/etc/secure/example.com/secrets.json' app.secrets: '%env(json:file:SECRETS_FILE)%' env(NUM_ITEMS): 'App\\Entity\\BlogPost::NUM_ITEMS' app.num_items: '%env(constant:NUM_ITEMS)%'
  61. SensioLabs

  62. SensioLabs The Cache Component

  63. Compute some data structures can be a time or memory

    consuming task. However, recalculating them on every request may not always be necessary. Caches can be used to share the same result between requests to save resources. The Cache component
  64. The PHP Framework Interoperability Group develops recommendations and interfaces for

    common problems that are solved by different frameworks. Standards are published as so-called PHP Standard Recommendations (PSRs). The PHP-FIG
  65. PSR-6

  66. PSR-6 specifies a standard for a cache implementation. It describes

    interfaces that represent the cache data and its metadata as well as how to store data into and retrieve from the cache. PSR-6
  67. • encapsulates the data that should be cached • associates

    data with a key and expiration time • CacheItemInterface is specified by PSR-6 Cache items
  68. • cache pools are the gateway to write cache items

    into the cache and get them back via their key • CacheItemPoolInterface is specified by PSR-6 Cache pools
  69. • Cache adapters are Symfony‘s terminology for concrete cache backends.

    • They are never used directly be the end-user, but will only be configured once. • Developers only act with the cache through cache pools. Cache adapters
  70. • APCu • Doctrine • Filesystem • Memcached • Pdo

    • Redis Built-in adapters
  71. Configuring the default adapter framework: cache: app: cache.adapter.redis system: cache.adapter.apcu

  72. The system cache pool is used internally by Symfony to

    cache framework related fragments (e.g. the serializer and validator caches). The system cache pool
  73. The app cache pool is meant to store application related

    data. It is not used automatically by the framework. Application developers must make use of the cache.app service to store data into and retrieve data from the app cache. The app cache pool will be used for autowiring by default. The app cache pool
  74. CacheItemInterface interface CacheItemInterface { public function getKey(); public function get();

    public function isHit(); public function set($value); public function expiresAt($expiration); public function expiresAfter($time); }
  75. CacheItemPoolInterface interface CacheItemPoolInterface { public function getItem($key); public function getItems(array

    $keys = array()); public function hasItem($key); public function clear(); public function deleteItem($key); public function deleteItems(array $keys); public function save(CacheItemInterface $item); public function saveDeferred(CacheItemInterface $item); public function commit(); }
  76. Storing cache items public function computeAndCache(CacheItemPoolInterface $cache) { $item =

    $cache->getItem('cache_key'); // compute some $value $item->set($value); $cache->save($item); }
  77. Retrieve cache items public function retrieveFromCache(CacheItemPoolInterface $cache): ?Value { $item

    = $cache->getItem('cache_key'); if ($item->isHit()) { return $item->get(); } return null; }
  78. Full example public function computeAndCache(CacheItemPoolInterface $cache) { $item = $cache->getItem('cache_key');

    // return the cached value if possible if ($item->isHit()) { return $item->get(); } // compute some $value $item->set($value); $cache->save($item) ; return $value; }
  79. Custom cache pools framework: cache: pools: # the "api" cache

    pool will be # available as the cache.api service api: adapter: memcached
  80. PSR-16

  81. PSR-6 solves caching but is rather formal. It is more

    verbose than needed for many use cases. PSR-16 defines a streamlined interface for common cases. PSR-16
  82. The CacheInterface interface CacheInterface { public function get($key, $default =

    null); public function set($key, $value, $ttl = null); public function delete($key); public function clear(); public function getMultiple($keys, $default = null); public function setMultiple($values, $ttl = null); public function deleteMultiple($keys); public function has($key); }
  83. Full example public function computeAndCache(CacheInterface $cache) { if ($cache->has('cache_key')) {

    // return the cached value if possible return $cache->get('cache_key'); } // compute some $value $cache->set('cache_key', $value) ; return $value; }
  84. Wrapping a PSR-6 adapter services: api_cache: class: Symfony\Component\Cache\Simple\Psr6Cache arguments: -

    '@cache.app'
  85. SensioLabs

  86. SensioLabs The Workflow Component

  87. Introduction Workflows are processes in your application (for example, the

    publishing process of blog posts). They should be kept outside your code and be defined in your application config.
  88. Terms 1/1 • Place the states a workflow can be

    in • Transition an action that brings the workflow from one place into another
  89. Terms 2/2 • Definition the places of a workflow and

    the transitions to get from one place to another • Marking the current state of the workflow, stored in a MarkingStore
  90. Workflow configuration framework: workflows: blog_publishing: type: 'workflow’ # or ‘state_machine’

    # ...
  91. Workflow configuration framework: workflows: blog_publishing: type: 'workflow' marking_store: type: 'multiple_state'

    # or 'single_state' arguments: - 'currentPlace' # ...
  92. Workflow configuration framework: workflows: blog_publishing: type: 'workflow' marking_store: type: 'multiple_state'

    arguments: - 'currentPlace' supports: [AppBundle\Entity\BlogPost] # ...
  93. Workflow configuration framework: workflows: blog_publishing: type: 'workflow' marking_store: type: 'multiple_state'

    arguments: - 'currentPlace' supports: [AppBundle\Entity\BlogPost] places: - draft # ...
  94. Workflow configuration framework: workflows: blog_publishing: type: 'workflow' marking_store: type: 'multiple_state'

    arguments: - 'currentPlace' supports: [AppBundle\Entity\BlogPost] places: - draft # ... transitions: to_review: from: draft to: review # ...
  95. • a definition will be created for each workflow •

    a workflow can be retrieved from the service container (workflow.<name>) • the service is an instance of Workflow Workflow configuration
  96. • can() test if a transition can be applied •

    apply() applies a transition • getEnabledTransitions() returns all applyable transitions The Workflow class
  97. Applying transitions public function publishIfPossible( Article $article, Workflow $workflow )

    { if ($workflow->can($article, 'publish')) { $workflow->apply($article, 'publish'); } }
  98. • several events are triggered throughout the lifecycle of a

    workflow • listeners can access the workflow through the passed event object Workflow events
  99. • workflow.leave before a place is left • workflow.transition before

    a transition is applied • workflow.enter before a place is entered Workflow events
  100. • workflow.entered after a place has been entered • workflow.completed

    after a transition was applied • workflow.announce announces all enabled transitions Workflow events
  101. • transitions can be blocked by listeners of the workflow.guard

    event • an instance of GuardEvent will be passed • guard listeners are taken into account when can() is executed The guard event
  102. The GuardEvent class GuardEvent extends Event { private $blocked =

    false; public function isBlocked() { return $this->blocked; } public function setBlocked($blocked) { $this->blocked = (bool) $blocked; } }
  103. SensioLabs

  104. Please leave feedback https://joind.in/talk/0bb53

  105. Full code example https://github.com/sensiolabs-de/flex-meetup

  106. Phone +49 221 16 53 54 0 Email training@sensiolabs.de SensioLabs

    Training Department training.sensiolabs.com Address Balthasarstraße 79 50670 Köln Germany SensioLabs