Skip to content

Commit 72d40a8

Browse files
committed
Merge branch '2.4'
2 parents db1cda5 + b0e07b4 commit 72d40a8

7 files changed

+144
-65
lines changed

.travis.yml

-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ python:
44
- "2.7"
55

66
install:
7-
- "git submodule update --init"
87
- "bash install.sh"
98
- "pip install -q -r requirements.txt --use-mirrors"
109

book/installation.rst

+2-2
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ If there are any issues, correct them now before moving on.
233233
$ rm -rf app/cache/*
234234
$ rm -rf app/logs/*
235235
236-
$ APACHEUSER=`ps aux | grep -E '[a]pache|[h]ttpd|[_]www|[w]ww-data' | grep -v root | head -1 | cut -d\ -f1`
236+
$ APACHEUSER=`ps aux | grep -E '[a]pache|[h]ttpd|[_]www|[w]ww-data|[n]ginx' | grep -v root | head -1 | cut -d\ -f1`
237237
$ sudo chmod +a "$APACHEUSER allow delete,write,append,file_inherit,directory_inherit" app/cache app/logs
238238
$ sudo chmod +a "`whoami` allow delete,write,append,file_inherit,directory_inherit" app/cache app/logs
239239
@@ -248,7 +248,7 @@ If there are any issues, correct them now before moving on.
248248

249249
.. code-block:: bash
250250
251-
$ APACHEUSER=`ps aux | grep -E '[a]pache|[h]ttpd|[_]www|[w]ww-data' | grep -v root | head -1 | cut -d\ -f1`
251+
$ APACHEUSER=`ps aux | grep -E '[a]pache|[h]ttpd|[_]www|[w]ww-data|[n]ginx' | grep -v root | head -1 | cut -d\ -f1`
252252
$ sudo setfacl -Rn -m u:"$APACHEUSER":rwX -m u:`whoami`:rwX app/cache app/logs
253253
$ sudo setfacl -dRn -m u:"$APACHEUSER":rwX -m u:`whoami`:rwX app/cache app/logs
254254

+122
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
.. index::
2+
single: Console; Commands as Services
3+
4+
How to Define Commands as Services
5+
==================================
6+
7+
.. versionadded:: 2.4
8+
Support for registering commands in the service container was introduced in
9+
version 2.4.
10+
11+
By default, Symfony will take a look in the ``Command`` directory of each
12+
bundle and automatically register your commands. If a command extends the
13+
:class:`Symfony\\Bundle\\FrameworkBundle\\Command\\ContainerAwareCommand`,
14+
Symfony will even inject the container.
15+
While making life easier, this has some limitations:
16+
17+
* Your command must live in the ``Command`` directory;
18+
* There's no way to conditionally register your service based on the environment
19+
or availability of some dependencies;
20+
* You can't access the container in the ``configure()`` method (because
21+
``setContainer`` hasn't been called yet);
22+
* You can't use the same class to create many commands (i.e. each with
23+
different configuration).
24+
25+
To solve these problems, you can register your command as a service and tag it
26+
with ``console.command``:
27+
28+
.. configuration-block::
29+
30+
.. code-block:: yaml
31+
32+
# app/config/config.yml
33+
services:
34+
acme_hello.command.my_command:
35+
class: Acme\HelloBundle\Command\MyCommand
36+
tags:
37+
- { name: console.command }
38+
39+
.. code-block:: xml
40+
41+
<!-- app/config/config.xml -->
42+
<?xml version="1.0" encoding="UTF-8" ?>
43+
<container xmlns="http://symfony.com/schema/dic/services"
44+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
45+
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
46+
47+
<services>
48+
<service id="acme_hello.command.my_command"
49+
class="Acme\HelloBundle\Command\MyCommand">
50+
<tag name="console.command" />
51+
</service>
52+
</services>
53+
</container>
54+
55+
.. code-block:: php
56+
57+
// app/config/config.php
58+
$container
59+
->register('acme_hello.command.my_command', 'Acme\HelloBundle\Command\MyCommand')
60+
->addTag('console.command')
61+
;
62+
63+
Using Dependencies and Parameters to Set Default Values for Options
64+
-------------------------------------------------------------------
65+
66+
Imagine you want to provide a default value for the ``name`` option. You could
67+
pass one of the following as the 5th argument of ``addOption()``:
68+
69+
* a hardcoded string;
70+
* a container parameter (e.g. something from parameters.yml);
71+
* a value computed by a service (e.g. a repository).
72+
73+
By extending ``ContainerAwareCommand``, only the first is possible, because you
74+
can't access the container inside the ``configure()`` method. Instead, inject
75+
any parameter or service you need into the constructor. For example, suppose you
76+
have some ``NameRepository`` service that you'll use to get your default value::
77+
78+
// src/Acme/DemoBundle/Command/GreetCommand.php
79+
namespace Acme\DemoBundle\Command;
80+
81+
use Acme\DemoBundle\Entity\NameRepository;
82+
use Symfony\Component\Console\Command\Command;
83+
use Symfony\Component\Console\Input\InputInterface;
84+
use Symfony\Component\Console\Input\InputOption;
85+
use Symfony\Component\Console\Output\OutputInterface;
86+
87+
class GreetCommand extends Command
88+
{
89+
protected $nameRepository;
90+
91+
public function __construct(NameRepository $nameRepository)
92+
{
93+
$this->nameRepository = $nameRepository;
94+
}
95+
96+
protected function configure()
97+
{
98+
$defaultName = $this->nameRepository->findLastOne();
99+
100+
$this
101+
->setName('demo:greet')
102+
->setDescription('Greet someone')
103+
->addOption('name', '-n', InputOption::VALUE_REQUIRED, 'Who do you want to greet?', $defaultName)
104+
;
105+
}
106+
107+
protected function execute(InputInterface $input, OutputInterface $output)
108+
{
109+
$name = $input->getOption('name');
110+
111+
$output->writeln($name);
112+
}
113+
}
114+
115+
Now, just update the arguments of your service configuration like normal to
116+
inject the ``NameRepository``. Great, you now have a dynamic default value!
117+
118+
.. caution::
119+
120+
Be careful not to actually do any work in ``configure`` (e.g. make database
121+
queries), as your code will be run, even if you're using the console to
122+
execute a different command.

cookbook/console/console_command.rst

+4-48
Original file line numberDiff line numberDiff line change
@@ -65,55 +65,11 @@ This command will now automatically be available to run:
6565
.. _cookbook-console-dic:
6666

6767
Register Commands in the Service Container
68-
------------------------------------------
69-
70-
.. versionadded:: 2.4
71-
Support for registering commands in the service container was added in
72-
version 2.4.
73-
74-
Instead of putting your command in the ``Command`` directory and having Symfony
75-
auto-discover it for you, you can register commands in the service container
76-
using the ``console.command`` tag:
77-
78-
.. configuration-block::
79-
80-
.. code-block:: yaml
81-
82-
# app/config/config.yml
83-
services:
84-
acme_hello.command.my_command:
85-
class: Acme\HelloBundle\Command\MyCommand
86-
tags:
87-
- { name: console.command }
88-
89-
.. code-block:: xml
90-
91-
<!-- app/config/config.xml -->
92-
<?xml version="1.0" encoding="UTF-8" ?>
93-
<container xmlns="http://symfony.com/schema/dic/services"
94-
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
95-
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
96-
97-
<service id="acme_hello.command.my_command"
98-
class="Acme\HelloBundle\Command\MyCommand">
99-
<tag name="console.command" />
100-
</service>
101-
</container>
102-
103-
.. code-block:: php
104-
105-
// app/config/config.php
106-
107-
$container
108-
->register('acme_hello.command.my_command', 'Acme\HelloBundle\Command\MyCommand')
109-
->addTag('console.command')
110-
;
111-
112-
.. tip::
68+
-------------------------------------------
11369

114-
Registering your command as a service gives you more control over its
115-
location and the services that are injected into it. But, there are no
116-
functional advantages, so you don't need to register your command as a service.
70+
Just like controllers, commands can be declared as services. See the
71+
:doc:`dedicated cookbook entry </cookbook/console/commands_as_services>`
72+
for details.
11773

11874
Getting Services from the Service Container
11975
-------------------------------------------

cookbook/console/index.rst

+1
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ Console
88
usage
99
sending_emails
1010
logging
11+
commands_as_services

cookbook/form/dynamic_form_modification.rst

+10-10
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ creating that particular field is delegated to an event listener::
9999
{
100100
$builder->add('price');
101101

102-
$builder->addEventListener(FormEvents::PRE_SET_DATA, function(FormEvent $event) {
102+
$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
103103
// ... adding the name field if needed
104104
});
105105
}
@@ -116,7 +116,7 @@ the event listener might look like the following::
116116
public function buildForm(FormBuilderInterface $builder, array $options)
117117
{
118118
// ...
119-
$builder->addEventListener(FormEvents::PRE_SET_DATA, function(FormEvent $event) {
119+
$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
120120
$product = $event->getData();
121121
$form = $event->getForm();
122122

@@ -249,7 +249,7 @@ Using an event listener, your form might look like this::
249249
->add('subject', 'text')
250250
->add('body', 'textarea')
251251
;
252-
$builder->addEventListener(FormEvents::PRE_SET_DATA, function(FormEvent $event) {
252+
$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
253253
// ... add a choice list of friends of the current application user
254254
});
255255
}
@@ -325,13 +325,13 @@ and fill in the listener logic::
325325

326326
$builder->addEventListener(
327327
FormEvents::PRE_SET_DATA,
328-
function(FormEvent $event) use ($user) {
328+
function (FormEvent $event) use ($user) {
329329
$form = $event->getForm();
330330

331331
$formOptions = array(
332332
'class' => 'Acme\DemoBundle\Entity\User',
333333
'property' => 'fullName',
334-
'query_builder' => function(EntityRepository $er) use ($user) {
334+
'query_builder' => function (EntityRepository $er) use ($user) {
335335
// build a custom query
336336
// return $er->createQueryBuilder('u')->addOrderBy('fullName', 'DESC');
337337

@@ -491,7 +491,7 @@ sport like this::
491491

492492
$builder->addEventListener(
493493
FormEvents::PRE_SET_DATA,
494-
function(FormEvent $event) {
494+
function (FormEvent $event) {
495495
$form = $event->getForm();
496496

497497
// this would be your entity, i.e. SportMeetup
@@ -556,7 +556,7 @@ The type would now look like::
556556
));
557557
;
558558

559-
$formModifier = function(FormInterface $form, Sport $sport = null) {
559+
$formModifier = function (FormInterface $form, Sport $sport = null) {
560560
$positions = null === $sport ? array() : $sport->getAvailablePositions();
561561

562562
$form->add('position', 'entity', array(
@@ -568,7 +568,7 @@ The type would now look like::
568568

569569
$builder->addEventListener(
570570
FormEvents::PRE_SET_DATA,
571-
function(FormEvent $event) use ($formModifier) {
571+
function (FormEvent $event) use ($formModifier) {
572572
// this would be your entity, i.e. SportMeetup
573573
$data = $event->getData();
574574

@@ -578,7 +578,7 @@ The type would now look like::
578578

579579
$builder->get('sport')->addEventListener(
580580
FormEvents::POST_SUBMIT,
581-
function(FormEvent $event) use ($formModifier) {
581+
function (FormEvent $event) use ($formModifier) {
582582
// It's important here to fetch $event->getForm()->getData(), as
583583
// $event->getData() will get you the client data (that is, the ID)
584584
$sport = $event->getForm()->getData();
@@ -730,7 +730,7 @@ all of this, use a listener::
730730

731731
public function buildForm(FormBuilderInterface $builder, array $options)
732732
{
733-
$builder->addEventListener(FormEvents::POST_SUBMIT, function($event) {
733+
$builder->addEventListener(FormEvents::POST_SUBMIT, function ($event) {
734734
$event->stopPropagation();
735735
}, 900); // Always set a higher priority than ValidationListener
736736

cookbook/security/voters_data_permission.rst

+5-4
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,6 @@ edit a particular object. Here's an example implementation:
6666
use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface;
6767
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
6868
use Symfony\Component\Security\Core\User\UserInterface;
69-
use Acme\DemoBundle\Entity\Post;
7069
7170
class PostVoter implements VoterInterface
7271
{
@@ -81,9 +80,11 @@ edit a particular object. Here's an example implementation:
8180
));
8281
}
8382
84-
public function supportsClass($obj)
83+
public function supportsClass($class)
8584
{
86-
return $obj instanceof Post;
85+
$supportedClass = 'Acme\DemoBundle\Entity\Post';
86+
87+
return $supportedClass === $class || is_subclass_of($class, $supportedClass);
8788
}
8889
8990
/**
@@ -92,7 +93,7 @@ edit a particular object. Here's an example implementation:
9293
public function vote(TokenInterface $token, $post, array $attributes)
9394
{
9495
// check if class of this object is supported by this voter
95-
if (!$this->supportsClass($post)) {
96+
if (!$this->supportsClass(get_class($post))) {
9697
return VoterInterface::ACCESS_ABSTAIN;
9798
}
9899

0 commit comments

Comments
 (0)