我有一个实体项,它可以包含具有相同类项的项(前提条件)的集合。我使用this文档制作了collection
类型的表单。我想在文档中做几乎相同的事情。但我的情况是:
我的收集项目会自行引用主要项目
我想从现有列表中添加现有项目,而不是创建新项目
使用prototyping
,我正在添加一个新的选择集合项,其中JS具有相同的HTML结构,就像symfony表单中的默认重新填充一样。但自然会被替换的选择关系ID。
坚持关系是有效的,但只有手动破解,并且 $ form 对象中缺少数据。
当我使用js prototyping
添加关系并发布数据时,会在ArrayCollection中添加具有正确 Item 类的新实体。这个新实体返回的是已发布的ID作为ArrayCollection项的键,但是一个空实体本身作为值。 (新的一个是下面的密钥1)
#collection: ArrayCollection {#829 ▼
-elements: array:2 [▼
5 => Item {#834 ▼
#id: 5
-title: "foo"
+preconditions: PersistentCollection {#836 ▶}
}
1 => Item {#890 ▼
#id: null
-title: null
+preconditions: ArrayCollection {#886 ▶}
}
]
}
问题1:这导致持久存在一个未知的新实体想要插入(因为DB中不存在ID为null的实体),然后是无效的空数据。它不能插入,因为它实际上已经存在。
问题2:在持久化之前我必须手动修改ArrayCollection属性,我必须重新填充无效实体。因此条目对于持久关系有效。
问题3:当我以这种方式修改ArrayCollection时,我需要这个数据也可以在twig中访问。而对 $ form 的更新将导致异常,即我无法在提交后修改 $ form 。然后我看到了here一个事件监听器的建议,但即使有一个事件监听器我也不能'更新 $ form 因为 $ form 没有准备好或者为时已晚,无法更新。
是按照正确的方式来实现我的目标,还是确实存在更好的变体?
如何在帖子后正确填充ArrayCollection中的新实体?
控制器:
public function newesiAction($id, Request $request)
{
$em = $this->getDoctrine()->getManager();
// For repopulating an existing entity
$item = 0 < $id ? $em->getRepository('AppBundle:Item')->find($id) : new Item();
$form = $this->createForm(new ItemType($this->container), $item);
$form->add('submit', 'submit', array('label' => 'speichern'));
$form->handleRequest($request);
/* After handleRequest, the posted (also new) precondition entities are given. But not as expected. So we update the array collection.
* Not as expected meant: New relation entities becomes new entities with NULL as id. So entities with NULL as id wantet to be INSERTED, what is not our goal.
*/
foreach($item->preconditions as $precondition_entity_id => $precondition_entity) {
$precondition_entity_inner_id = $precondition_entity->getId();
if(null === $precondition_entity_inner_id) {
$item->preconditions[$precondition_entity_id] = $em->getRepository('AppBundle:Item')->find($precondition_entity_id);
}
}
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($item);
$em->flush();
}
return $this->render('AppBundle:Item:edit.html.twig', array(
'form' => $form->createView(),
));
}
的ItemType:
<?php
// src/AppBundle/Form/Type/ItemType.php
namespace AppBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormEvent;
class ItemType extends AbstractType
{
public function __construct($container) {
$this->container = $container;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('title');
$builder->add('preconditions', 'collection', array(
'type' => new PreconditionType(),
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
));
$builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) {
// $em = $this->container->get('doctrine')->getManager();
// $form = $event->getForm();
// // Replace the new related entity that have NULL in its ID, with an fully loaded entity
// $entity = $event->getData();
// foreach($entity->preconditions as $precondition_entity_id_posted => $possible_empty_entity) {
// $precondition_entity_id_loaded = $possible_empty_entity->getId();
// if(null === $precondition_entity_id_loaded) {
// $entity->preconditions[$precondition_entity_id_posted] = $em->getRepository('AppBundle:Item')->find($precondition_entity_id_posted);
// }
// }
// $form->get('preconditions')->setData($entity->preconditions);
});
$builder->add('available_items', 'entity', array(
'class' => 'AppBundle\Entity\Item',
'multiple' => true,
'expanded' => false,
'mapped' => false
));
$builder->add('add_item_precondition', 'button', array(
'attr' => array(
'onclick' => "addPreconditionForm('" . $this->getName() . "_available_items')"
)
));
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Item',
));
}
public function getName()
{
return 'item';
}
}
?>
前提条件类型:
<?php
// src/AppBundle/Form/Type/PreconditionType.php
namespace AppBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class PreconditionType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('relation', 'hidden', array(
'mapped' => false,
'required' => false
));
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Item'
));
}
public function getName()
{
return 'precondition';
}
}
?>
答案 0 :(得分:1)
我有可能与sensiolabs的员工讨论这个问题。它正式无法使用内置工具自动执行此操作,您必须循环收集条目并重新获取不完整的实体。
所以我的问题的答案: