Symfony2表单:自动保存相关对象

时间:2015-09-07 09:09:32

标签: php forms symfony entitymanager

我有一个用于插入实体类别的表单。该实体有两个与之相关的其他实体。 一个相关实体是另一个单独的实体。另一个实体本身是自引用的类别,它是一个表示前提条件的数组集合。到目前为止,我可以坚持使用正确的ORM注释与主要实体保持联系。

类别

的粗略方案
  • id:int
  • title:string
  • group:group obj
  • 前提条件:[类别obj,类别obj,...]

我创建了一个类型类来创建表单,如文档中描述的最佳实践。

$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;
    }
}

1 个答案:

答案 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
    ))