I have the following tables: films, categories, films_categories and the entities:
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;
}
/* ... */
}
What I want to do is create a form and the action to add a new film and assign a category to it. Here is the form I used:
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',
)
));
}
}
The 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
}
}
The result is various errors and and ORMExcption with the message "Found entity of type on association Admin\Entity\Film#categories, but expecting Admin\Entity\Category"
Please help me out, I'm literally freaking out over this! Thank you :)
From what i found out from this is some thing like this that your entity is receiving Admin\Entity\Film#categories and in this part categories is some what a value. Where as your entity is expecting an object of type Admin\Entity\Film#categories.
To get over this you have to create a
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);
}
And then in your Action you have to pass object of Category to Film Entity in some thing like this
$Film->SetCategory($categoryObj);
Of course you have to set your business logic according to your part, but this error Should be removed by this apporach.