我是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: { }
答案 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();
}