Подтвердить что ты не робот

Может ли Symfony2 сформировать прослушиватель событий для доступа к контейнеру сервиса и как?

Как в заголовке, может ли прослушиватель событий формы Symfony2 обращаться к контейнеру службы?

Это пример прослушивателя событий (для события post bind):

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;
    }

}
4b9b3361

Ответ 1

Что вам нужно для доступа к контейнеру службы?

Вы можете вводить любые услуги в ваш слушатель, используя инъекцию зависимостей (поскольку вы определяете своего слушателя как службу, правильно?).

Вы должны иметь возможность сделать что-то вроде:

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

И в вашем слушателе:

private $someService;

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

Где someService - это идентификатор любой услуги, которую вы хотите ввести.

Если вы хотите, вы можете ввести контейнер службы с помощью @service_container, но, вероятно, лучше ввести только то, что вам нужно, потому что я думаю, что все, что знает контейнер, делает вас немного ленивым.

Ответ 2

Я думаю, что способ работы Абонента формы немного отличается от обычного прослушивателя событий.

В вашем контроллере вы создаете экземпляр типа вашей формы, т.е.

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

Поскольку контейнер доступен в вашем контроллере, вы можете передать его непосредственно в ваш тип формы, т.е.

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

В моем случае мне нужен контекст безопасности, поэтому моя реализация (аналогичная, но немного отличающаяся от вашего оригинала q):

В моем контроллере:

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

В моем классе Form:

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
}

И в моем подписчике формы

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
        }
    }

}

Надеюсь, что это поможет.