symfony3:为具有多对一关系的列的实体创建表单

时间:2016-01-08 21:21:43

标签: php doctrine-orm symfony-forms symfony

我有一个“任务”表,它引用了一个“Estados”表,其中包含从Tasks.taskestado到Estados.estado列的外键。

以下是任务的相关XML映射:

.setAlwaysOnTop(true);

对于Estados:

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

鉴于此,我正在尝试创建一个动作(novaAction())来创建任务。 这是控制器代码:

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

相关的TasksType代码:

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

'empty_data'选项是尝试在不向其传递任务实例的情况下创建表单。 另外,当我使用注释代码添加taskestado时,我有相同的结果,i。例如,没有争论。

这是相关的任务实体:

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

当我打开页面时,出现以下错误:

  

必须管理传递到选择字段的实体。也许坚持他们在实体经理?

我还生成了CRUD(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; } ... } ),以便我可以检查它是如何完成的,但代码类似,以及结果(修复了一些日期时间列的TasksType中的一些问题) )。

我做错了什么?

3 个答案:

答案 0 :(得分:3)

如错误所示,您需要在任务的映射中设置cascade = persist。例如:

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

看看是否有效......

答案 1 :(得分:2)

我终于得到了答案,这远非显而易见。

正如我在问题中所说,从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 :(得分:1)

确保你有

$this->taskestado = new ArrayCollection();

__construct()课程的Tasks中。

然后2个通知:

尽量只在代码中使用英语。通过这种方式,您可以获得更多响应 作为“最佳实践”,使用Singulars作为您的实体类名称,例如TaskTaskEstado