From 947ad92a90d9ad2803ce897342e4706f93e61d30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Chardonnet?= Date: Sat, 1 Mar 2014 00:45:11 +0100 Subject: [PATCH 01/13] [Console] Adding use cases to command as service | Q | A | ------------- | --- | Doc fix? | yes | New docs? | no | Applies to | 2.4+ | Fixed tickets | N/A Command as a service can be useful to give access to services and configuration parameters in the `configure` method. A simple use case: you want to allow the user to set an option's default value in the `app/config/parameters.yml` file. Or the default value needs to be computed by a service (database retrieval for instance). With a `ContainerAwareCommand`, this wouldn't be possible because the `configure` method is called from the constructor, so the container isn't set yet. --- cookbook/console/console_command.rst | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/cookbook/console/console_command.rst b/cookbook/console/console_command.rst index 6e3721a24ef..455aab090cc 100644 --- a/cookbook/console/console_command.rst +++ b/cookbook/console/console_command.rst @@ -71,9 +71,12 @@ Register Commands in the Service Container Support for registering commands in the service container was added in version 2.4. -Instead of putting your command in the ``Command`` directory and having Symfony -auto-discover it for you, you can register commands in the service container -using the ``console.command`` tag: +By default, Symfony will take a look in the ``Command`` directory of you +bundles and automatically register your commands. For the ones implementing +the ``ContainerAwareCommand`` interface, Symfony will even inject the container. + +If you wan to, you can instead register them as services in the container using +the ``console.command`` tag: .. configuration-block:: @@ -111,9 +114,20 @@ using the ``console.command`` tag: .. tip:: - Registering your command as a service gives you more control over its - location and the services that are injected into it. But, there are no - functional advantages, so you don't need to register your command as a service. + Command as a service can be usefull in few situations: + * if you need your commands to be defined somewhere else than ``Command`` + * if you need to access services or configuration parameters in the + ``configure`` method + + For example, Imagine you want to provide a default value for the ``name`` + option. You could hard code a string and pass it as the 4th argument of + ``addArgument``, or you could allow the user to set the default value in the + configuration. + + With a ``ContainerAwareCommand`` you wouldn't be able to retrieve the + configuration parameter, because the ``configure`` method is called in the + command's constructor. The only solution is to inject them through its + constructor. Getting Services from the Service Container ------------------------------------------- From a055140916455563182a2df5fe63acb2c6ad5a96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Chardonnet?= Date: Sat, 1 Mar 2014 12:54:18 +0100 Subject: [PATCH 02/13] Took @WouterJ's advices into account --- cookbook/console/console_command.rst | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/cookbook/console/console_command.rst b/cookbook/console/console_command.rst index 455aab090cc..4beba877e89 100644 --- a/cookbook/console/console_command.rst +++ b/cookbook/console/console_command.rst @@ -75,7 +75,7 @@ By default, Symfony will take a look in the ``Command`` directory of you bundles and automatically register your commands. For the ones implementing the ``ContainerAwareCommand`` interface, Symfony will even inject the container. -If you wan to, you can instead register them as services in the container using +If you want to, you can instead register them as services in the container using the ``console.command`` tag: .. configuration-block:: @@ -115,11 +115,12 @@ the ``console.command`` tag: .. tip:: Command as a service can be usefull in few situations: - * if you need your commands to be defined somewhere else than ``Command`` - * if you need to access services or configuration parameters in the - ``configure`` method - For example, Imagine you want to provide a default value for the ``name`` + * If you need your commands to be defined somewhere else than ``Command``; + * if you need to access services or configuration parameters in the + ``configure`` method. + + For example, imagine you want to provide a default value for the ``name`` option. You could hard code a string and pass it as the 4th argument of ``addArgument``, or you could allow the user to set the default value in the configuration. From a7b916e42e525c2cb4133d5f05feb0ab6d35e74d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Chardonnet?= Date: Sat, 1 Mar 2014 15:17:41 +0100 Subject: [PATCH 03/13] Fixed typos spotted by @cordoval --- cookbook/console/console_command.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/cookbook/console/console_command.rst b/cookbook/console/console_command.rst index 4beba877e89..320c4d0377b 100644 --- a/cookbook/console/console_command.rst +++ b/cookbook/console/console_command.rst @@ -71,7 +71,7 @@ Register Commands in the Service Container Support for registering commands in the service container was added in version 2.4. -By default, Symfony will take a look in the ``Command`` directory of you +By default, Symfony will take a look in the ``Command`` directory of your bundles and automatically register your commands. For the ones implementing the ``ContainerAwareCommand`` interface, Symfony will even inject the container. @@ -114,9 +114,10 @@ the ``console.command`` tag: .. tip:: - Command as a service can be usefull in few situations: + Commands as services can be useful in few situations: - * If you need your commands to be defined somewhere else than ``Command``; + * if you need your commands to be defined somewhere else than in the + ``Command`` folder; * if you need to access services or configuration parameters in the ``configure`` method. From cdd534a806ba45020c076dda70d2128be1cb3b69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Chardonnet?= Date: Sat, 1 Mar 2014 20:12:46 +0100 Subject: [PATCH 04/13] Added @lsmith77 and @dbu use cases --- cookbook/console/console_command.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cookbook/console/console_command.rst b/cookbook/console/console_command.rst index 320c4d0377b..3441549e363 100644 --- a/cookbook/console/console_command.rst +++ b/cookbook/console/console_command.rst @@ -118,6 +118,11 @@ the ``console.command`` tag: * if you need your commands to be defined somewhere else than in the ``Command`` folder; + * if you need to register the command conditionally (depending on the + environment or presence of some dependencies); + * ou want to reuse the command with a different service or different + configuration, without having to extend the command - you could just + define a second service with the same class; * if you need to access services or configuration parameters in the ``configure`` method. From e13795114c37b5085bf7c57fb79cce6a6cb57571 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Chardonnet?= Date: Sat, 1 Mar 2014 23:35:14 +0100 Subject: [PATCH 05/13] Created a new article --- components/console/commands_as_services.rst | 118 ++++++++++++++++++++ components/console/index.rst | 1 + cookbook/console/console_command.rst | 74 ------------ 3 files changed, 119 insertions(+), 74 deletions(-) create mode 100644 components/console/commands_as_services.rst diff --git a/components/console/commands_as_services.rst b/components/console/commands_as_services.rst new file mode 100644 index 00000000000..b0bffe5fd1a --- /dev/null +++ b/components/console/commands_as_services.rst @@ -0,0 +1,118 @@ +.. index:: + single: Console; Commands as Services + +How to define Commands as Services +================================== + +.. versionadded:: 2.4 + Support for registering commands in the service container was added in + version 2.4. + +By default, Symfony will take a look in the ``Command`` directory of your +bundles and automatically register your commands. For the ones implementing +the ``ContainerAwareCommand`` interface, Symfony will even inject the container. + +While making life easier, this default implementation has some drawbacks in some +situations: + +* what if you want your command to be defined elsewhere than in the ``Command`` + folder? +* what if you want to register conditionally your command, depending on the + current environment or on the availability of some dependencies? +* what if you need to access dependencies before the ``setContainer`` is called + (for example in the ``configure`` method)? +* what if you want to reuse a command many times, but with different + dependencies or parameters? + +To solve those problems, you can register your command as a service by simply +defining it with the ``console.command`` tag: + +.. configuration-block:: + + .. code-block:: yaml + + # app/config/config.yml + services: + acme_hello.command.my_command: + class: Acme\HelloBundle\Command\MyCommand + tags: + - { name: console.command } + + .. code-block:: xml + + + + + + + + + + + .. code-block:: php + + // app/config/config.php + + $container + ->register('acme_hello.command.my_command', 'Acme\HelloBundle\Command\MyCommand') + ->addTag('console.command') + ; + +Here are some use cases. + +Use dependencies and parameters in configure +-------------------------------------------- + +For example, imagine you want to provide a default value for the ``name`` +argument. You could: + +* hard code a string and pass it as the 4th argument of ``addArgument``; +* allow the user to set the default value in the configuration; +* retrieve the default value from a service (a repository for example). + +With a ``ContainerAwareCommand`` you wouldn't be able to retrieve the +configuration parameter, because the ``configure`` method is called in the +command's constructor. The only solution is to inject them through its +constructor: + + nameRepository = $nameRepository; + } + + protected function configure() + { + $defaultName = $this->nameRepository->findLastOne(); + + $this + ->setName('demo:greet') + ->setDescription('Greet someone') + ->addArgument('name', InputArgument::OPTIONAL, 'Who do you want to greet?', $defaultName) + ; + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + $name = $input->getArgument('name'); + + $output->writeln($name); + } + } diff --git a/components/console/index.rst b/components/console/index.rst index c814942d018..a4b85f9cba9 100644 --- a/components/console/index.rst +++ b/components/console/index.rst @@ -6,6 +6,7 @@ Console introduction usage + commands_as_services single_command_tool events helpers/index diff --git a/cookbook/console/console_command.rst b/cookbook/console/console_command.rst index 3441549e363..abd5fddbc94 100644 --- a/cookbook/console/console_command.rst +++ b/cookbook/console/console_command.rst @@ -62,80 +62,6 @@ This command will now automatically be available to run: $ app/console demo:greet Fabien -.. _cookbook-console-dic: - -Register Commands in the Service Container ------------------------------------------- - -.. versionadded:: 2.4 - Support for registering commands in the service container was added in - version 2.4. - -By default, Symfony will take a look in the ``Command`` directory of your -bundles and automatically register your commands. For the ones implementing -the ``ContainerAwareCommand`` interface, Symfony will even inject the container. - -If you want to, you can instead register them as services in the container using -the ``console.command`` tag: - -.. configuration-block:: - - .. code-block:: yaml - - # app/config/config.yml - services: - acme_hello.command.my_command: - class: Acme\HelloBundle\Command\MyCommand - tags: - - { name: console.command } - - .. code-block:: xml - - - - - - - - - - - .. code-block:: php - - // app/config/config.php - - $container - ->register('acme_hello.command.my_command', 'Acme\HelloBundle\Command\MyCommand') - ->addTag('console.command') - ; - -.. tip:: - - Commands as services can be useful in few situations: - - * if you need your commands to be defined somewhere else than in the - ``Command`` folder; - * if you need to register the command conditionally (depending on the - environment or presence of some dependencies); - * ou want to reuse the command with a different service or different - configuration, without having to extend the command - you could just - define a second service with the same class; - * if you need to access services or configuration parameters in the - ``configure`` method. - - For example, imagine you want to provide a default value for the ``name`` - option. You could hard code a string and pass it as the 4th argument of - ``addArgument``, or you could allow the user to set the default value in the - configuration. - - With a ``ContainerAwareCommand`` you wouldn't be able to retrieve the - configuration parameter, because the ``configure`` method is called in the - command's constructor. The only solution is to inject them through its - constructor. - Getting Services from the Service Container ------------------------------------------- From 6a7a25fa165b71a84c12350a3977eb549d4c3d2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Chardonnet?= Date: Sun, 2 Mar 2014 11:47:42 +0100 Subject: [PATCH 06/13] Fixed @WouterJ's feedback --- components/console/commands_as_services.rst | 53 ++++++++++----------- components/console/introduction.rst | 1 + 2 files changed, 25 insertions(+), 29 deletions(-) diff --git a/components/console/commands_as_services.rst b/components/console/commands_as_services.rst index b0bffe5fd1a..3aa217c25ee 100644 --- a/components/console/commands_as_services.rst +++ b/components/console/commands_as_services.rst @@ -1,26 +1,25 @@ .. index:: single: Console; Commands as Services -How to define Commands as Services +How to Define Commands as Services ================================== .. versionadded:: 2.4 - Support for registering commands in the service container was added in + Support for registering commands in the service container was introduced in version 2.4. By default, Symfony will take a look in the ``Command`` directory of your bundles and automatically register your commands. For the ones implementing the ``ContainerAwareCommand`` interface, Symfony will even inject the container. - While making life easier, this default implementation has some drawbacks in some situations: -* what if you want your command to be defined elsewhere than in the ``Command`` - folder? -* what if you want to register conditionally your command, depending on the +* What if you want your command to be defined elsewhere than in the ``Command`` + directory? +* what if you want to conditionally register your command, depending on the current environment or on the availability of some dependencies? -* what if you need to access dependencies before the ``setContainer`` is called - (for example in the ``configure`` method)? +* what if you need to access dependencies before the ``setContainer()`` is + called (for example in the ``configure()`` method)? * what if you want to reuse a command many times, but with different dependencies or parameters? @@ -46,45 +45,41 @@ defining it with the ``console.command`` tag: xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> - - - + + + + + .. code-block:: php // app/config/config.php - $container ->register('acme_hello.command.my_command', 'Acme\HelloBundle\Command\MyCommand') ->addTag('console.command') ; -Here are some use cases. - -Use dependencies and parameters in configure --------------------------------------------- +Use Case: Using Dependencies and Parameters to Set Default Values for Options +----------------------------------------------------------------------------- -For example, imagine you want to provide a default value for the ``name`` -argument. You could: +Imagine you want to provide a default value for the ``name``option. You could +pass one of the following as the 5th argument of ``addOption()``: -* hard code a string and pass it as the 4th argument of ``addArgument``; -* allow the user to set the default value in the configuration; -* retrieve the default value from a service (a repository for example). +* an hardcoded string; +* a value coming from the configuration (allows the user to change it easily); +* a value computed by a service (e.g. a repository). With a ``ContainerAwareCommand`` you wouldn't be able to retrieve the -configuration parameter, because the ``configure`` method is called in the -command's constructor. The only solution is to inject them through its -constructor: +configuration parameter, because the ``configure()`` method is called in the +constructor. The only solution is to inject them through it:: - setName('demo:greet') ->setDescription('Greet someone') - ->addArgument('name', InputArgument::OPTIONAL, 'Who do you want to greet?', $defaultName) + ->addOption('name', '-n', InputOption::VALUE_REQUIRED, 'Who do you want to greet?', $defaultName) ; } protected function execute(InputInterface $input, OutputInterface $output) { - $name = $input->getArgument('name'); + $name = $input->getOption('name'); $output->writeln($name); } diff --git a/components/console/introduction.rst b/components/console/introduction.rst index 98f8b8643be..8ea786629dd 100644 --- a/components/console/introduction.rst +++ b/components/console/introduction.rst @@ -527,6 +527,7 @@ Learn More! * :doc:`/components/console/usage` * :doc:`/components/console/single_command_tool` * :doc:`/components/console/events` +* :doc:`/components/console/commands_as_services` .. _Packagist: https://packagist.org/packages/symfony/console .. _ANSICON: https://github.com/adoxa/ansicon/releases From 11bfe506c9c5d175c787d4a1b300f207ddcf2415 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Chardonnet?= Date: Sun, 2 Mar 2014 17:27:35 +0100 Subject: [PATCH 07/13] Added warning about performances --- components/console/commands_as_services.rst | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/components/console/commands_as_services.rst b/components/console/commands_as_services.rst index 3aa217c25ee..29ba2c715a9 100644 --- a/components/console/commands_as_services.rst +++ b/components/console/commands_as_services.rst @@ -61,8 +61,8 @@ defining it with the ``console.command`` tag: ->addTag('console.command') ; -Use Case: Using Dependencies and Parameters to Set Default Values for Options ------------------------------------------------------------------------------ +Using Dependencies and Parameters to Set Default Values for Options +------------------------------------------------------------------- Imagine you want to provide a default value for the ``name``option. You could pass one of the following as the 5th argument of ``addOption()``: @@ -111,3 +111,9 @@ constructor. The only solution is to inject them through it:: $output->writeln($name); } } + +.. caution:: + + When running the console, every commands are instanciated, which means every + ``configure()`` methods are called. Be careful with database queries, as + this could impact performances. From e8b3320e97336beb0a270484b618a01dc3158f12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Chardonnet?= Date: Sun, 9 Mar 2014 20:10:52 +0100 Subject: [PATCH 08/13] Took into account @cordoval's feedback --- components/console/commands_as_services.rst | 22 ++++++++++----------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/components/console/commands_as_services.rst b/components/console/commands_as_services.rst index 29ba2c715a9..066eb8aab39 100644 --- a/components/console/commands_as_services.rst +++ b/components/console/commands_as_services.rst @@ -14,14 +14,12 @@ the ``ContainerAwareCommand`` interface, Symfony will even inject the container. While making life easier, this default implementation has some drawbacks in some situations: -* What if you want your command to be defined elsewhere than in the ``Command`` - directory? -* what if you want to conditionally register your command, depending on the - current environment or on the availability of some dependencies? -* what if you need to access dependencies before the ``setContainer()`` is - called (for example in the ``configure()`` method)? -* what if you want to reuse a command many times, but with different - dependencies or parameters? +* Define the command elsewhere than in the ``Command`` directory; +* Conditionally register your command, depending on the current environment or + on the availability of some dependencies; +* Access dependencies before the ``setContainer()`` is called (for example in + the ``configure()`` method); +* Reuse a command many times, but with different dependencies or parameters To solve those problems, you can register your command as a service by simply defining it with the ``console.command`` tag: @@ -73,7 +71,7 @@ pass one of the following as the 5th argument of ``addOption()``: With a ``ContainerAwareCommand`` you wouldn't be able to retrieve the configuration parameter, because the ``configure()`` method is called in the -constructor. The only solution is to inject them through it:: +constructor. The only solution is to inject them:: // src/Acme/DemoBundle/Command/GreetCommand.php namespace Acme\DemoBundle\Command; @@ -114,6 +112,6 @@ constructor. The only solution is to inject them through it:: .. caution:: - When running the console, every commands are instanciated, which means every - ``configure()`` methods are called. Be careful with database queries, as - this could impact performances. + When running the console, every command is instantiated, which means every + ``configure()`` method is called. Be careful with database queries, as + they could impact performance. From da2ee60c71d8bc9c67b1e4b052d6e14277bd350f Mon Sep 17 00:00:00 2001 From: Andrew M Date: Mon, 10 Mar 2014 18:43:35 +0200 Subject: [PATCH 09/13] Fix PSR coding standards error --- cookbook/form/dynamic_form_modification.rst | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/cookbook/form/dynamic_form_modification.rst b/cookbook/form/dynamic_form_modification.rst index 2add7ddd759..8a35f45bdac 100644 --- a/cookbook/form/dynamic_form_modification.rst +++ b/cookbook/form/dynamic_form_modification.rst @@ -99,7 +99,7 @@ creating that particular field is delegated to an event listener:: { $builder->add('price'); - $builder->addEventListener(FormEvents::PRE_SET_DATA, function(FormEvent $event) { + $builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) { // ... adding the name field if needed }); } @@ -116,7 +116,7 @@ the event listener might look like the following:: public function buildForm(FormBuilderInterface $builder, array $options) { // ... - $builder->addEventListener(FormEvents::PRE_SET_DATA, function(FormEvent $event) { + $builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) { $product = $event->getData(); $form = $event->getForm(); @@ -254,7 +254,7 @@ Using an event listener, your form might look like this:: ->add('subject', 'text') ->add('body', 'textarea') ; - $builder->addEventListener(FormEvents::PRE_SET_DATA, function(FormEvent $event) { + $builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) { // ... add a choice list of friends of the current application user }); } @@ -330,13 +330,13 @@ and fill in the listener logic:: $builder->addEventListener( FormEvents::PRE_SET_DATA, - function(FormEvent $event) use ($user) { + function (FormEvent $event) use ($user) { $form = $event->getForm(); $formOptions = array( 'class' => 'Acme\DemoBundle\Entity\User', 'property' => 'fullName', - 'query_builder' => function(EntityRepository $er) use ($user) { + 'query_builder' => function (EntityRepository $er) use ($user) { // build a custom query // return $er->createQueryBuilder('u')->addOrderBy('fullName', 'DESC'); @@ -496,7 +496,7 @@ sport like this:: $builder->addEventListener( FormEvents::PRE_SET_DATA, - function(FormEvent $event) { + function (FormEvent $event) { $form = $event->getForm(); // this would be your entity, i.e. SportMeetup @@ -565,7 +565,7 @@ The type would now look like:: )); ; - $formModifier = function(FormInterface $form, Sport $sport = null) { + $formModifier = function (FormInterface $form, Sport $sport = null) { $positions = null === $sport ? array() : $sport->getAvailablePositions(); $form->add('position', 'entity', array( @@ -577,7 +577,7 @@ The type would now look like:: $builder->addEventListener( FormEvents::PRE_SET_DATA, - function(FormEvent $event) use ($formModifier) { + function (FormEvent $event) use ($formModifier) { // this would be your entity, i.e. SportMeetup $data = $event->getData(); @@ -587,7 +587,7 @@ The type would now look like:: $builder->get('sport')->addEventListener( FormEvents::POST_SUBMIT, - function(FormEvent $event) use ($formModifier) { + function (FormEvent $event) use ($formModifier) { // It's important here to fetch $event->getForm()->getData(), as // $event->getData() will get you the client data (that is, the ID) $sport = $event->getForm()->getData(); @@ -739,7 +739,7 @@ all of this, use a listener:: public function buildForm(FormBuilderInterface $builder, array $options) { - $builder->addEventListener(FormEvents::POST_SUBMIT, function($event) { + $builder->addEventListener(FormEvents::POST_SUBMIT, function ($event) { $event->stopPropagation(); }, 900); // Always set a higher priority than ValidationListener From c8fe61046bf9c3dafbd51cad78552c0787c04880 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Chardonnet?= Date: Sat, 22 Mar 2014 18:18:32 +0100 Subject: [PATCH 10/13] Moved back and listened to @weaverryan Moved the article from components to the cookbook. --- components/console/index.rst | 1 - components/console/introduction.rst | 1 - .../console/commands_as_services.rst | 53 ++++++++++--------- cookbook/console/console_command.rst | 9 ++++ cookbook/console/index.rst | 1 + 5 files changed, 39 insertions(+), 26 deletions(-) rename {components => cookbook}/console/commands_as_services.rst (64%) diff --git a/components/console/index.rst b/components/console/index.rst index a4b85f9cba9..c814942d018 100644 --- a/components/console/index.rst +++ b/components/console/index.rst @@ -6,7 +6,6 @@ Console introduction usage - commands_as_services single_command_tool events helpers/index diff --git a/components/console/introduction.rst b/components/console/introduction.rst index 8ea786629dd..98f8b8643be 100644 --- a/components/console/introduction.rst +++ b/components/console/introduction.rst @@ -527,7 +527,6 @@ Learn More! * :doc:`/components/console/usage` * :doc:`/components/console/single_command_tool` * :doc:`/components/console/events` -* :doc:`/components/console/commands_as_services` .. _Packagist: https://packagist.org/packages/symfony/console .. _ANSICON: https://github.com/adoxa/ansicon/releases diff --git a/components/console/commands_as_services.rst b/cookbook/console/commands_as_services.rst similarity index 64% rename from components/console/commands_as_services.rst rename to cookbook/console/commands_as_services.rst index 066eb8aab39..c6001e246bf 100644 --- a/components/console/commands_as_services.rst +++ b/cookbook/console/commands_as_services.rst @@ -8,21 +8,22 @@ How to Define Commands as Services Support for registering commands in the service container was introduced in version 2.4. -By default, Symfony will take a look in the ``Command`` directory of your -bundles and automatically register your commands. For the ones implementing -the ``ContainerAwareCommand`` interface, Symfony will even inject the container. -While making life easier, this default implementation has some drawbacks in some -situations: - -* Define the command elsewhere than in the ``Command`` directory; -* Conditionally register your command, depending on the current environment or - on the availability of some dependencies; -* Access dependencies before the ``setContainer()`` is called (for example in - the ``configure()`` method); -* Reuse a command many times, but with different dependencies or parameters - -To solve those problems, you can register your command as a service by simply -defining it with the ``console.command`` tag: +By default, Symfony will take a look in the ``Command`` directory of each +bundle and automatically register your commands. If a command extends the +:class:`Symfony\\Bundle\\FrameworkBundle\\Command\\ContainerAwareCommand`, +Symfony will even inject the container. +While making life easier, this has some limitations: + +* Your command must live in the ``Command`` directory; +* There's no way to conditionally register your service based on the environment + or availability of some dependencies; +* You can't access the container in the ``configure()`` method (because + ``setContainer`` hasn't been called yet); +* You can't use the same class to create many commands (i.e. each with + different configuration). + +To solve these problems, you can register your command as a service and tag it +with ``console.command``: .. configuration-block:: @@ -62,16 +63,17 @@ defining it with the ``console.command`` tag: Using Dependencies and Parameters to Set Default Values for Options ------------------------------------------------------------------- -Imagine you want to provide a default value for the ``name``option. You could +Imagine you want to provide a default value for the ``name`` option. You could pass one of the following as the 5th argument of ``addOption()``: -* an hardcoded string; -* a value coming from the configuration (allows the user to change it easily); +* a hardcoded string; +* a container parameter (e.g. something from parameters.yml); * a value computed by a service (e.g. a repository). -With a ``ContainerAwareCommand`` you wouldn't be able to retrieve the -configuration parameter, because the ``configure()`` method is called in the -constructor. The only solution is to inject them:: +By extending ``ContainerAwareCommand``, only the first is possible, because you +can't access the container inside the ``configure()`` method. Instead, inject +any parameter or service you need into the constructor. For example, suppose you +have some ``NameRepository`` service that you'll use to get your default value:: // src/Acme/DemoBundle/Command/GreetCommand.php namespace Acme\DemoBundle\Command; @@ -110,8 +112,11 @@ constructor. The only solution is to inject them:: } } +Now, just update the arguments of your service configuration like normal to +inject the ``NameRepository``. Great, you now have a dynamic default value! + .. caution:: - When running the console, every command is instantiated, which means every - ``configure()`` method is called. Be careful with database queries, as - they could impact performance. + Be careful not to actually do any work in ``configure`` (e.g. make database + queries), as your code will be run, even if you're using the console to + execute a different command. diff --git a/cookbook/console/console_command.rst b/cookbook/console/console_command.rst index abd5fddbc94..ab509787773 100644 --- a/cookbook/console/console_command.rst +++ b/cookbook/console/console_command.rst @@ -62,6 +62,15 @@ This command will now automatically be available to run: $ app/console demo:greet Fabien +.. _cookbook-console-dic: + +Register Commands in the Service Container +------------------------------------------- + +Just like controllers, commands can be declared as services. See the +:doc:`dedicated cookbook entry ` +for details. + Getting Services from the Service Container ------------------------------------------- diff --git a/cookbook/console/index.rst b/cookbook/console/index.rst index 878d1fc862a..6f1f939d772 100644 --- a/cookbook/console/index.rst +++ b/cookbook/console/index.rst @@ -8,3 +8,4 @@ Console usage sending_emails logging + commands_as_services From 36384db076378c180adfcdde20edf2c3760416c2 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Fri, 21 Mar 2014 15:59:20 +0100 Subject: [PATCH 11/13] make method supportsClass() in custom voter compatible with the interface's documentation --- cookbook/security/voters_data_permission.rst | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/cookbook/security/voters_data_permission.rst b/cookbook/security/voters_data_permission.rst index 0e5055261e1..6646f4e8928 100644 --- a/cookbook/security/voters_data_permission.rst +++ b/cookbook/security/voters_data_permission.rst @@ -64,7 +64,6 @@ edit a particular object. Here's an example implementation:: use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\User\UserInterface; - use Acme\DemoBundle\Entity\Post; class PostVoter implements VoterInterface { @@ -79,9 +78,11 @@ edit a particular object. Here's an example implementation:: )); } - public function supportsClass($obj) + public function supportsClass($class) { - return $obj instanceof Post; + $supportedClass = 'Acme\DemoBundle\Entity\Post'; + + return $supportedClass === $class || is_subclass_of($class, $supportedClass); } /** @@ -90,7 +91,7 @@ edit a particular object. Here's an example implementation:: public function vote(TokenInterface $token, $post, array $attributes) { // check if class of this object is supported by this voter - if (!$this->supportsClass($post)) { + if (!$this->supportsClass(get_class($post))) { return VoterInterface::ACCESS_ABSTAIN; } From 08a2f7be70c31d42772454e77790988383c0592e Mon Sep 17 00:00:00 2001 From: guiditoito Date: Fri, 21 Mar 2014 18:25:13 -0300 Subject: [PATCH 12/13] Add support for nginx This doesn't work for nginx you forgot the user. It's a broadly used webserver at this point and should be included. --- book/installation.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/book/installation.rst b/book/installation.rst index e219e9640c9..5a0f04b5de9 100644 --- a/book/installation.rst +++ b/book/installation.rst @@ -233,7 +233,7 @@ If there are any issues, correct them now before moving on. $ rm -rf app/cache/* $ rm -rf app/logs/* - $ APACHEUSER=`ps aux | grep -E '[a]pache|[h]ttpd|[_]www|[w]ww-data' | grep -v root | head -1 | cut -d\ -f1` + $ APACHEUSER=`ps aux | grep -E '[a]pache|[h]ttpd|[_]www|[w]ww-data|[n]ginx' | grep -v root | head -1 | cut -d\ -f1` $ sudo chmod +a "$APACHEUSER allow delete,write,append,file_inherit,directory_inherit" app/cache app/logs $ sudo chmod +a "`whoami` allow delete,write,append,file_inherit,directory_inherit" app/cache app/logs @@ -248,7 +248,7 @@ If there are any issues, correct them now before moving on. .. code-block:: bash - $ APACHEUSER=`ps aux | grep -E '[a]pache|[h]ttpd|[_]www|[w]ww-data' | grep -v root | head -1 | cut -d\ -f1` + $ APACHEUSER=`ps aux | grep -E '[a]pache|[h]ttpd|[_]www|[w]ww-data|[n]ginx' | grep -v root | head -1 | cut -d\ -f1` $ sudo setfacl -Rn -m u:"$APACHEUSER":rwX -m u:`whoami`:rwX app/cache app/logs $ sudo setfacl -dRn -m u:"$APACHEUSER":rwX -m u:`whoami`:rwX app/cache app/logs From b75d45dc49c6236ffb95b97c54d1046c276f10ff Mon Sep 17 00:00:00 2001 From: Christophe Coevoet Date: Mon, 24 Mar 2014 12:25:14 +0100 Subject: [PATCH 13/13] Simplified the Travis configuration Submodules are already handled by Travis itself, so no need to do it a second time --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index c20155875c2..9afcdfaaff4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,6 @@ python: - "2.7" install: - - "git submodule update --init" - "bash install.sh" - "pip install -q -r requirements.txt --use-mirrors"