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

SymfonyLive San Francisco 2015 - Overriding Sym...

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. WHO AM I? ➤ Head of the ➤ Trainer and

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

    developer ➤ Enjoying sharer ➤ @saro0h @catlannister
  3. ANY PLAN TODAY? ➤ Symfony Full Stack ➤ Override the

    structure ➤ Override everything in a bundle
  4. ➤ 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/
  5. 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/
  6. 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
  7. CHANGE THE NAME THE KERNEL In the composer.son file: 4/4

    { "extra": { "symfony-app-dir": "ezpublish", "incenteev-parameters": { "file": "ezpublish/config/parameters.yml" } } }
  8. 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/
  9. 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; }
  10. 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/
  11. 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'; }
  12. 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/
  13. 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
  14. 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
  15. 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!
  16. 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/
  17. 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';
  18. « 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
  19. 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/
  20. CHANGE BUNDLES’ FOLDER Originally: Override: { "autoload": { "psr-0": {

    "": "src/" } } } { "autoload": { "psr-4": { "": "src/" } } } { "autoload": { "psr-0": { "": "newFolder/" } } } { "autoload": { "psr-4": { "": "newFolder/" } } } $ composer dumpautoload
  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/
  22. CHANGE THE BIN FOLDER Originally: Override: { "config": { "bin-dir":

    "bin" } } { "config": { "bin-dir": "exec" } }
  23. 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/
  24. 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; }
  25. 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/
  26. CHANGE THE CHARSET ➤ In the app/AppKernel class, you need

    to implement the getCharset(). // Symfony\Component\HttpKernel\Kernel public function getCharset() { return 'UTF-8'; }
  27. 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/
  28. 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"
  29. 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/
  30. 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'); }
  31. LET’S SAY YOU NEED TO OVERRIDE THE ROUTES OF THE

    FOSUSERBUNDLE FOR YOUR OWN BUNDLE
  32. 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
  33. « 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.
  34. OVERRIDE A TEMPLATE Let’s say you need to override the

    following file: vendor/Symfony/…/TwigBundle/Resources/ views/Exception/error.html.twig
  35. OVERRIDE A TEMPLATE You need to create the following file:

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

    app/Resources/TwigBundle/views/Exception/error.html.twig Option 1
  37. 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
  38. 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
  39. 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 }
  40. 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'; }
  41. To be able to override the controller that way, it

    must be referenced as the following: TwigBundle:Exception:show
  42. 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
  43. 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
  44. OVERRIDE THE CONFIGURATION 1. Create a compiler pass. 2. As

    you get the containerBuilder, you can use the method setParameter($name, $value). Option 2
  45. 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
  46. 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'; } }
  47. 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
  48. OVERRIDE A VALIDATION CONFIGURATION Add new validation constraint in the

    bundle that is overriding the original with the same validation group.
  49. 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
  50. OVERRIDE A TRANSLATION FILE Translation files are resources! Create the

    same file in the app/Resources/translations folder. Option 2
  51. ➤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…