将 EntityManager 从 EntityType 传递到另一个 EntityType
passing the EntityManager from an EntityType to another EntityType
我正在使用 Symfony 3.3。
- 摘要:
我有一个必须在控制器中验证的表单,验证中使用的实体包含 ArrayCollection 属性,这意味着我将使用 2 个 EntityType classes 验证嵌入表单(父类的 CollectionType 为子类)。
问题是:我想在验证之前通过 OptionResolver 将 EntityManager 对象传递给子 EntityType 以编辑表单数据。
所以,我必须通过 2 个步骤将 EntityManager 对象从 Controller 传递到 ChildType:
- 从 Controller 到 ParentType:成功完成
- 从 ParentType 到 ChildType :我收到一个错误(见下文)
- 详情:
在控制器中:
public function postAssignmentAction(Request $request)
{
$result = new Assignments();
$em = $this->get('doctrine.orm.entity_manager');
$form = $this->createForm(AssignmentsType::class, $result, array(
'validation_groups' => array('Creation', 'Default'),
'em' => $em,
));
$form->submit($request->request->all()["assignments"]);
//validation ...
}
在 ParentType (AssignmentsType) 中:
class AssignmentsType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
//dump($options['em']); //this line works fine and it dump the EntityManager
$builder->add('assignments', CollectionType::class,array(
'entry_type' => AssignmentType::class,
'required'=> true,
'allow_add' => true,
'by_reference' => false,
'em' => $options['em'] //without this line, there is no error if we delete the ChildType (AssignmentType)
);
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => 'Empire\UniversityBundle\Entity\Assignments',
'cascade_validation' => true,
'error_bubbling' => false,
'em' => null,
]);
$resolver->setRequired('em');
}
}
到现在为止,如果我们从之前的代码中删除这一行 : ('em' => $options['em']) 没有错误。
如果我在将选项从 ParentType 传递到 ChildType 时重复相同的操作,就像我们在 ParentType 中所做的那样,我会收到错误消息(如下)。
让我们以 ChildType 结束 class:
class AssignmentType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
dump($options['em']); //this line can't be executed because of the error
$this->em = $options['em'];
$builder->add('full_name');
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => 'Empire\UniversityBundle\Entity\Assignment',
'validation_groups' => array('Creation', 'Default'),
'cascade_validation' => true,
'error_bubbling' => false,
'em' => null,
]);
$resolver->setRequired('em');
}
}
所以在 ParentType 中,使用 ParentType:buildForm() 的选项:
public function buildForm(FormBuilderInterface $builder, array $options){
$builder->add('assignments', CollectionType::class,array(
'entry_type' => AssignmentType::class,
'required'=> true,
'allow_add' => true,
'by_reference' => false,
'em' => $options['em']
);
}
- 错误部分
我收到这个错误:
"message": "The option \"em\" does not exist. Defined options are: \"action\", \"allow_add\", \"allow_delete\", \"allow_extra_fields\", \"attr\", \"auto_initialize\", \"block_name\", \"by_reference\", \"compound\", \"constraints\", \"csrf_field_name\", \"csrf_message\", \"csrf_protection\", \"csrf_token_id\", \"csrf_token_manager\", \"data\", \"data_class\", \"delete_empty\", \"disabled\", \"empty_data\", \"entry_options\", \"entry_type\", \"error_bubbling\", \"error_mapping\", \"extra_fields_message\", \"horizontal_input_wrapper_class\", \"horizontal_label_class\", \"horizontal_label_offset_class\", \"inherit_data\", \"invalid_message\", \"invalid_message_parameters\", \"label\", \"label_attr\", \"label_format\", \"label_render\", \"mapped\", \"method\", \"post_max_size_message\", \"property_path\", \"prototype\", \"prototype_data\", \"prototype_name\", \"required\", \"sonata_admin\", \"sonata_field_description\", \"sonata_help\", \"translation_domain\", \"trim\", \"upload_max_size_message\", \"validation_groups\".",
"class": "Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException",
即使在 ChildType:configureOptions() 方法中定义了 "em" 选项之后:
$resolver->setDefaults([
'data_class' => 'Empire\UniversityBundle\Entity\Assignment',
'cascade_validation' => true,
'error_bubbling' => false,
'em' => null,
]);
$resolver->setRequired('em');
我不知道为什么第一步(将 EntityManager 从 Controller 传递到 ParentType)有效
但是在第二步中(将EntityManager从ParentType传递给ChildType),它不起作用
有关实体的更多详细信息,您可以在此处找到实体 classes:
赋值:是具有这些属性的子实体
- 姓名
- 描述
Assignments : 是具有此属性的父实体
-赋值:"Assignment" 个实体的 ArrayCollection
否则,是否有任何解决方案可以在 ChildType 中传递 EntityManager ?我的意思是没有任何技巧,例如使用变量 $options["label"] 或 $options["attr"]
非常感谢您的任何建议。
- Github 讨论问题:https://github.com/symfony/symfony/issues/25675
此致
在 symfony 3.3 文档中
If you need to access services from your form class, add a __construct() method like normal:
class AssignmentsType extends AbstractType
{
private $em;
public function __construct(EntityManagerInterface $entityManager)
{
$this->em = $entityManager;
}
...
..
.
If you're using the default services.yml configuration (i.e. services from the Form/ are loaded and autoconfigure is enabled), this will already work!
If you're not using autoconfigure, make sure to tag your service with form.type.
我问了一个关于从一个 EntityType 到另一个 EntityType 的对象(不是特定的像 EntityManager 实例这样的服务,它在任何地方都具有相同值的服务)的一般性问题:github.
经过一些研究后,我找到了我在此处发布的最佳解决方案 github answer。
我在 ParentType 的 buildForm:add() 方法的第三个参数中使用同一行 "custom_option" 将对象从 ParentType 传递到 ChildType 是错误的。因为 ParentType class 包含一个嵌入表单,并且要将任何选项(甚至是自定义选项)传递给 ChildType,该选项应该位于 buildForm:add 的第三个参数的 'entry_options' 行中().否则选项将被发送到 CollectionType 而不是 ChildType class.
参考:collection.html#entry-options
所以根据我第一个问题(本题)的代码修改后的ParentType应该是这样的:
class AssignmentsType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
//dump($options['em']); //this line works fine and it dump the object from the em option
$builder->add('assignments', CollectionType::class,array(
'entry_type' => AssignmentType::class,
'required'=> true,
'allow_add' => true,
'by_reference' => false,
'entry_options' => array('em' => $options['em']) ,// ->>>we modified this line <<<-
);
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => 'Empire\UniversityBundle\Entity\Assignments',
'cascade_validation' => true,
'error_bubbling' => false,
'em' => null,
]);
$resolver->setRequired('em');
}
}
此致
我正在使用 Symfony 3.3。
- 摘要:
我有一个必须在控制器中验证的表单,验证中使用的实体包含 ArrayCollection 属性,这意味着我将使用 2 个 EntityType classes 验证嵌入表单(父类的 CollectionType 为子类)。
问题是:我想在验证之前通过 OptionResolver 将 EntityManager 对象传递给子 EntityType 以编辑表单数据。
所以,我必须通过 2 个步骤将 EntityManager 对象从 Controller 传递到 ChildType:
- 从 Controller 到 ParentType:成功完成
- 从 ParentType 到 ChildType :我收到一个错误(见下文)
- 详情:
在控制器中:
public function postAssignmentAction(Request $request)
{
$result = new Assignments();
$em = $this->get('doctrine.orm.entity_manager');
$form = $this->createForm(AssignmentsType::class, $result, array(
'validation_groups' => array('Creation', 'Default'),
'em' => $em,
));
$form->submit($request->request->all()["assignments"]);
//validation ...
}
在 ParentType (AssignmentsType) 中:
class AssignmentsType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
//dump($options['em']); //this line works fine and it dump the EntityManager
$builder->add('assignments', CollectionType::class,array(
'entry_type' => AssignmentType::class,
'required'=> true,
'allow_add' => true,
'by_reference' => false,
'em' => $options['em'] //without this line, there is no error if we delete the ChildType (AssignmentType)
);
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => 'Empire\UniversityBundle\Entity\Assignments',
'cascade_validation' => true,
'error_bubbling' => false,
'em' => null,
]);
$resolver->setRequired('em');
}
}
到现在为止,如果我们从之前的代码中删除这一行 : ('em' => $options['em']) 没有错误。
如果我在将选项从 ParentType 传递到 ChildType 时重复相同的操作,就像我们在 ParentType 中所做的那样,我会收到错误消息(如下)。
让我们以 ChildType 结束 class:
class AssignmentType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
dump($options['em']); //this line can't be executed because of the error
$this->em = $options['em'];
$builder->add('full_name');
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => 'Empire\UniversityBundle\Entity\Assignment',
'validation_groups' => array('Creation', 'Default'),
'cascade_validation' => true,
'error_bubbling' => false,
'em' => null,
]);
$resolver->setRequired('em');
}
}
所以在 ParentType 中,使用 ParentType:buildForm() 的选项:
public function buildForm(FormBuilderInterface $builder, array $options){
$builder->add('assignments', CollectionType::class,array(
'entry_type' => AssignmentType::class,
'required'=> true,
'allow_add' => true,
'by_reference' => false,
'em' => $options['em']
);
}
- 错误部分
我收到这个错误:
"message": "The option \"em\" does not exist. Defined options are: \"action\", \"allow_add\", \"allow_delete\", \"allow_extra_fields\", \"attr\", \"auto_initialize\", \"block_name\", \"by_reference\", \"compound\", \"constraints\", \"csrf_field_name\", \"csrf_message\", \"csrf_protection\", \"csrf_token_id\", \"csrf_token_manager\", \"data\", \"data_class\", \"delete_empty\", \"disabled\", \"empty_data\", \"entry_options\", \"entry_type\", \"error_bubbling\", \"error_mapping\", \"extra_fields_message\", \"horizontal_input_wrapper_class\", \"horizontal_label_class\", \"horizontal_label_offset_class\", \"inherit_data\", \"invalid_message\", \"invalid_message_parameters\", \"label\", \"label_attr\", \"label_format\", \"label_render\", \"mapped\", \"method\", \"post_max_size_message\", \"property_path\", \"prototype\", \"prototype_data\", \"prototype_name\", \"required\", \"sonata_admin\", \"sonata_field_description\", \"sonata_help\", \"translation_domain\", \"trim\", \"upload_max_size_message\", \"validation_groups\".",
"class": "Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException",
即使在 ChildType:configureOptions() 方法中定义了 "em" 选项之后:
$resolver->setDefaults([
'data_class' => 'Empire\UniversityBundle\Entity\Assignment',
'cascade_validation' => true,
'error_bubbling' => false,
'em' => null,
]);
$resolver->setRequired('em');
我不知道为什么第一步(将 EntityManager 从 Controller 传递到 ParentType)有效
但是在第二步中(将EntityManager从ParentType传递给ChildType),它不起作用
有关实体的更多详细信息,您可以在此处找到实体 classes:
赋值:是具有这些属性的子实体
- 姓名
- 描述
Assignments : 是具有此属性的父实体
-赋值:"Assignment" 个实体的 ArrayCollection
否则,是否有任何解决方案可以在 ChildType 中传递 EntityManager ?我的意思是没有任何技巧,例如使用变量 $options["label"] 或 $options["attr"]
非常感谢您的任何建议。
- Github 讨论问题:https://github.com/symfony/symfony/issues/25675
此致
在 symfony 3.3 文档中
If you need to access services from your form class, add a __construct() method like normal:
class AssignmentsType extends AbstractType
{
private $em;
public function __construct(EntityManagerInterface $entityManager)
{
$this->em = $entityManager;
}
...
..
.
If you're using the default services.yml configuration (i.e. services from the Form/ are loaded and autoconfigure is enabled), this will already work!
If you're not using autoconfigure, make sure to tag your service with form.type.
我问了一个关于从一个 EntityType 到另一个 EntityType 的对象(不是特定的像 EntityManager 实例这样的服务,它在任何地方都具有相同值的服务)的一般性问题:github.
经过一些研究后,我找到了我在此处发布的最佳解决方案 github answer。
我在 ParentType 的 buildForm:add() 方法的第三个参数中使用同一行 "custom_option" 将对象从 ParentType 传递到 ChildType 是错误的。因为 ParentType class 包含一个嵌入表单,并且要将任何选项(甚至是自定义选项)传递给 ChildType,该选项应该位于 buildForm:add 的第三个参数的 'entry_options' 行中().否则选项将被发送到 CollectionType 而不是 ChildType class.
参考:collection.html#entry-options
所以根据我第一个问题(本题)的代码修改后的ParentType应该是这样的:
class AssignmentsType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
//dump($options['em']); //this line works fine and it dump the object from the em option
$builder->add('assignments', CollectionType::class,array(
'entry_type' => AssignmentType::class,
'required'=> true,
'allow_add' => true,
'by_reference' => false,
'entry_options' => array('em' => $options['em']) ,// ->>>we modified this line <<<-
);
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => 'Empire\UniversityBundle\Entity\Assignments',
'cascade_validation' => true,
'error_bubbling' => false,
'em' => null,
]);
$resolver->setRequired('em');
}
}
此致