Answer the question
In order to leave comments, you need to log in
When editing a collection of entities, new entities are not saved - why?
The essence of the problem:
there is a Test entity:
<?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 *************************************/
...
}
$em = $this->getDoctrine()->getManager();
$repo_test = $em->getRepository('Acme\AppBundle\Entity\Test');
$test = $repo_test->findOneBy( array( 'breakagedemands' => $id ) );
...
...
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
) );
}
...
}
...
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' => 'Поломка: '
)
);
}
...
}
/**
* 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 *************************************/
}
...
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(),
)
);
}
Answer the question
In order to leave comments, you need to log in
Oh, well, you messed up here. How does it actually work?))
If done by your method, then the Test entity should look something like this:
/**
* Test
* @ORM\Table(name="test")
* @ORM\Entity
*/
class Test {
/**
* @var integer
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue
*/
private $id;
/**
* @ORM\OneToMany(targetEntity="Acme\AppBundle\Entity\Breakagedemand", mappedBy="test", cascade={"persist"})
*/
private $collection;
public function __construct()
{
$this->collection = new ArrayCollection();
}
...
public function addCollection( Breakagedemand $breakagedemand )
{
// Устанавливаем для каждого добавляемого в коллекцию элемента тест, к которому он относится
$breakagedemand->setTest($this);
// И только после этого добавляем его в коллекцию
$this->collection[] = $breakagedemand;
return $this;
}
...
}
/**
* Breakagedemand
* @ORM\Table(name="breakagedemand")
* @ORM\Entity
*/
class Breakagedemand {
/**
* @var integer
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue
*/
private $id;
// cascade={"persist"} тут не нужен, с этой стороны мы не будем редактировать сущность Breakage
// Название сущности выбрано неверное, так как тут не будет никакого ID, а будет экземпляр сущности Breakage
/**
* @var integer
* @ORM\ManyToOne(targetEntity="Acme\AppBundle\Entity\Breakage", inversedBy="breakagedemands")
* @ORM\JoinColumn(name="posbreakage_id", referencedColumnName="id")
*/
private $posbreakage;
// cascade={"persist"} тут не нужен, с этой стороны вы тест добавлять никогда не будете
// referencedColumnName="id" должен быть ID - так как мы связываем после по ИД с таблицей тестов
/**
* @ORM\ManyToOne(targetEntity="Acme\AppBundle\Entity\Test", inversedBy="collection")
* @ORM\JoinColumn(name="test_id", referencedColumnName="id")
*/
private $test;
// $this->test не является коллекцией, не надо объявлять new ArrayCollection() в конструкторе
public function __construct()
{
}
// соответственно метод должен быть не addTest а setTest
public function setTest(Test $test = null)
{
$this->test = $test;
return $this;
}
public function getTest()
{
return $this->test;
}
public function setPosbreakage(Breakage $posbreakage )
{
$this->posbreakage = $posbreakage;
return $this;
}
/**
* Get posbreakage
* @return integer
*/
public function getPosbreakage()
{
return $this->posbreakage;
}
}
/**
* Test
* @ORM\Table(name="test")
* @ORM\Entity
*/
class Test {
/**
* @var integer
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue
*/
private $id;
/**
* Список номеров, в котором должно выйти объявление
* @var \Doctrine\Common\Collections\Collection
*
* @ORM\ManyToMany(targetEntity="Breakage")
* @ORM\JoinTable(name="test2breakage",
* joinColumns={
* @ORM\JoinColumn(name="test_id", referencedColumnName="id")
* },
* inverseJoinColumns={
* @ORM\JoinColumn(name="breakage_id", referencedColumnName="id")
* }
* )
*/
private $breakages;
public function __construct()
{
$this->breakages = new ArrayCollection();
}
public function addBreakage(Breakage $breakage)
{
$this->breakages[] = $breakage;
return $this;
}
/**
* Remove nomer
*
* @param Breakage $breakage
*/
public function removeBreakage(Breakage $breakage)
{
$this->breakages->removeElement($breakage);
}
/**
* Get nomer
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getBreakages()
{
return $this->breakages;
}
}
/**
* @ORM\Entity
*
**/
class Breakage
{
// ...
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
...
$builder->add('breakages', 'entity', array(
'class' => 'NameSpace\MyBundle\Entity\Breakage',
'property' => 'name',
'multiple' => true
));
}
Thanks for the answer.
About removing the ArrayCollection from Breakagedemand - I also thought of this after the topic was published :)
Your version of the form is understandable - I had it originally, but ... this is enough for me when only one parameter is edited and you can set multiple for the list or checkboxes.
For me, the Test entity is a prototype of an entity with 55 fields, among which 4 fields are collections of forms, where in each form, in addition to one parameter in the form of a list, you need to work with two or three more parameters and here multiple will no longer work, for example:
a set of parameters in the form inside the collection:
1. Breakdown type (choose from the list); 2. Number of breakdowns (specify in the text field); 3. Cost (indicate in the text field).
Accordingly, when we add a new breakdown form to the collection on the page, we create a list for choosing the type and empty text for the quantity and cost.
In this case, the data from such collections of forms must be stored in separate database tables, where the connection between these tables with the test table is carried out through the id test. This is so - a small digression.
I will look into other suggestions and options - thanks.
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question