我有一个用于插入实体类别的表单。该实体有两个与之相关的其他实体。 一个相关实体是另一个单独的实体组。另一个实体本身是自引用的类别,它是一个表示前提条件的数组集合。到目前为止,我可以坚持使用正确的ORM注释与主要实体保持联系。
类别
的粗略方案我创建了一个类型类来创建表单,如文档中描述的最佳实践。
$form = $this->createForm(new CategoryType($em));
在我坚持实体之前,我必须初始化它并将发布的数据设置为它。发布的相关对象不能简单地设置为持久化实体,因为它们具有错误的数据类型。 (例如,自引用集合仅作为具有id的数组发布,而不是所选项目的数组集合。) 因此,我捕获这些原始数据,并从实体管理器中单独获取相关实体。
插入实体应自动填充相关实体,whitout通过实体管理器单独获取
这是表单组件的含义,这些相关对象是否未发布并完全可用?或者我的实施中缺少什么? 有没有办法更自动化?
在'preconditions'属性的表单类上,我必须执行mapped => false
否则我会收到一个错误类型被传递的异常。但最后我希望表单通过映射自动匹配,whitout跳过映射,以及whitout将相关实体与实体管理器分开。
class CategoryType extends AbstractType
{
public function __construct($em)
{
$this->em = $em;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$qb = $this->em->createQueryBuilder();
$categories = $qb->select('e.id, e.title')
->from('MyvendorCoreBundle:Category', 'e')
->indexBy('e', 'e.id')
->orderBy('e.title')
->getQuery()
->getResult();
$categories_choice = array_map(function ($value) {
return $value['title'];
}, $categories);
$builder->add('title')
->add('group_Id', new GroupType($this->em))
->add('preconditions', 'choice', array(
'choices' => $categories_choice,
'multiple' => true,
'mapped' => false
))
->add('save', 'submit');
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Myvendor\CoreBundle\Entity\Category'
));
}
public function getName()
{
return 'category';
}
}
控制器方法
public function newAction(Request $request)
{
$em = $this->getDoctrine()->getManager();
$form = $this->createForm(new CategoryType($em));
// Repopulating the form after submission
$form->handleRequest($request);
// Prepare a new empty Category
$category = new Category();
if ($form->isValid()) {
/* Catch some raw datas posted from the form */
// Posted precondition category ids to get its entities more later
$precondition_category_ids = $form->get('preconditions')->getData();
// Posted group entity that have only filled the group id in the object
$group_raw = $form->get('group_Id')->getData();
// Get the explicit filled group entity throuth the posted id.
$group = $em->find('MyvendorCoreBundle:Group', $group_raw->getGroupid());
// Fill the prepaired group with the posted datas
$category->setTitle($form->get('title')->getData());
$category->setGroupId($group);
// Adding preconditions
try {
for ($i = 0; count($precondition_category_ids) > $i; $i ++) {
$precondition_category_id = $precondition_category_ids[$i];
if (0 >= $precondition_category_id) { // Retrieving id must be greater than 0
throw new \Exception('Error retrieving precondition id');
}
$precondition_category = $em->find('MyvendorCoreBundle:Category', $precondition_category_id);
if ($precondition_category instanceof Category) {
$category->addPrecondition($precondition_category);
} else {
throw new \Exception('Error retrieving precondition as Myvendor\CoreBundle\Entity\Category');
}
}
$em->persist($category); // Insert the group item with its relations
$em->flush();
echo '<h1 style="color:green">persisted</h1>';
} catch (\Exception $e) {
echo '<h1 style="color:red">' . $e->getMessage() . '</h1>';
}
}
return $this->render('MyvendorCoreBundle:fbm:new.html.twig', array(
'form' => $form->createView()
));
}
GroupType
class GroupType extends AbstractType
{
public function __construct($em){
$this->em = $em;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$groups = $this->em->createQuery("
SELECT o.groupid, o.descr
FROM MyvendorCoreBundle:Group o
INDEX BY o.groupid
ORDER BY o.descr
")->getResult();
$groups_dropdown = array();
$groups_dropdown = array_map(function($value) { return $value['descr']; }, $groups);
$builder->add('groupid', 'choice', array(
'label' => false,
'choices' => $groups_dropdown,
'attr' => array('style' => 'width: 300px')
));
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Myvendor\CoreBundle\Entity\Group',
));
}
public function getName()
{
return 'group';
}
}
/**
* @ORM\Entity
* @ORM\Table(name="category")
*/
class Category
{
public function __construct()
{
$this->preconditions = new ArrayCollection();
}
/**
* @ORM\Column(type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @var \Myvendor\CoreBundle\Entity\Group
*
* @Assert\Type(type="Myvendor\CoreBundle\Entity\Group")
* @Assert\Valid()
* @ORM\ManyToOne(targetEntity="Myvendor\CoreBundle\Entity\Group", inversedBy="Category")
* @ORM\JoinColumn(name="group_id", nullable=false, referencedColumnName="groupid")
*/
private $group_Id;
/**
* @var string
* @Assert\NotBlank()
* @ORM\Column(type="string", length=255, nullable=false)
*/
private $title;
/**
* Preconditions are Categorys referencing to an Category.
* For a single Category its empty (which have no subelements).
* A join table holds the references of a main Category to its sub-Categorys (preconditions)
*
* @ORM\ManyToMany(targetEntity="Category")
* @ORM\JoinTable(name="category_precondition",
* joinColumns={@JoinColumn(name="category_id", referencedColumnName="id")},
* inverseJoinColumns={@JoinColumn(name="category_precondition_id", referencedColumnName="id")}
* )
*/
private $preconditions;
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set title
*
* @param string $title
*
* @return Category
*/
public function setTitle($title)
{
$this->title = $title;
return $this;
}
/**
* Get title
*
* @return string
*/
public function getTitle()
{
return $this->title;
}
/**
* Set groupId
*
* @param \Myvendor\CoreBundle\Entity\Group $groupId
*
* @return Category
*/
public function setGroupId(\Myvendor\CoreBundle\Entity\Group $groupId)
{
$this->group_Id = $groupId;
return $this;
}
/**
* Get groupId
*
* @return \Myvendor\CoreBundle\Entity\Group
*/
public function getGroupId()
{
return $this->group_Id;
}
/**
* Add precondition
*
* @param \Myvendor\CoreBundle\Entity\Category $precondition
*
* @return $this
*/
public function addPrecondition(\Myvendor\CoreBundle\Entity\Category $precondition)
{
$this->preconditions[] = $precondition;
return $this;
}
/**
* Get preconditions
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getPreconditions()
{
return $this->preconditions;
}
/**
* Group
*
* @ORM\Table(name="group", indexes={@ORM\Index(name="homepage", columns={"homepage"}), @ORM\Index(name="theme", columns={"theme"})})
* @ORM\Entity
*/
class Group
{
/**
* @var string
*
* @ORM\Column(name="descr", type="string", length=60, nullable=true)
*/
private $descr;
/**
* @var integer
*
* @Assert\NotBlank()
* @ORM\Column(name="groupid", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="IDENTITY")
*/
public $groupid;
/**
* Set descr
*
* @param string $descr
* @return Group
*/
public function setDescr($descr)
{
$this->descr = $descr;
return $this;
}
/**
* Get descr
*
* @return string
*/
public function getDescr()
{
return $this->descr;
}
/**
* Get groupid
*
* @return integer
*/
public function getGroupid()
{
return $this->groupid;
}
}
答案 0 :(得分:0)
解决方案是选择实体的类型必须不是选择列表,而是真正的集合类型。
所以使用这样的东西
->add('preconditions', 'collection', array(
'entry_type' => 'entity',
'entry_options' => array(
'class' => 'MyVendorCoreBundle:EduStructItem',
'choice_label' => 'title'
),
'allow_add' => true,
'allow_delete' => true
))
而不是
->add('preconditions', 'choice', array(
'choices' => $categories_choice,
'multiple' => true,
'mapped' => false
))