Doctrine orm 嵌入表单集合:检查实体是否存在

Doctrine orm 嵌入表单集合:检查实体是否存在,doctrine-orm,symfony,symfony-forms,Doctrine Orm,Symfony,Symfony Forms,我正在实施。但是在我的例子中,标记实体有一个唯一的名称属性: /** * @ORM\Entity() */ class Tag { /** * @var string * @ORM\Column(name="name", type="string", length=63, unique=true) */ private $name; /** * @ORM\ManyToMany(targetEntity="Task", casc

我正在实施。但是在我的例子中,
标记
实体有一个唯一的
名称
属性:

/**
 * @ORM\Entity()
 */
class Tag
{
    /**
     * @var string
     * @ORM\Column(name="name", type="string", length=63, unique=true)
     */
    private $name;

    /**
     * @ORM\ManyToMany(targetEntity="Task", cascade={"persist"})
     * @ORM\JoinTable(name="tasks_tags")
     */
    protected $tasks;

  }
如何检查
标记
实体在
新建
编辑
控制器中是否已存在,以便决定创建新实体。如果
Tag
存在,我可以将其添加到新任务中

public function newAction(Request $request)
{
    $task = new Task();

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

    if ($form->isSubmitted() && $form->isValid()) {
        $tags = $form->get('tags')->getData();

        $em = $this->getDoctrine()->getManager();
        foreach ($tags as $tagName) {
            $tag = $this->getDoctrine()->getRepository('AppBundle:Tag')->findOneBy(array('name' => $tagName));
            if (!$tag) {
                $newTag = new Tag();
                $newTag->setName($tagName);
                $em->persist($newTag);
            }
        }
        $em->persist($task);
        $em->flush();

        return $this->redirectToRoute('tasks_list');
    }
}
我在提交后出现此错误:

可捕获的致命错误:类
AppBundle\Entity\Tag
的对象无法转换为字符串

我认为这是因为
标记
实体在提交
任务
表单之前被持久化了


如何处理此部分?

否,这是因为您正在重定向到
任务列表
,该列表将显示
标记
您已持久化,但您没有该对象的字符串表示形式

为避免此错误,请将以下方法引入
Tag
实体

public function __toString()
{
  // This is only an example; you can insert 
  // here whatever you want to display
  // as tag's string representation

  return $this->name;
}

不,这是因为您正在重定向到
任务列表
,该列表将显示
标记
,您已持久化,但您没有该对象的字符串表示形式

为避免此错误,请将以下方法引入
Tag
实体

public function __toString()
{
  // This is only an example; you can insert 
  // here whatever you want to display
  // as tag's string representation

  return $this->name;
}

Tag
实体中的
$tasks
上有
cascade={“persist”}
;然而,您将一个
$task
持久化在一个
$tag
之后。移除
task
上的
cascade={“persist”}
并尝试将
cascade={“persist”}
放在
task
实体中的
$tags
上,并检查是否有任何差异。

;然而,您将一个
$task
持久化在一个
$tag
之后。删除
cascade={“persist”}
上的
task
并尝试将
cascade={“persist”}
放在
task
实体中的
$tags
上,并检查是否有任何差异。

由于您尚未发布TaskType::class,我猜您已经使用此代码片段来获取标记:

$builder->add('tags', CollectionType::class, array(
   'entry_type' => TagType::class
));
你看,Symfony表单的工作方式是,它们将从用户那里获得的数据序列化回实体。创建标记集合时,实际上要做的是将标记名称序列化回内部标记对象。所以这部分代码:

$tags = $form->get('tags')->getData();
实际上获取标记对象的数组,而不仅仅是字符串。这就是为什么在数组中循环检查现有标记时:

foreach ($tags as $tagName) {}
$tagName实际上不是标记名。它是类标记的对象。尝试按标记名查找标记时:

->findOneBy(array('name' => $tagName))
实际上,您所做的是向条令存储库传递一个标记对象以查询名称。现在,在内部,它当然会尝试将其转换为字符串,因为您无法将对象与字符串进行比较。这就是为什么会出现错误

为了实现您的目标,您首先必须:

->findOneBy(array('name' => $tagName->getName()))

(如果此时更改标记名的命名也很好,因为它实际上不是一个名称,而是一个对象),那么如果在数据库中找到标记,则应通过$em->remove()删除在本例中保存在标记名变量中的对象并将新找到的标记添加到任务中。

由于您尚未发布TaskType::class,我猜您已经使用此代码段来获取标记:

$builder->add('tags', CollectionType::class, array(
   'entry_type' => TagType::class
));
你看,Symfony表单的工作方式是,它们将从用户那里获得的数据序列化回实体。创建标记集合时,实际上要做的是将标记名称序列化回内部标记对象。所以这部分代码:

$tags = $form->get('tags')->getData();
实际上获取标记对象的数组,而不仅仅是字符串。这就是为什么在数组中循环检查现有标记时:

foreach ($tags as $tagName) {}
$tagName实际上不是标记名。它是类标记的对象。尝试按标记名查找标记时:

->findOneBy(array('name' => $tagName))
实际上,您所做的是向条令存储库传递一个标记对象以查询名称。现在,在内部,它当然会尝试将其转换为字符串,因为您无法将对象与字符串进行比较。这就是为什么会出现错误

为了实现您的目标,您首先必须:

->findOneBy(array('name' => $tagName->getName()))

(如果此时更改标记名的命名也很好,因为它实际上不是一个名称,而是一个对象),那么如果在数据库中找到标记,则应通过$em->remove()删除在本例中保存在标记名变量中的对象,并将新找到的标记添加到任务中。

应使用数据转换器。参考:

TagType
类中添加此代码:

class TagType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        // ... your code

        $builder->get('name')
            ->addModelTransformer(new TagToNameTransformer($this->manager));
    }
}

瞧!如果您的标记已经存在,将找到它并链接到您的任务。

您应该使用数据转换器。参考:

TagType
类中添加此代码:

class TagType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        // ... your code

        $builder->get('name')
            ->addModelTransformer(new TagToNameTransformer($this->manager));
    }
}

瞧!如果您的标记已经存在,它将被找到并链接到您的任务。

您好,不,这不是原因。我在tasks_list pagehello中将标记显示为{{tag.name}},不,这不是原因。我在tasks_list pageyes中,在“$newTag->setName($tagName);”行中将标记显示为{{tag.name}}$tagName正在试图寻找
\uuuToString()
将对象转换为字符串,该字符串不存在,因此…很好的捕获正确,在“$newTag->setName($tagName)”行中,`$tagName正试图寻找
\uuu toString()
来将对象转换为字符串,但该字符串不存在,因此…捕捉良好