Skip to content

Commit

Permalink
Merge branch '2.4'
Browse files Browse the repository at this point in the history
  • Loading branch information
weaverryan committed Mar 24, 2014
2 parents db1cda5 + b0e07b4 commit 72d40a8
Show file tree
Hide file tree
Showing 7 changed files with 144 additions and 65 deletions.
1 change: 0 additions & 1 deletion .travis.yml
Expand Up @@ -4,7 +4,6 @@ python:
- "2.7"

install:
- "git submodule update --init"
- "bash install.sh"
- "pip install -q -r requirements.txt --use-mirrors"

Expand Down
4 changes: 2 additions & 2 deletions book/installation.rst
Expand Up @@ -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
Expand All @@ -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

Expand Down
122 changes: 122 additions & 0 deletions cookbook/console/commands_as_services.rst
@@ -0,0 +1,122 @@
.. index::
single: Console; Commands as Services

How to Define Commands as Services
==================================

.. versionadded:: 2.4
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 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::

.. 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
<!-- app/config/config.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
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">
<services>
<service id="acme_hello.command.my_command"
class="Acme\HelloBundle\Command\MyCommand">
<tag name="console.command" />
</service>
</services>
</container>
.. code-block:: php
// app/config/config.php
$container
->register('acme_hello.command.my_command', 'Acme\HelloBundle\Command\MyCommand')
->addTag('console.command')
;
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()``:

* a hardcoded string;
* a container parameter (e.g. something from parameters.yml);
* a value computed by a service (e.g. a repository).

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;

use Acme\DemoBundle\Entity\NameRepository;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

class GreetCommand extends Command
{
protected $nameRepository;

public function __construct(NameRepository $nameRepository)
{
$this->nameRepository = $nameRepository;
}

protected function configure()
{
$defaultName = $this->nameRepository->findLastOne();

$this
->setName('demo:greet')
->setDescription('Greet someone')
->addOption('name', '-n', InputOption::VALUE_REQUIRED, 'Who do you want to greet?', $defaultName)
;
}

protected function execute(InputInterface $input, OutputInterface $output)
{
$name = $input->getOption('name');

$output->writeln($name);
}
}

Now, just update the arguments of your service configuration like normal to
inject the ``NameRepository``. Great, you now have a dynamic default value!

.. caution::

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.
52 changes: 4 additions & 48 deletions cookbook/console/console_command.rst
Expand Up @@ -65,55 +65,11 @@ This command will now automatically be available to run:
.. _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.

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:

.. 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
<!-- app/config/config.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
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">
<service id="acme_hello.command.my_command"
class="Acme\HelloBundle\Command\MyCommand">
<tag name="console.command" />
</service>
</container>
.. code-block:: php
// app/config/config.php
$container
->register('acme_hello.command.my_command', 'Acme\HelloBundle\Command\MyCommand')
->addTag('console.command')
;
.. 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.
Just like controllers, commands can be declared as services. See the
:doc:`dedicated cookbook entry </cookbook/console/commands_as_services>`
for details.

Getting Services from the Service Container
-------------------------------------------
Expand Down
1 change: 1 addition & 0 deletions cookbook/console/index.rst
Expand Up @@ -8,3 +8,4 @@ Console
usage
sending_emails
logging
commands_as_services
20 changes: 10 additions & 10 deletions cookbook/form/dynamic_form_modification.rst
Expand Up @@ -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
});
}
Expand All @@ -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();

Expand Down Expand Up @@ -249,7 +249,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
});
}
Expand Down Expand Up @@ -325,13 +325,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');

Expand Down Expand Up @@ -491,7 +491,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
Expand Down Expand Up @@ -556,7 +556,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(
Expand All @@ -568,7 +568,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();

Expand All @@ -578,7 +578,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();
Expand Down Expand Up @@ -730,7 +730,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

Expand Down
9 changes: 5 additions & 4 deletions cookbook/security/voters_data_permission.rst
Expand Up @@ -66,7 +66,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
{
Expand All @@ -81,9 +80,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);
}
/**
Expand All @@ -92,7 +93,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;
}
Expand Down

0 comments on commit 72d40a8

Please sign in to comment.