symfony3: создайте форму для сущности, у которой есть столбец с отношением "многие к одному"


У меня есть таблица "Задачи", которая ссылается на таблицу "Estados" с внешним ключом из столбца Tasks.taskestado в Estados.estado.

Вот соответствующее сопоставление XML для задач:

<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>
...

И для 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>
...

Учитывая это, я пытаюсь выполнить действие (novaaction()) для создания задач. Вот код контроллера:

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');
    }

И соответствующий код типа задачи:

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();
        #},
    ));
}
}

Опция 'empty_data' была попыткой создать форму без передачи экземпляр задач к нему. Кроме того, у меня тот же результат, когда я добавляю taskestado с прокомментированным кодом, т. Е. Без аргументов.

И вот соответствующая сущность задач:

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;
    }

    ...
}

Когда я открываю страницу, я получаю следующую ошибку:

Объектами, переданными в поле выбора, необходимо управлять. Может быть, сохранить их в диспетчере сущностей?

Я также сгенерировал CRUD (bin/console doctrine:generate:crud --filter=Tasks), чтобы проверить, как это делается, но код похож, как и результаты (после устранения некоторых проблем в типе задач для некоторых столбцов даты и времени).

Что я делаю не так?

Author: Nuno Pereira, 2016-01-09

3 answers

Как говорится в ошибке, вам нужно установить cascade = сохраняться в ваших сопоставлениях для задач. Например:

<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>

Также вместо того, чтобы делать $em->persist($form->getData()); Использовать $em->persist($task);

Посмотрим, сработает ли это...

 3
Author: Ratty, 2016-01-08 21:34:31

Наконец-то я получил ответ на этот вопрос, он был далеко не очевиден.

Как я уже сказал в вопросе, существует связь "многие к одному" от Tasks.taskestado до Estados.estado. Estados.estado - это строка, которая может быть обнуляемой, пустой строкой или (обычно) непустой строкой. Хотя это не указано в сопоставлении, пустая строка является значением по умолчанию для taskestado.

У меня уже есть данные в таблице, и одна из записей для Estados.estado точно пуста строка.

Я не публиковал вопрос, но я увидел следующую информацию в трассировке стека этого исключения:

[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

Итак, EntityType извлек значения из базы данных и пытался их отобразить. Другими словами, они уже были сохранены, и проблема на самом деле не могла заключаться в том, как я инициализировал сущность.

Итак, я вспомнил о пустом строковом значении для сущности Estados и попытался удалить его из базы данных: проблема решена, Объект TaskEstado был инициализирован и отображен, как и ожидалось.

Теперь мне нужен способ обойти это, но решение было найдено.

Спасибо всем за ваши ответы.

 2
Author: Nuno Pereira, 2016-01-11 17:27:12

Убедитесь, что у вас есть

$this->taskestado = new ArrayCollection();

В __construct() вашего Tasks класса.

Затем 2 уведомления:

Старайтесь использовать в своем коде только английский язык. Таким образом, вы получите гораздо больше ответов. В качестве "наилучшей практики" используйте сингуляры для имен классов сущностей, таких как Task, TaskEstado

 1
Author: mblaettermann, 2016-01-09 12:30:03