0

短篇小说:
我需要从一个不继承自 Controller 类的类中获取请求服务(它是一个 DataTransformer,它 - 显然 - 实现了 DataTransformerInterface)。

长话短说:
我有一个包含电子邮件字段的嵌入式表单。如果用户输入了我的用户数据库表中不存在的电子邮件,我想用这封电子邮件创建一个新用户。
为了做到这一点,我需要设置它的 IP,所以我遵循了嵌入式表单教程数据转换器配方,但最后我不知道在哪里可以将 Request 实例注入我的 DataTransformer 构造函数或其他东西。

如果我在一个从控制器扩展的类中,它会很简单:
$this->container->get('request')->getClientIp()

4

2 回答 2

3

您可以通过“引用(注入)服务”来做到这一点。在您的情况下,您想注入 Request ,它是来自较窄范围的服务

如果您正在使用转换器,您可能已经在使用自定义表单类型,并且正在您的表单类型BuildForm方法中实例化数据转换器,请参阅此处了解更多信息。

您想将 Request 对象注入自定义表单类型,然后可以将其作为构造函数参数传递给 Data Transformer。

为此,请修改services.yml您的包中的文件,并将构造函数添加到自定义表单类型和自定义数据转换器,如下所示:

// src/Acme/HelloBundle/Resources/config/services.yml
parameters:
    // ...    

services:
    acme.type.custom_type:
        class: Acme\HelloBundle\Form\Type\CustomType
        scope: request
        arguments: ["@doctrine.odm.mongodb.document_manager", "@request"]
        tags:
            - { name: form.type, alias: custom_type }

像这样更新 CustomType 类:

<?php
// src/Acme/HelloBundle/Form/Type/CustomType.php

namespace Acme\HelloBundle\Form\Type;

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Doctrine\ODM\MongoDB\DocumentManager;

use Acme\HelloBundle\Form\DataTransformer\CustomDataTransformer;

class CustomType extends AbstractType
{
    private $request;
    private $dm;

    public function __construct(DocumentManager $dm, Request $request) {
        $this->dm = $dm;
        $this->request = $request;
    }

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        // Create a new Data Transformer that will be able to use the Request Object!
        $transformer = new CustomDataTransformer($this->dm, $this->request);
        $builder->addModelTransformer($transformer);
    }
    // ...
}

最后向转换器添加一个构造函数,类似于在表单类型中添加的构造函数:

<?php
// src/Acme/HelloBundle/Form/DataTransformer/CustomDataTransformer.php

namespace Acme\HelloBundle\Form\DataTransformer;

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Form\DataTransformerInterface;
use Doctrine\ODM\MongoDB\DocumentManager;

class CustomDataTransformer implements DataTransformerInterface
{
    private $request;
    private $dm;

    public function __construct(DocumentManager $dm, Request $request) {
        $this->dm = $dm;
        $this->request = $request;
    }

    // ...
}

请注意,连同我已经注入 MongoDB DocumentManager 的请求,这是为了表明可以注入多个对象。

于 2013-09-18T19:47:20.430 回答
1

好的,这很简单:在我的问题中,我假设 DataTransformer 将被“神奇地”调用,但它在构建表单时被实例化,所以如果它对任何人都有帮助,这里是:

  1. 在 DataTransformer 类中(实现 DataTransformerInterface):

    1. 定义新的类属性以保存依赖注入:

      /**
       * @var EntityManager
       */
       private $entityManager;
      
      /**
      * @var \Symfony\Component\DependencyInjection\Container
      */
      private $container;
      
    2. 定义构造函数,如:

      public function __construct( EntityManager $entityManager, Container $container )
      {
          $this->entityManager = $entityManager;
          $this->container = $container;
      }
      
  2. 在您的表单类中(实现 AbstractType)

    1. 将以下调用添加到setDefaultOptions方法:

      $resolver->setRequired( array( 'em', 'container' ) );
      
      $resolver->setAllowedTypes( array(
                                   'em'        => 'Doctrine\Common\Persistence\ObjectManager',
                                   'container' => 'appDevDebugProjectContainer',
                              ) );
      
    2. buildForm方法中,应用变压器配方中定义的变压器,但将其实例化为:

      $entityManager = $options['em'];
      $container     = $options['container'];
      $transformer = new FantasticTransformer( $entityManager, $container );
      
  3. 在您的控制器中,当您调用createForm方法时,是否可以注入 EntityManager 和 Container 实例,只需按如下方式添加它们:

        $form = $this->createForm( 'your_form', $lookup, array(
                                                                'action' => $this->generateUrl( 'your_action_url' ),
                                                                'em' => $this->getDoctrine()->getManager(),
                                                                'container' => $this->container
                                                           ) );
    
  4. 现在,您终于可以从请求服务调用 DataTransformer 类的构造函数中定义的容器获取客户端 IP:

    $ip = $this->container->get('request')->getClientIp();
    

请注意,我们注入的是容器而不是请求实例,这是由于Symfony 作用域

于 2013-09-18T19:04:40.467 回答