简体   繁体   中英

Can Symfony2 form event listener access the service container and how?

As per title, can a Symfony2 form event listener access the service container?

This is an example event listener (for post bind event):

class CustomerTypeSubscriber implements EventSubscriberInterface
{

    public static function getSubscribedEvents()
    {
        return array(FormEvents::POST_BIND => 'onPostBind');
    }

    public function onPostBind(DataEvent $event)
    {
        // Get the entity (Customer type)
        $data = $event->getData();

        // Get current user
        $user = null;    

        // Remove country if address is not provided
        if(!$data->getAddress()) :
            $data->setCountry(null);
        endif;
    }

}

What do you need to access to service container for?

You can inject any services into your listener using dependency injection (as you define your listener as a service, right?).

You should be able to do something like:

    service.listener:
    class: Path\To\Your\Class
    calls:
      - [ setSomeService, [@someService] ]
    tags:
      - { [Whatever your tags are] }

And in your listener:

private $someService;

public function setSomeService($service) {
    $this->someService = $someService;
}

Where someService is the ID of whatever service you want to inject.

If you want, you can inject the service container with @service_container, but it's probably better to inject only what you need 'cause I think having everything container aware makes you a bit lazy.

I think the way a Form Subscriber works is a little different to a regular Event Listener.

In your controller, you are instantiating your form type, ie

$form = $this->createForm(new CustomerType(), $customer);

Since the container is available in your controller, you could pass it directly to your form type, ie

$form = $this->createForm(new CustomerType($this->container), $customer);

In my case I needed the security context, so my implementation (similar but slightly different to your original q):

In my controller:

$form = $this->createForm(new CustomerType($this->get('security.context')), $customer));

In my Form class:

use Symfony\Component\Security\Core\SecurityContext;
class CustomerType extends AbstractType
{
    protected $securityContext;

    public function __construct(SecurityContext $securityContext)
    {
        $this->securityContext = $securityContext;
    }

    public function buildForm(FormBuilder $builder, array $options)
    {
        // Delegate responsibility for creating a particular field to EventSubscriber
        $subscriber = new CustomerAddSpecialFieldSubscriber($builder->getFormFactory(), $this->securityContext);
        $builder->addEventSubscriber($subscriber);
        $builder->add( ... the rest of my fields ... );
    }

    // other standard Form functions
}

And in my Form Subscriber

use Symfony\Component\Security\Core\SecurityContext;
CustomerAddSpecialFieldSubscriber
{
    private $factory;

    protected $securityContext;

    public function __construct(FormFactoryInterface $factory, SecurityContext $securityContext)
    {
        $this->factory = $factory;
        $this->securityContext = $securityContext;
    }

    public static function getSubscribedEvents()
    {
        return array(FormEvents::PRE_SET_DATA => 'preSetData');
    }

    public function preSetData(DataEvent $event)
    {
        if (true === $this->securityContext->isGranted('ROLE_ADMIN')) {
            // etc
        }
    }

}

Hope it helps.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM