从DataTransformer类获取请求服务

时间:2013-09-18 17:13:55

标签: php symfony

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

长篇故事:
我有一个包含电子邮件字段的嵌入式表单。如果用户输入了我的用户数据库表中不存在的电子邮件,我想用这封电子邮件创建一个新用户 为了做到这一点,我需要设置它的IP,所以我遵循embedded forms tutorialdata transformer recipe,但最后我不知道我能在哪里将Request实例注入我的DataTransformer构造函数或其他什么。

如果我在一个从控制器扩展的类中,它将如下所示: $this->container->get('request')->getClientIp()

2 个答案:

答案 0 :(得分:3)

您可以"Referencing (Injecting) Services"执行此操作。在您的情况下,您想要注入service from a narrower scope的请求。

如果您使用的是变换器,您可能已经在使用自定义表单类型,并在表单类型 BuildForm 方法中实例化数据变换器,有关详细信息,请参阅here

您希望将Request对象注入自定义Form Type,然后它可以作为构造函数参数传递给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);
    }
    // ...
}

最后添加一个构造函数到变换器,类似于Form Type中添加的构造函数:

<?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,这表明可以注入多个对象。

答案 1 :(得分:0)

好的,这很简单: 在我的问题中,我假设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 方法中,应用transformer recipe中定义的转换器,但将其实例化为:

      $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. 现在,您最终可以从请求服务调用客户端IP调用DataTransformer类的构造函数中定义的容器:

    $ip = $this->container->get('request')->getClientIp();
    
  5. 请注意,我们正在注入容器而不是请求实例,这是由于Symfony scopes