保留表单数据Symfony 2.8

时间:2016-05-27 13:57:13

标签: php forms symfony

我是Symfony的新手,我按照此文档http://symfony.com/doc/current/cookbook/form/form_collections.html构建了一个基本的嵌入式集合表单。

按照文档说明。我们有标签和任务。任务与Tag和Tag具有oneToMany关系,与Task具有ManyToOne关系。

我还在TaskType中使用EntityType :: class和queryBuilder来预填充表单上数据库中现有Task实体的选择列表。

我已经完成了构建表单,一切正常。但是,当我提交表单而不是使用现有的"任务ID"时,会生成一个具有新ID但具有相同数据的新任务。此新任务ID将分配给新的Tag实体。我希望将现有的任务ID用于新标签。

以下是我的YAML文件类:

  

TaskController.php

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use AppBundle\Entity\Task;
use AppBundle\Entity\Tag;
use AppBundle\Form\Type\TaskType;


class TaskController extends Controller
{
    public function newAction(Request $request)
    {
        $task = new Task();

        // dummy code - this is here just so that the Task has some tags
        // otherwise, this isn't an interesting example
        $tag1 = new Tag();
        $tag1->setName('tag1');

        $tag1->addTask($task);
        $task->getTags()->add($tag1);


        $form = $this->createForm(TaskType::class, $task);

        $form->handleRequest($request);

        if ($form->isValid()) {


            $em = $this->getDoctrine()->getManager();
            $em->persist($task);
            $em->flush();
        }

        return $this->render('AppBundle:Task:new.html.twig', array(
            'form' => $form->createView(),
        ));

    }

}
  

Tag.php

namespace AppBundle\Entity;

/**
 * Tag
 */
class Tag
{
    /**
     * @var integer
     */
    private $id;

    /**
     * @var string
     */
    private $name;


    /**
     * @var \AppBundle\Entity\Task
     */
    private $task;


    /**
     * Get id
     *
     * @return integer
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set name
     *
     * @param string $name
     *
     * @return Tag
     */
    public function setName($name)
    {
        $this->name = $name;

        return $this;
    }

    /**
     * Get name
     *
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }


    /**
     * Set task
     *
     * @param \AppBundle\Entity\Task $task
     *
     * @return Tag
     */
    public function setTask(\AppBundle\Entity\Task $task = null)
    {
        $this->task = $task;

        return $this;
    }

    /**
     * Get task
     *
     * @return \AppBundle\Entity\Task
     */
    public function getTask()
    {
        return $this->task;
    }


    public function addTask(Task $task)
    {

        $this->setTask($task);
    }
}
  

TagType.php

namespace AppBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;



class TagType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('name');
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'AppBundle\Entity\Tag',
        ));
    }

}
  

Tag.orm.yml

AppBundle\Entity\Tag:
    type: entity
    table: null
    repositoryClass: AppBundle\Repository\TagRepository
    id:
        id:
            type: integer
            id: true
            generator:
                strategy: AUTO
    fields:
        name:
            type: string
            length: 255

    manyToOne:
        task:
            targetEntity: Task
            inversedBy: tags
            joinColumn:
                name: task_id
                referencedColumnName: id
            cascade: [ persist ]


    lifecycleCallbacks: {  }
  

Task.php

namespace AppBundle\Entity;

use Doctrine\Common\Collections\ArrayCollection;

/**
 * Task
 */
class Task
{
    /**
     * @var integer
     */
    private $id;

    /**
     * @var string
     */
    private $description;

    /**
     * @var ArrayCollection
     */
    protected $tags;


    public function __construct()
    {
        $this->tags = new ArrayCollection();
    }

    /**
     * Get id
     *
     * @return integer
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set description
     *
     * @param string $description
     *
     * @return Task
     */
    public function setDescription($description)
    {
        $this->description = $description;

        return $this;
    }

    /**
     * Get description
     *
     * @return string
     */
    public function getDescription()
    {
        return $this->description;
    }

    /**
     * Get tags
     *
     * @return ArrayCollection
     */
    public function getTags()
    {
        return $this->tags;
    }

    public function addTag(Tag $tag)
    {
        $tag->addTask($this);
        $this->tags->add($tag);
    }


    /**
     * Remove tag
     *
     * @param \AppBundle\Entity\Tag $tag
     */
    public function removeTag(\AppBundle\Entity\Tag $tag)
    {
        $this->tags->removeElement($tag);
    }


    public function __toString()
    {
       return (string) $this->getDescription();
    }


}
  

TaskType.php

namespace AppBundle\Form\Type;


use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Doctrine\ORM\EntityRepository;



class TaskType extends AbstractType
{
    function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('description', EntityType::class,array(
            'class' => 'AppBundle:Task',
            'query_builder' => function (EntityRepository $er) {
                return $er->createQueryBuilder('d');
            },));

        $builder->add('tags', CollectionType::class, array(
            'entry_type' => TagType::class,
            'allow_add'    => true,
            'by_reference' => false,
        ));

        $builder->add('save', SubmitType::class, array('label' => 'Save'));

    }


    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'AppBundle\Entity\Task',
        ));
    }

}
  

Task.orm.yaml

AppBundle\Entity\Task:
    type: entity
    table: null
    repositoryClass: AppBundle\Repository\TaskRepository
    id:
        id:
            type: integer
            id: true
            generator:
                strategy: AUTO
    fields:
        description:
            type: string
            length: 255

    oneToMany:
        tags:
          targetEntity: Tag
          mappedBy: task
          cascade: [ persist ]

    lifecycleCallbacks: {  }

2 个答案:

答案 0 :(得分:0)

哦,我看到了问题。 当您提交表单(并保存带有标签的新任务)时,您显示相同的表单,因此用户希望这是“编辑”表单,但事实并非如此。

如何执行此操作的正确方法是创建用于编辑任务的新控制器操作,例如editAction(),其类似于newAction(),只是路由将具有用于标识的参数任务(例如task_id)并且在开头而不是使用$task = new Task();创建新任务时,您将从DB获取任务,例如:

$task = $this->get("doctrine")->getManager()->getRepository("AppBundle:Task")->findOneById($task_id);

您也可以重复使用相同的表单类型。

那么,在实体持久保存到这个新的编辑操作后,在原始newAction中添加重定向:

return $this->redirectToRoute("task_edit", array("task_id" => $task->getId()));

因此,在提交添加表单后,您将被重定向到编辑操作,因此下次更改任务并提交任务时,任务将更新,而不是创建新任务。

答案 1 :(得分:0)

所以我需要做的是使用$ form-> getData()来获取提交的实体(任务和标签),然后将它们手动保存到数据库中。

   if ($form->isValid()) {
        $data = $form->getData();

        $description = $data->getDescription();

        $tags = new ArrayCollection();

        $tags = $data->getTags();

        foreach ($tags as $tag) {
            $tag->addTask($description);
        }


        $em = $this->getDoctrine()->getManager();
        $em->persist($tag);
        $em->flush();
    }