Как получить доступ к сервисам или конфигурации изнутри формы

Иногда вам может понадобиться получить доступ к сервису или другой конфигурации изнутри вашего класса формы. Чтобы сделать это, у вас есть 2 варианта:

1) Передать опции в вашу форму

Наиболее простой способ передать сервисы или конфигурацию в вашу форму - через опции форм. Представьте, что вам нужно получить доступ к менеджеру сущностей Doctrine, чтобы вы могли сделать запрос. Для начала, позвольте (на самом деле, потребуйте), чтобы новая опция entity_manager была передана в вашу форму:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// src/AppBundle/Form/TaskType.php
// ...

class TaskType extends AbstractType
{
    // ...

    public function configureOptions(OptionsResolver $resolver)
    {
        // ...

        $resolver->setRequired('entity_manager');
    }
}

Теперь, когда вы сделала это, вы должны передать опцию entity_manager при создании вашей формы:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
// src/AppBundle/Controller/DefaultController.php
use AppBundle\Form\TaskType;
use Doctrine\ORM\EntityManagerInterface;

// ...
public function newAction(EntityManagerInterface $em)
{
    // или вызвать их через контейнер
    // $em = $this->get('doctrine')->getManager();

    $task = ...;
    $form = $this->createForm(TaskType::class, $task, array(
        'entity_manager' => $em,
    ));

    // ...
}

Наконец, опция entity_manager доступна в аргументе $options вашего метода buildForm():

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// src/AppBundle/Form/TaskType.php
// ...

class TaskType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        /** @var \Doctrine\ORM\EntityManager $em */
        $em = $options['entity_manager'];
        // ...
    }

    // ...
}

Используйте этот метод, чтобы передать что угодно в вашу форму.

2) Определить вашу форму, как сервис

В качестве альтернативы, вы можете определить ваш класс формы, как сервис. Это хорошая идея, если вы хотите использовать форму повторно в нескольких местах - регистрация формы в качестве сервиса облегчает это.

Представьте, что вам нужно получить доступ к объекту EntityManager, чтобы вы могли сделать запрос. Для начала, добавьте это в качестве аргумента к вашему классу формы:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
// src/AppBundle/Form/TaskType.php

use Doctrine\ORM\EntityManagerInterface;
// ...

class TaskType extends AbstractType
{
    private $em;

    public function __construct(EntityManagerInterface $em)
    {
        $this->em = $em;
    }

    // ...
}

Если вы используете автомонтирование и автоконфигурацию, то вам больше ничего не нужно делать. Symfony автоматически передаст правильный объект EntityManager в ваш метод __construct().

Если вы не используете автомонтирование и автоконфигурацию, зарегистрируйте вашу форму, как сервис, вручную и тегируйте с помощью form.type:

  • YAML
    1
    2
    3
    4
    5
    # src/AppBundle/Resources/config/services.yml
    services:
        AppBundle\Form\TaskType:
            arguments: ['@doctrine.orm.entity_manager']
            tags: [form.type]
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    <!-- src/AppBundle/Resources/config/services.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="AppBundle\Form\TaskType">
                <argument type="service" id="doctrine.orm.entity_manager"/>
                <tag name="form.type" />
            </service>
        </services>
    </container>
    
  • PHP
    1
    2
    3
    4
    5
    6
    7
    8
    // src/AppBundle/Resources/config/services.php
    use AppBundle\Form\TaskType;
    use Symfony\Component\DependencyInjection\Reference;
    
    $container->register(TaskType::class)
        ->addArgument(new Reference('doctrine.orm.entity_manager'))
        ->addTag('form.type')
    ;
    

New in version 3.3: До Symfony 3.3, вам нужно было определять сервисы типа формы, как public. Начиная с Symfony 3.3, вы также можете определять их, как private.

Вот и всё! Ваш контроллер - где вы создали форму - не требует никаких изменений: Symfony достаточно умна, чтобы загружать TaskType из контейнера.

Смотрите Доступ к сервисам и конфигурации, чтобы получить больше информации.

Эта документация является переводом официальной документации Symfony и предоставляется по свободной лицензии CC BY-SA 3.0.