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

SymfonyLive San Francisco 2015 - Overriding Symfony in a million ways

SymfonyLive San Francisco 2015 - Overriding Symfony in a million ways

During this session, we will have a look at how easy it is to override everything in a Symfony application. We'll see how the directory structure can be adapted to your needs, but more importantly, we will learn how to override any Symfony feature by writing some custom event listeners or by tweaking the Dependency Container configuration.

Sarah KHALIL

October 29, 2015
Tweet

More Decks by Sarah KHALIL

Other Decks in Technology

Transcript

  1. OVERRIDING SYMFONY IN A MILLION WAYS
    Sarah Khalil

    View full-size slide

  2. WHO AM I?
    ➤ Head of the
    ➤ Trainer and developer
    ➤ Enjoying sharer
    ➤ @saro0h

    View full-size slide

  3. WHO AM I?
    ➤ Head of the
    ➤ Trainer and developer
    ➤ Enjoying sharer
    ➤ @saro0h
    @catlannister

    View full-size slide

  4. ANY PLAN TODAY?
    ➤ Symfony Full
    Stack
    ➤ Override the
    structure
    ➤ Override
    everything in a
    bundle

    View full-size slide

  5. GLOBALLY
    Override the Symfony default directory
    structure (and a little more)

    View full-size slide

  6. ➤ AppKernel
    ➤ Cache directory
    ➤ Log directory
    ➤ Web directory
    ➤ Vendor directory
    ➤ src directory
    ➤ bin directory
    ➤ environment parameters
    ➤ charset
    ➤ session folder
    ➤ config files
    https://www.flickr.com/photos/rotscher/

    View full-size slide

  7. AppKernel
    ➤ Cache directory
    ➤ Log directory
    ➤ Web directory
    ➤ Vendor directory
    ➤ src directory
    ➤ bin directory
    ➤ environment parameters
    ➤ charset
    ➤ session folder
    ➤ config files
    https://www.flickr.com/photos/rotscher/

    View full-size slide

  8. «
    Override "app"

    View full-size slide

  9. «
    Override "app"

    View full-size slide

  10. CHANGE THE NAME THE KERNEL
    // Symfony\Component\HttpKernel\Kernel
    public function getName()
    {
    if (null === $this->name) {
    $this->name = preg_replace('/[^a-zA-Z0-9_]+/', '', basename($this->rootDir));
    }
    return $this->name;
    }
    Change the name of the original app directory
    + requires statements in the front controllers.
    1/4

    View full-size slide

  11. CHANGE THE NAME THE KERNEL
    Change the prefix of the original appKernel class.
    2/4

    View full-size slide

  12. CHANGE THE NAME THE KERNEL
    In the composer.son file:
    4/4
    {
    "extra": {
    "symfony-app-dir": "ezpublish",
    "incenteev-parameters": {
    "file": "ezpublish/config/parameters.yml"
    }
    }
    }

    View full-size slide

  13. AppKernel
    Cache directory
    ➤ Log directory
    ➤ Web directory
    ➤ Vendor directory
    ➤ src directory
    ➤ bin directory
    ➤ environment parameters
    ➤ charset
    ➤ session folder
    ➤ config files
    https://www.flickr.com/photos/rotscher/

    View full-size slide

  14. OVERRIDE THE CACHE DIRECTORY
    The cache sits in the app/cache folder.
    In the app/AppKernel class, you need to implement the getCacheDir().
    // Symfony\Component\HttpKernel\Kernel
    public function getCacheDir()
    {
    return $this->rootDir.'/cache/'.$this->environment;
    }

    View full-size slide

  15. AppKernel
    Cache directory
    Log directory
    ➤ Web directory
    ➤ Vendor directory
    ➤ src directory
    ➤ bin directory
    ➤ environment parameters
    ➤ charset
    ➤ session folder
    ➤ config files
    https://www.flickr.com/photos/rotscher/

    View full-size slide

  16. OVERRIDE THE LOG DIRECTORY
    The cache sits in the app/logs folder.
    In the app/AppKernel class, you need to implement the getLogDir().
    // Symfony\Component\HttpKernel\Kernel
    public function getLogDir()
    {
    return $this->rootDir.'/logs';
    }

    View full-size slide

  17. AppKernel
    Cache directory
    Log directory
    Web directory
    ➤ Vendor directory
    ➤ src directory
    ➤ bin directory
    ➤ environment parameters
    ➤ charset
    ➤ session folder
    ➤ config files
    https://www.flickr.com/photos/rotscher/

    View full-size slide

  18. OVERRIDE THE WEB DIRECTORY
    1. Make sure that the path to the app/ directory of your application is correct for the
    required files in your front controller (app.php|app_dev.php)
    2. Change extra.symfony-web-dir in the composer.son file your application:
    1/3
    $loader = require_once __DIR__.'/../app/bootstrap.php.cache';
    require_once __DIR__.'/../app/AppKernel.php';
    {
    ...
    "extra": {
    ...
    "symfony-web-dir": "my_new_web_dir"
    }
    }
    http://symfony.com/doc/current/cookbook/configuration/override_dir_structure.html#override-the-web-directory

    View full-size slide

  19. OVERRIDE THE WEB DIRECTORY (WITH A SHARED HOST)
    Option a: Override the web folder of your
    application to the one that is exposed by the shared
    host (www | public_html folder).
    Option b : Create a symbolic link from the web
    directory to the directory that is « exposed » by the
    shared host (www | public_html folder).
    2/3
    http://symfony.com/doc/current/cookbook/configuration/override_dir_structure.html#override-the-web-directory

    View full-size slide

  20. OVERRIDE THE WEB DIRECTORY (WITH ASCETIC USED)
    You also need to override the assetic.read_from
    configuration parameter to target the new web directory you
    changed:
    3/3
    assetic:
    # ...
    read_from: "%kernel.root_dir%/../../public_html"
    Don’t forget to clear the cache!

    View full-size slide

  21. AppKernel
    Cache directory
    Log directory
    Web directory
    Vendor directory
    ➤ src directory
    ➤ bin directory
    ➤ environment parameters
    ➤ charset
    ➤ session folder
    ➤ config files
    https://www.flickr.com/photos/rotscher/

    View full-size slide

  22. OVERRIDE THE VENDOR DIRECTORY
    1. Override the config.vendor-dir in the composer.json file.
    2.Override the path to the vendor directory in the app/autoload.php:
    {
    ...
    "config": {
    ...
    "vendor-dir": "/some/dir/vendor"
    },
    ...
    }
    $loader = require '/some/dir/vendor/autoload.php';

    View full-size slide

  23. «
    This modification can be of interest if you are working in a virtual
    environment and cannot use NFS.
    Ex: if you're running a Symfony application using Vagrant/VirtualBox in a
    guest operating system.
    -Symfony documentation

    View full-size slide

  24. AppKernel
    Cache directory
    Log directory
    Web directory
    Vendor directory
    src directory
    ➤ bin directory
    ➤ environment parameters
    ➤ charset
    ➤ session folder
    ➤ config files
    https://www.flickr.com/photos/rotscher/

    View full-size slide

  25. CHANGE BUNDLES’ FOLDER
    Originally:
    Override:
    {
    "autoload": {
    "psr-0": {
    "": "src/"
    }
    }
    }
    {
    "autoload": {
    "psr-4": {
    "": "src/"
    }
    }
    }
    {
    "autoload": {
    "psr-0": {
    "": "newFolder/"
    }
    }
    }
    {
    "autoload": {
    "psr-4": {
    "": "newFolder/"
    }
    }
    }
    $ composer dumpautoload

    View full-size slide

  26. AppKernel
    Cache directory
    Log directory
    Web directory
    Vendor directory
    src directory
    bin directory
    ➤ environment parameters
    ➤ charset
    ➤ session folder
    ➤ config files
    https://www.flickr.com/photos/rotscher/

    View full-size slide

  27. CHANGE THE BIN FOLDER
    Originally:
    Override:
    {
    "config": {
    "bin-dir": "bin"
    }
    }
    {
    "config": {
    "bin-dir": "exec"
    }
    }

    View full-size slide

  28. AppKernel
    Cache directory
    Log directory
    Web directory
    Vendor directory
    src directory
    bin directory
    Environment parameters
    ➤ charset
    ➤ session folder
    ➤ config files
    https://www.flickr.com/photos/rotscher/

    View full-size slide

  29. OVERRIDE THE ENVIRONMENT VARIABLES
    ➤ All environment variables begin with SYMFONY__
    ➤ In the app/AppKernel class, implement getEnvParameters (call the parent first).
    // Symfony\Component\HttpKernel\Kernel
    protected function getEnvParameters()
    {
    $parameters = array();
    foreach ($_SERVER as $key => $value) {
    if (0 === strpos($key, 'SYMFONY__')) {
    $parameters[strtolower(str_replace('__', '.', substr($key, 9)))] = $value;
    }
    }
    return $parameters;
    }

    View full-size slide

  30. AppKernel
    Cache directory
    Log directory
    Web directory
    Vendor directory
    src directory
    bin directory
    Environment parameters
    Charset
    ➤ session folder
    ➤ config files
    https://www.flickr.com/photos/rotscher/

    View full-size slide

  31. CHANGE THE CHARSET
    ➤ In the app/AppKernel class, you need to implement the getCharset().
    // Symfony\Component\HttpKernel\Kernel
    public function getCharset()
    {
    return 'UTF-8';
    }

    View full-size slide

  32. AppKernel
    Cache directory
    Log directory
    Web directory
    Vendor directory
    src directory
    bin directory
    Environment parameters
    Charset
    Session folder
    ➤ config files
    https://www.flickr.com/photos/rotscher/

    View full-size slide

  33. OVERRIDE THE SESSION STORAGE FOLDER
    Originally:
    Override:
    framework:
    session:
    handler_id: session.handler.native_file
    save_path: "%kernel.cache_dir%/sessions"
    framework:
    session:
    handler_id: session.handler.native_file
    save_path: "%kernel.root_dir%/sessions"

    View full-size slide

  34. AppKernel
    Cache directory
    Log directory
    Web directory
    Vendor directory
    src directory
    bin directory
    Environment parameters
    Charset
    Session folder
    Config files
    https://www.flickr.com/photos/rotscher/

    View full-size slide

  35. OVERRIDE THE CONFIGURATION FILE
    Override the folder, the name of the file…
    // app/config/AppKernel.php
    public function registerContainerConfiguration(LoaderInterface $loader)
    {
    $loader->load($this->getRootDir().'/config/config_'.$this->getEnvironment().'.yml');
    }

    View full-size slide

  36. OVERRIDE
    BUNDLE
    Override everything you can find in a
    bundle.

    View full-size slide

  37. ➤ Routes
    ➤ Templates
    ➤ Controllers
    ➤ Services
    ➤ Configuration
    ➤ Forms
    ➤ Validation
    ➤ Translation

    View full-size slide

  38. ➤ Routes
    ➤ Templates
    ➤ Controllers
    ➤ Services
    ➤ Configuration
    ➤ Forms
    ➤ Validation
    ➤ Translation

    View full-size slide

  39. Routes
    ➤ Templates
    ➤ Controllers
    ➤ Services
    ➤ Configuration
    ➤ Forms
    ➤ Validation
    ➤ Translation

    View full-size slide

  40. Routes
    ➤ Templates
    ➤ Controllers
    ➤ Services
    ➤ Configuration
    ➤ Forms
    ➤ Validation
    ➤ Translation

    View full-size slide

  41. «
    You have 2 options.

    View full-size slide

  42. LET’S SAY YOU NEED TO OVERRIDE THE
    ROUTES OF THE FOSUSERBUNDLE
    FOR YOUR OWN BUNDLE

    View full-size slide

  43. EASIEST WAY
    ➤Don’t import the routes of the FOSUserBundle in your app/
    config/routing.yml file.
    ➤Copy / Paste all the routes from FOSUserBundle in your
    app/config/routing.yml file and modify if directly.
    Option 1
    http://symfony.com/doc/current/cookbook/bundles/override.html#routing

    View full-size slide

  44. « WORKING WITH RESOURCES » WAY
    1. Import the routes of the FOSUserBundle in your app/
    config/routing.yml file.
    2. Create a new routing file following this pattern:
    •app/Resources/BundleName/path/to/routing/file/to/override.extension
    •exemple : in app/Resources/FosUserBundle/config/routing/all.xml
    3. In there, override the routes you need to.
    Option 2
    # app/config/routing.yml
    fos_user:
    resource: "@FOSUserBundle/Resources/config/routing/all.xml"
    If you refer to resources without using the @BundleName
    shortcut, they can't be overridden in this way.

    View full-size slide

  45. Routes
    Templates
    ➤ Controllers
    ➤ Services
    ➤ Configuration
    ➤ Forms
    ➤ Validation
    ➤ Translation

    View full-size slide

  46. Routes
    Templates
    ➤ Controllers
    ➤ Services
    ➤ Configuration
    ➤ Forms
    ➤ Validation
    ➤ Translation

    View full-size slide

  47. OVERRIDE A TEMPLATE
    Let’s say you need to override the following file:
    vendor/Symfony/…/TwigBundle/Resources/
    views/Exception/error.html.twig

    View full-size slide

  48. «
    You have 2 options.

    View full-size slide

  49. OVERRIDE A TEMPLATE
    You need to create the following file:
    app/Resources/TwigBundle/views/Exception/
    error.html.twig

    View full-size slide

  50. HOW IT WORKS? (« WORKING WITH RESOURCES WAY »)
    Create:
    app/Resources/TwigBundle/views/Exception/error.html.twig
    Option 1

    View full-size slide

  51. HOW IT WORKS? (« WORKING WITH RESOURCES WAY »)
    When calling the AcmeBlogBundle:Blog:index.html.twig
    logical path, Symfony looks in the following places
    (respectively):
    1.app/Resources/TwigBundle/views/Exception/error.html.twig
    2.[…]/TwigBundle/Resources/Exception/Exceptions/
    error.html.twig
    Option 1
    http://symfony.com/doc/current/book/templating.html#overriding-bundle-templates

    View full-size slide

  52. OVERRIDE A TEMPLATE (USING BUNDLE INHERITANCE)
    1. Implement the method getParent() in the bundle class.
    2. Recreate the file under the same arborescence:
    Option 2
    // src/AppBundle/AppBundle.php
    public function getParent()
    {
    return 'TwigBundle';
    }
    src/AppBundle/Resources/views/Exception/error.html.twig
    http://symfony.com/doc/current/cookbook/bundles/inheritance.html#overriding-resources-templates-routing-etc

    View full-size slide

  53. Routes
    Templates
    Controllers
    ➤ Services
    ➤ Configuration
    ➤ Forms
    ➤ Validation
    ➤ Translation

    View full-size slide

  54. Routes
    Templates
    Controllers
    ➤ Services
    ➤ Configuration
    ➤ Forms
    ➤ Validation
    ➤ Translation

    View full-size slide

  55. OVERRIDE A CONTROLLER
    ➤ Let’s say you need to override the showAction of the TwigBundle:
    // Symfony\Bundle\TwigBundle\Controller\ExceptionController
    public function showAction(
    Request $request,
    FlattenException $exception,
    DebugLoggerInterface $logger = null
    ){
    // Some logic and returns a response
    }

    View full-size slide

  56. OVERRIDE A CONTROLLER (USING THE BUNDLE INHERITANCE)
    1. Implement the method getParent() in your bundle class.
    2. Create the src/AppBundle/Controller/ExceptionController.php with the
    showAction.
    3. (Optional) Extends from the ExceptionController to be able to call the
    parent::showAction(), get the response and modify it as you need.
    // src/AppBundle/AppBundle.php
    public function getParent()
    {
    return 'TwigBundle';
    }

    View full-size slide

  57. To be able to override the controller that
    way, it must be referenced as the following:
    TwigBundle:Exception:show

    View full-size slide

  58. Routes
    Templates
    Controllers
    Services
    ➤ Configuration
    ➤ Forms
    ➤ Validation
    ➤ Translation

    View full-size slide

  59. Routes
    Templates
    Controllers
    Services
    ➤ Configuration
    ➤ Forms
    ➤ Validation
    ➤ Translation

    View full-size slide

  60. 4 OPTIONS…

    View full-size slide

  61. 4 OPTIONS…
    And no, I won’t show you all of them ;)

    View full-size slide

  62. COMPILER PASS
    http://symfony.com/doc/current/cookbook/service_container/compiler_passes.html
    1

    View full-size slide

  63. DECORATION OF SERVICE
    2

    View full-size slide

  64. DECORATION OF SERVICE
    bar:
    public: false
    class: stdClass
    decorates: foo
    arguments: ["@bar.inner"]
    http://symfony.com/doc/current/components/dependency_injection/advanced.html#decorating-services

    View full-size slide

  65. Routes
    Templates
    Controllers
    Services
    Configuration
    ➤ Forms
    ➤ Validation
    ➤ Translation

    View full-size slide

  66. Routes
    Templates
    Controllers
    Services
    Configuration
    ➤ Forms
    ➤ Validation
    ➤ Translation

    View full-size slide

  67. «
    You have 2 options.

    View full-size slide

  68. OVERRIDE THE CONFIGURATION
    The config_[your_env].yml is imported in the
    registerContainerConfiguration() method in the app/appKernel
    class.
    It is read from top to bottom. If a configuration variable is
    declared, you can override it after it.
    That’s basically what it is done with the config.yml file and the
    config_[your_env].yml
    Option 1

    View full-size slide

  69. OVERRIDE THE CONFIGURATION
    1. Create a compiler pass.
    2. As you get the containerBuilder, you can use
    the method setParameter($name, $value).
    Option 2

    View full-size slide

  70. Routes
    Templates
    Controllers
    Services
    Configuration
    Forms
    ➤ Validation
    ➤ Translation

    View full-size slide

  71. Routes
    Templates
    Controllers
    Services
    Configuration
    Forms
    ➤ Validation
    ➤ Translation

    View full-size slide

  72. OVERRIDE A TYPE (REPLACE IT)
    You need to declare the original type as a service, that
    way, you can override it as explained in the service chapter.
    Option 1

    View full-size slide

  73. OVERRIDE A TYPE (DYNAMIQUE INHERITANCE) Option 2
    namespace AppBundle\Form\Type;
    use Symfony\Component\Form\AbstractType;
    use Symfony\Component\Form\FormBuilderInterface;
    class RegistrationFormType extends AbstractType
    {
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
    $builder->add('name');
    $builder->remove('surname');
    }
    public function getParent()
    {
    return 'fos_user_registration';
    }
    public function getName()
    {
    return 'app_user_registration';
    }
    }

    View full-size slide

  74. Routes
    Templates
    Controllers
    Services
    Configuration
    Forms
    Validation
    ➤ Translation

    View full-size slide

  75. Routes
    Templates
    Controllers
    Services
    Configuration
    Forms
    Validation
    ➤ Translation

    View full-size slide

  76. OVERRIDE THE VALIDATION OF A FIELD
    ➤Symfony loads all validation configuration files
    from every bundle and combines them into one
    validation metadata tree.
    ➤This means you are able to add new constraints to
    a property, but you cannot override them.
    http://symfony.com/doc/2.3/cookbook/bundles/override.html#validation-metadata

    View full-size slide

  77. OVERRIDE A VALIDATION CONFIGURATION
    Add new validation constraint in the bundle that is
    overriding the original with the same validation group.

    View full-size slide

  78. FOS\UserBundle\Model\User:
    properties:
    plainPassword:
    - NotBlank:
    groups: [Registration]
    - Length:
    min: 6
    minMessage: fos_user.password.short
    groups: [Registration]

    View full-size slide

  79. Routes
    Templates
    Controllers
    Services
    Configuration
    Forms
    Validation
    Translation

    View full-size slide

  80. Routes
    Templates
    Controllers
    Services
    Configuration
    Forms
    Validation
    Translation

    View full-size slide

  81. «
    You have 2 options.

    View full-size slide

  82. OVERRIDE A TRANSLATION FILE
    It’s all about domains! (messages.en.xlf)
    1.All you need to do is to recreate the translation file in
    YourBundle/Resources/translations.
    2.Make sure that your bundle is loaded before the
    original bundle (no bundle inheritance).
    Option 1

    View full-size slide

  83. OVERRIDE A TRANSLATION FILE
    Translation files are resources!
    Create the same file in the app/Resources/translations
    folder.
    Option 2

    View full-size slide

  84. ➤You can use event listeners|subscribers to override
    controllers (kernel.controller).
    ➤You can use the app/autoload.php file to override
    classes.
    ➤You could use other options according to the thing you
    need to override…

    View full-size slide

  85. PARICON2015.SYMFONY.COM

    View full-size slide

  86. Thank you!
    @saro0h
    speakerdeck.com/saro0h/
    This is a zero guys!
    saro0h

    View full-size slide