Zend Framework 2 Doctrine 2多对多实体关系问题

时间:2013-07-21 14:38:30

标签: doctrine-orm many-to-many entity zend-framework2

我有以下表格:电影,类别,电影_类别和实体:

Film.php

    <?php

namespace Admin\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Table(name="films")
 */
class Film{

    /**
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     * @ORM\Column(type="integer")
     * @ORM\Column(length=11)
     */
    private $id;

    /**
     * @ORM\Column(type="string")
     */
    private $name;

    /* .... */

    /**
     * @ORM\ManyToMany(targetEntity="Category")
     * @ORM\JoinTable(name="films_categories", 
     *              joinColumns={@ORM\JoinColumn(name="film_id", referencedColumnName = "id")}, 
     *              inverseJoinColumns={@ORM\JoinColumn(name="category_id", referencedColumnName="id")})
     */
    private $categories;

    public function __construct(){
        $this->categories = new ArrayCollection();
    }

    public function getCategoriesNames(){
        $names = array();
        foreach($this->categories as $category){
            $names[] = $category->getName();
        }   
        return $names;  
    }

    public function getId(){
        return $this->id;
    }

    public function setId($id){
        $this->id = $id;
    }

    /* ... */

    /**
     * @return Collection
     */
    public function getCategories(){
        return $this->categories;
    }

    public function addCategories(Collection $categories){
        foreach($categories as $category){
            $this->categories->add($category);
        }
    }

    public function removeCategories(Collection $categories){
        foreach($categories as $category){
            $this->categories->removeElement($category);
        }
    }
}

Category.php

<?php

namespace Admin\Entity;

use Doctrine\ORM\Mapping as ORM;


/**
 * @ORM\Table(name="categories")
 */
class Category {

    /**
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     * @ORM\Column(type="integer")
     */
    private $id;

    /* ... */   

    public function getId(){
        return $this->id;
    }

    public function setId($id){
        $this->id = $id;
    }

    /* ... */
}

我想要做的是创建一个表单以及添加新电影并为其分配类别的操作。这是我使用的表格:

FilmFieldset.php

<?php
namespace Admin\Form;

use Zend\Form\Fieldset;
use Zend\InputFilter\InputFilterProviderInterface;
use DoctrineORMModule\Stdlib\Hydrator\DoctrineEntity;
use Admin\Entity\Film;

class FilmFieldset extends Fieldset implements InputFilterProviderInterface{

    protected $entityManager;

    public function __construct($em){

        parent::__construct('film');


        $this->entityManager= $em;
        $this->setHydrator(new DoctrineEntity($em,'Admin\Entity\Film'))
            ->setObject(new Film());

        #$this->setAttribute('method','post');
        #$this->setAttribute('class','standardForm');

        $this->add(array(
            'name' => 'id',
            'type' => 'hidden'
        ));     

        /* ... */   

        $this->add(
            array(
                'type' => 'DoctrineModule\Form\Element\ObjectSelect',
                'name' => 'categories',
                'attributes' => array(
                    'multiple' => 'multiple',
                ),                
                'options' => array(
                    'object_manager' => $em,
                    'target_class'   => 'Admin\Entity\Category',
                    'property'       => 'name',
                    'label'          => 'Categories: ',
                    'disable_inarray_validator' => true               
                ),
            )
        );                      

    }

    public function getInputFilterSpecification(){
        return array(
                    /* .... */
            'categories' => array(
                'required' => true,                 
            ),                  
        );  
    }

}

The FilmForm.php

<?php
namespace Admin\Form;

use Zend\Form\Form;
use Zend\Stdlib\Hydrator\ClassMethods;
use Admin\Entity\Film;
use Zend\InputFilter\InputFilter;
use DoctrineModule\Stdlib\Hydrator\DoctrineObject as DoctrineHydrator;

class FilmForm extends Form{

    public function __construct($em){
        parent::__construct('filmForm');

        $this->setAttribute('method','post')
             ->setAttribute('class','standardForm')
             ->setHydrator(new DoctrineHydrator($em,'\Admin\Entity\Film'))
             ->setInputFilter(new InputFilter());

            /* I register the fieldset through a service and not directly here */
        // $this->add(array(
            // 'type' => new FilmFieldset($em),
            // 'options' => array(
                // 'user_as_base_fieldset' => true
            // )
        // ));

        $this->add(array(
            'name' => 'security',
            'type' => 'Zend\Form\Element\Csrf'
        ));

        $this->add(array(
            'name' => 'submit',
            'type' => 'submit',
        ));

        $this->setValidationGroup(array(
            'security',
            'film' => array(
                'categories',
            )
        ));
    }


}

addAction:

public function addAction() {
    $em = $this->getEntityManager();
    $form = $this->getForm();
    $film = new Film();
        $form->bind($film);

    if($request->isPost()){
        $post = array_merge_recursive(
                    $request->getPost()->toArray(),
                    $request->getFiles()->toArray()
                );      
        $form->setData($post);
        if($form->isValid()){
            $categories = array();
            foreach($post['film']['categories'] as $categoryId){
                $categories[] = $em->getRepository('Admin\Entity\Category')->find($categoryId);
            }

            $film->addCategories($categories);

            $em->persist($film);
            $em->flush();
         }else{
             // the form is not valid
         }
    }

结果是各种错误和ORMExcption,消息“找到关联Admin \ Entity \ Film#categories上的类型实体,但期望Admin \ Entity \ Category”

请帮帮我,我真的很害怕!谢谢:))

3 个答案:

答案 0 :(得分:1)

从我发现的是这样的事情,你的实体正在接收管理员\实体\电影#类别,在这部分类别是一些价值。您的实体期望 Admin \ Entity \ Film#categories 类型的对象。

要克服这一点,你必须创建一个

 public function SetCategory(Admin\Entity\Category Category)
{
 $this->categories(or category or w/e your variable name is)= Category;
}
 public function getCategory()
{
 return $this->categories(or category or w/e your variable name is);
}

然后在你的行动中你必须将类别的对象传递给电影实体这样的事情

  $Film->SetCategory($categoryObj);

当然,您必须根据您的部分设置业务逻辑,但此错误应由此apporach删除。

答案 1 :(得分:0)

您需要为targetEntity定义FQCN。

变化:

* @ORM\ManyToMany(targetEntity="Category")

为:

* @ORM\ManyToMany(targetEntity="Admin\Entity\Category")

答案 2 :(得分:0)

这与水合和懒惰负荷有关。我不是这方面的专家,但#categories是一个代理对象,当你要保存它时,它会抱怨,因为它需要是一个真正的集合,而不是集合的代理对象。

如果您使用了noobie-php的方法,那么您将在主要对象上重新附加新的类别对象,因此它们不再是代理。

这令人沮丧,因为Doctrine本来应该省去很多麻烦,但实际上并没有做到你在许多情况下自然期望的事情。我前段时间发现了一张错误票,但现在找不到它 - 如果我能找到它就会加入它。