简体   繁体   English

在Symfony2中使用表单类型中的自定义服务

[英]Using a custom service in a form type in Symfony2

In my Symfony2 project, I need to produce a list of existing tables in a db. 在我的Symfony2项目中,我需要在db中生成现有表的列表。 Since not all tables are used as entities in my project, and the list itself needs to be a simple array and not an entity, I have written an sql statement for this. 由于并非所有表都用作项目中的实体,并且列表本身需要是一个简单的数组而不是实体,因此我为此编写了一个sql语句。 This sql-statement is embedded in a function in a custom service (and has been thoroughly tested). 此sql语句嵌入在自定义服务中的函数中(并已经过全面测试)。

Now, in a form type I would like to populate a field with the result array of the function mentioned above. 现在,在表单类型中,我想用上面提到的函数的结果数组填充一个字段。 These become the options the user can choose from. 这些成为用户可以选择的选项。

My question is how can I access the service in my form type? 我的问题是如何在表单类型中访问服务?

There is a simple solution, which is pure OOP, no framework specific config. 有一个简单的解决方案,它是纯OOP,没有特定于框架的配置。 Just inject manually your service instance into your form type instance, using the constructor: 只需使用构造函数将您的服务实例手动注入表单类型实例:

class SomeType extends AbstractType
{
    private $provider;

    public function __construct(DataBaseTableNameProvider $provider)
    {
        $this->provider = $provider;
    }

    public function buildForm(FormBuilder $builder, array $options)
    {
         $builder->add('tables', 'choices', array(
             'choices' => $this->provider->getTableNames(),
         ));
    }
}

Then, in your controller for exemple: 然后,在您的控制器中例如:

public function newAction()
{
     $form = $this->createForm(new SomeType($this->get('table_name_provider'));

     // more stuff
}

The exact same can be done using framework config, by following http://symfony.com/doc/2.0/cookbook/form/create_custom_field_type.html#creating-your-field-type-as-a-service . 使用框架配置可以完全相同,遵循http://symfony.com/doc/2.0/cookbook/form/create_custom_field_type.html#creating-your-field-type-as-a-service

The only difference is that it takes care about instanciating your type using DIC, and injecting the correct dependencies. 唯一的区别是它需要注意使用DIC实现类型的实例化,并注入正确的依赖项。 Then, you just need to modify your controller: 然后,您只需要修改您的控制器:

public function newAction()
{
     $form = $this->createForm('some_type_alias');

     // more stuff
}

example with translation service access in form type: 表单类型中的翻译服务访问示例:

your form type class: 你的表单类型:

class TaskType extends AbstractType {
    ....
    public function setDefaultOptions(OptionsResolverInterface $resolver) {
        $resolver->setDefaults(array(
            't' => 'Symfony\Bundle\FrameworkBundle\Translation\Translator',
        ));
    }  

    public function buildForm(FormBuilderInterface $builder, array $options) {
        $t = $options['t'];
        $t->trans('string to translate');
        ....
    }

controller: 控制器:

public function someAction() { 
    $form = $this->createForm(new TaskType(), 
                                $task, 
                                array('t' => $this->get('translator')));

Symfony Best Practices : Symfony最佳实践

You can also register your form type as a service. 您还可以将表单类型注册为服务。 This is only needed if your form type requires some dependencies to be injected by the container, otherwise it is unnecessary overhead and therefore not recommended to do this for all form type classes. 只有在表单类型需要容器注入某些依赖项时才需要这样做,否则这是不必要的开销,因此不建议对所有表单类型类执行此操作。

# src/AppBundle/Resources/config/services.yml
services:
    app.form.type.gender:
        class: AppBundle\Form\Type\ SomeType
        arguments:
            - "@app.table_name_provider"
        tags:
            - { name: form.type }
$form = $this->createForm(SomeType::class)

Update for Symfony 3.X, you have two options now... 更新Symfony 3.X,你现在有两个选择......

Sending the services through the options 通过选项发送服务

public function configureOptions(OptionsResolver $resolver)
{
    $resolver->setRequired('option_key');
}

Then pass it through the controller 然后将其传递给控制器

$form = $this->createForm(XXXType::class, $entity, array(
    'option_key' => $this->get('service_you_want_to_call')
));

Define your form as a service 将表单定义为服务

This option is cleaner IMO, and you don't have to send the option everywhere you call the form 此选项是更清晰的IMO,您无需在调用表单的任何位置发送选项

class XXXType extends AbstractType
{
    private $service;

    public function __construct(ServiceType $service)
    {
        $this->service = $service;
    }

And then defining the service in the config 然后在配置中定义服务

services:
    app.form.type.XXX:
        class: AppBundle\Form\XXXType
        arguments: ['@service_you_want_to_call']
        tags:
            - { name: form.type }

Every time you call the form with 每次你打电话给表格

$this->createForm(XXXType::class, $data, $options)

Symfony will be smart enough to know that it has to use that service arguments (it knows it because the form.type tag), so you won't need to pass any data to the constructor anymore. Symfony足够聪明,知道它必须使用该服务参数(它知道它因为form.type标签),所以你不需要再将任何数据传递给构造函数。

Symfony docs: How to Access Services or Config from Inside a Form Symfony docs:如何从表单内部访问服务或配置

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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