Reputation: 48899
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;
}
}
Upvotes: 13
Views: 15477
Reputation: 394
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, i.e.
$form = $this->createForm(new CustomerType(), $customer);
Since the container is available in your controller, you could pass it directly to your form type, i.e.
$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.
Upvotes: 5
Reputation: 15082
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.
Upvotes: 29