Суть проблемы:
есть сущность Test:
<?php
namespace Acme\AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Acme\AppBundle\Entity\Breakagedemand;
/**
* Test
* @ORM\Table(name="test")
* @ORM\Entity
*/
class Test {
/**
* @var integer
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue
*/
private $id;
...
/********************************** collection of breakagedemand *************************************/
/**
* @ORM\OneToMany(targetEntity="Acme\AppBundle\Entity\Breakagedemand", mappedBy="test", cascade={"persist"})
*/
private $collection;
public function __construct()
{
$this->collection = new ArrayCollection();
}
public function getCollection()
{
return $this->collection;
}
public function addCollection( Breakagedemand $_item )
{
$this->collection->add( $_item );
$_item->addTest( $this );
}
public function removeCollection( $_item )
{
$this->collection->removeElement( $_item );
}
/********************************** collection of breakagedemand *************************************/
...
}
Объект с конкретным id (код из контроллера):
$em = $this->getDoctrine()->getManager();
$repo_test = $em->getRepository('Acme\AppBundle\Entity\Test');
$test = $repo_test->findOneBy( array( 'breakagedemands' => $id ) );
...
формирует соответствующие данные в форму коллекции TestType:
...
class TestType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder ->add( 'collection', 'collection', array(
'type' => new BreakagedemandType(),
'options' => array(
'required' => false
),
'prototype' => true,
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
'label' => 'Поломки',
'required' => true
) );
}
...
}
Коллекция в этой форме формируется внедренной формой BreakagedemandType:
...
class BreakagedemandType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add( 'posrepairs_id' , 'hidden')
->add( 'isrepeated' , 'hidden')
->add('posbreakage_id', 'entity', array(
'class' => 'Acme\AppBundle\Entity\Breakage',
'property' => 'name',
'label' => 'Поломка: '
)
);
}
...
}
Данные в форму BreakagedemandType поступают из сущности Breakagedemand:
/**
* Breakagedemand
* @ORM\Table(name="breakagedemand")
* @ORM\Entity
*/
class Breakagedemand {
/**
* @var integer
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue
*/
private $id;
...
/********************************* posbreakages *************************************/
/**
* @var integer
* @ORM\ManyToOne(targetEntity="Acme\AppBundle\Entity\Breakage", inversedBy="breakagedemands", cascade={"persist"})
* @ORM\JoinColumn(name="posbreakage_id", referencedColumnName="id")
*/
private $posbreakage_id;
/**
* Set posbreakage_id
* @param integer $posbreakageId
* @return Breakagedemand
*/
public function setPosbreakageId( $posbreakageId )
{
$this->posbreakage_id = $posbreakageId;
return $this;
}
/**
* Get posbreakage_id
* @return integer
*/
public function getPosbreakageId()
{
return $this->posbreakage_id;
}
/********************************* posbreakages *************************************/
/********************************* test collection *************************************/
/**
* @ORM\ManyToOne(targetEntity="Acme\AppBundle\Entity\Test", inversedBy="collection", cascade={"persist"})
* @ORM\JoinColumn(name="posrepairs_id", referencedColumnName="breakagedemand_id")
*/
private $test;
public function __construct()
{
$this->test = new ArrayCollection();
}
public function getTest()
{
return $this->test;
}
public function addTest( $_item )
{
if ( !$this->test->contains( $_item ) )
{
$this->test->add( $_item );
$_item->addCollection( $this );
}
}
/********************************* test collection *************************************/
}
А эта сущность Breakagedemand соответственно связана с сущностью Breakage (суть сущности Breakage в сути вопроса не важна). В итоге получаю такую форму:
По разделам руководства:
symfony.com/doc/2.3/reference/forms/types/collecti...
symfony.com/doc/2.3/cookbook/form/form_collections...
symfony.com/doc/2.3/cookbook/form/form_collections...
добавил в twig код js с jquery, а так же рекомендуемый код в контроллер (обозначен как "код для удаления связей между коллекцией и сущностью"):
...
public function testCollectionAction( $id, Request $request ){
$em = $this->getDoctrine()->getManager();
$repo_test = $em->getRepository('Acme\AppBundle\Entity\Test');
$test = $repo_test->findOneBy( array( 'breakagedemands' => $id ) );
/* код для удаления связей между коллекцией и сущностью */
$originalcols = new ArrayCollection();
foreach ( $test->getCollection() as $col ) {
$originalcols->add( $col );
}
/* код для удаления связей между коллекцией и сущностью */
$form = $this->createForm( new TestType(), $test );
$form->handleRequest( $request );
if ($form->isValid()) {
/* код для удаления связей между коллекцией и сущностью */
foreach ( $originalcols as $col ) {
if (false === $test->getCollection()->contains( $col )) {
$em->persist( $col );
$em->remove( $col );
}
}
/* код для удаления связей между коллекцией и сущностью */
$em->persist( $test );
$em->flush();
}
return $this->render('AcmeAppBundle:Forms:collection.html.twig', array(
'form' => $form->createView(),
)
);
}
В полученной форме в итоге все очень здорово редактируется (меняются типы поломок) с сохранением в БД и так же удаляются - в БД это все тоже отражается. Но не могу победить проблему добавления нового объекта в коллекцию и соответственно в БД. Сам процесс добавления:
и ошибка:
Found entity of type Doctrine\Common\Collections\ArrayCollection on association Acme\AppBundle\Entity\Breakagedemand#test, but expecting Acme\AppBundle\Entity\Test
Я понимаю, что доктрина ждет Breakagedemand, а подается Test.
Посмотрите, пожалуйста, код свежим взглядом, а то я, скорее всего, уже не замечаю какой-нить бяки в коде, скорее всего в маппинге связей. При добавлении объекта в коллекцию я проверяю состояние имеющихся сущностей через $em->getUnitOfWork()->getEntityState( $_item ) - говорит, что (это естественно) все имеющиеся объекты MANAGED, а добавленная - NEW.
Заранее спасибо за помощь.