我有以下表格:电影、类别、电影_类别和实体:
电影.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);
}
}
}
类别.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,
),
);
}
}
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',
)
));
}
}
添加操作:
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”
请帮帮我,我真的被这个吓坏了!谢谢你:)
据我所知,您的实体正在接收类似的东西Admin\Entity\Film#categories,在这一部分中,类别具有一定的价值。您的实体需要一个类型为 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);
}
然后在你的操作中,你必须将Category的对象传递给Film实体,就像这样
$Film->SetCategory($categoryObj);
当然你必须根据你的部分设置你的业务逻辑,但是这个错误应该被这个方法删除。
您需要为目标实体定义 FQCN。
改变:
* @ORM\ManyToMany(targetEntity="Category")
至:
* @ORM\ManyToMany(targetEntity="Admin\Entity\Category")
这与水合作用和延迟加载有关。 我不是这方面的专家,但是 #categories 是一个代理对象,当您要保存它时,它会抱怨,因为它需要是一个实际的集合,而不是集合的代理对象。
如果您采用了 noobie-php 的方法,您将在主对象上重新附加新的类别对象,因此它们不再是代理。
这令人沮丧,因为 Doctrine 本来应该避免很多麻烦,但在很多情况下它实际上并没有达到您自然期望的效果。 我前段时间发现了一个关于此问题的错误票,但现在找不到它 - 如果我能找到它,我会将其添加到此。