Symfony3: create a form for an object that has a column with many relationships

I have a Tasks table that references a Estados table with a foreign key from the Tasks.taskestado column in Estados.estado.

Here's the appropriate XML mapping for Jobs:

<entity name="AppBundle\Entity\Tasks" table="TASKS" repository-class="AppBundle\Repository\TasksRepository"> <id name="taskid" type="bigint" column="TaskID"> <generator strategy="IDENTITY"/> </id> ... <many-to-one field="taskestado" target-entity="Estados" fetch="LAZY"> <join-columns> <join-column name="TaskEstado" referenced-column-name="Estado"/> </join-columns> </many-to-one> ... 

And for Estados:

 <entity name="AppBundle\Entity\Estados" table="ESTADOS"> <id name="estado" type="string" column="Estado" length="15"> <generator strategy="IDENTITY"/> </id> <field name="estadodescricao" type="string" column="EstadoDescricao" length="50" nullable="true"> <options> <option name="fixed"/> </options> </field> ... 

Given this, I am trying to do an action (novaAction ()) to create tasks. Here is the controller code:

 public function novaAction(Request $request) { $task = new Tasks(); $em = $this->getDoctrine()->getManager(); dump($task); #$task->setTaskEstado(new Estados()); $form = $this->createForm(TasksType::class, $task); $form->handleRequest($request); if ($form->isSubmitted()) { if ($form->isValid()) { // Criar a tarefa na BD $em->persist($form->getData()); $em->flush(); $this->addFlash('notice', 'app.nova_tarefa.mensagem_sucesso'); return $this->redirectToRoute('nova_tarefa'); } $this->addFlash('error', 'app.nova_tarefa.mensagem_erro'); } 

And the corresponding TasksType code:

 class TasksType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('taskid', HiddenType::class) ... #->add('taskestado') ->add('taskestado', EntityType::class, [ 'class' => 'AppBundle:Estados' ]) ... } /** * @param OptionsResolver $resolver */ public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults(array( 'data_class' => 'AppBundle\Entity\Tasks', #'empty_data' => function (\Symfony\Component\Form\FormInterface $form) { # #return new Tasks($form->get('tasks')->getData()); # return new Tasks(); #}, )); } } 

The parameter 'empty_data' was an attempt to create a form without passing it an instance of the Tasks. Also, I have the same result when I add taskestado with commented code, i.e. e. without argument.

And here is the corresponding "Tasks" object:

 namespace AppBundle\Entity; use Doctrine\Common\Collections\ArrayCollection; /** * Tasks */ class Tasks { /** * @var integer */ protected $taskid; /** * @var \AppBundle\Entity\Estados */ protected $taskestado; ... /** * Get taskid * * @return integer */ public function getTaskid() { return $this->taskid; } /** * Set taskestado * * @param \AppBundle\Entity\Estados $taskestado * * @return Tasks */ public function setTaskestado(\AppBundle\Entity\Estados $taskestado = null) { $this->taskestado = $taskestado; return $this; } /** * Get taskestado * * @return \AppBundle\Entity\Estados */ public function getTaskestado() { return $this->taskestado; } ... } 

When I open the page, I get the following error:

Objects transferred to the selection field must be managed. Maybe they are saved in the entity manager?

I also created CRUD ( bin/console doctrine:generate:crud --filter=Tasks ) so that I can check how this is done, but the code is similar as well as the results (after fixing some problems in TasksType for some datetime columns).

What am I doing wrong?

+8
php symfony doctrine2 symfony-forms
source share
3 answers

Finally, I got the answer to this question, it was far from obvious.

As I said in this question, there is a lot of one relationship from Tasks.taskestado to Estados.estado. Estados.estado is a string that can be null, an empty string, or (usually) a non-empty string. Although not specified in the mapping, an empty string is the default value for taskestado.

I already have the data in the table, and one of the entries for Estados.estado is definitely an empty string.

I did not write in the question, but I saw the following information in the stack trace of this exception:

 [1] Symfony\Component\Form\Exception\RuntimeException: Entities passed to the choice field must be managed. Maybe persist them in the entity manager? at n/a in /var/www/simpletask2/vendor/symfony/symfony/src/Symfony/Bridge/Doctrine/Form/ChoiceList/IdReader.php line 119 at Symfony\Bridge\Doctrine\Form\ChoiceList\IdReader->getIdValue(object(Estados)) in line at call_user_func(array(object(IdReader), 'getIdValue'), object(Estados)) in /var/www/simpletask2/vendor/symfony/symfony/src/Symfony/Component/Form/ChoiceList/ArrayChoiceList.php line 204 at Symfony\Component\Form\ChoiceList\ArrayChoiceList->flatten(array(object(Estados), object(Estados), object(Estados), object(Estados), object(Estados), object(Estados), object(Estados), object(Estados)), array(object(IdReader), 'getIdValue'), array(), array(), array()) in /var/www/simpletask2/vendor/symfony/symfony/src/Symfony/Component/Form/ChoiceList/ArrayChoiceList.php line 91 

So, EntityType retrieved the values ​​from the database and tried to display them. In other words, they were already saved, and the problem could not really be how I initialized the object.

So, I remembered the empty string value for the Estados object and tried to remove it from the database: the problem was solved, the TaskEstado object was initialized and displayed as expected.

Now I need a way around this, but a solution has been found.

Thank you all for your answers.

+2
source share

As the error says, you need to set cascade = persist in your mappings for Tasks. For example:

 <many-to-one field="taskestado" target-entity="Estados" fetch="LAZY"> <cascade> <cascade-persist/> </cascade> <join-columns> <join-column name="TaskEstado" referenced-column-name="Estado"/> </join-columns> </many-to-one> 

Also, instead of doing $em->persist($form->getData()); Use $em->persist($task);

See if this works ...

+3
source share

Make sure you have

 $this->taskestado = new ArrayCollection(); 

in __construct() your Tasks class.

Then 2 comments:

Try using only English in your code. This way you will get a lot more answers. As a β€œbest practice,” use Singulars for entity class names. Like Task , TaskEstado

+1
source share

All Articles