短篇小说:
我需要从一个不从Controller类继承的类中获取Request服务(它是一个DataTransformer,它显然实现了DataTransformerInterface)。
长篇故事:
我有一个包含电子邮件字段的嵌入式表单。如果用户输入了我的用户数据库表中不存在的电子邮件,我想用这封电子邮件创建一个新用户
为了做到这一点,我需要设置它的IP,所以我遵循embedded forms tutorial和data transformer recipe,但最后我不知道我能在哪里将Request实例注入我的DataTransformer构造函数或其他什么。
如果我在一个从控制器扩展的类中,它将如下所示:
$this->container->get('request')->getClientIp()
答案 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将被“神奇地”调用,但是在构建表单时它是实例化的,所以如果它对任何人都有帮助,那么它就是:
在DataTransformer类中(实现DataTransformerInterface):
定义新的类属性以保存依赖项注入:
/**
* @var EntityManager
*/
private $entityManager;
/**
* @var \Symfony\Component\DependencyInjection\Container
*/
private $container;
定义构造函数,如:
public function __construct( EntityManager $entityManager, Container $container )
{
$this->entityManager = $entityManager;
$this->container = $container;
}
在表单类中(实现AbstractType)
将以下调用添加到 setDefaultOptions 方法:
$resolver->setRequired( array( 'em', 'container' ) );
$resolver->setAllowedTypes( array(
'em' => 'Doctrine\Common\Persistence\ObjectManager',
'container' => 'appDevDebugProjectContainer',
) );
在 buildForm 方法中,应用transformer recipe中定义的转换器,但将其实例化为:
$entityManager = $options['em'];
$container = $options['container'];
$transformer = new FantasticTransformer( $entityManager, $container );
在您的控制器中,当您调用 createForm 方法时,是否可以注入EntityManager和Container实例,只需按如下方式添加它们:
$form = $this->createForm( 'your_form', $lookup, array(
'action' => $this->generateUrl( 'your_action_url' ),
'em' => $this->getDoctrine()->getManager(),
'container' => $this->container
) );
现在,您最终可以从请求服务调用客户端IP调用DataTransformer类的构造函数中定义的容器:
$ip = $this->container->get('request')->getClientIp();
请注意,我们正在注入容器而不是请求实例,这是由于Symfony scopes。