2017-02-21 7 views
1

Я реализую this tutorial. Однако в моем случае Tag объект имеет уникальный name свойство:Вложение коллекции форм: проверьте, существует ли компания

/** 
* @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 объект уже существует, в new и edit контроллеров, так что я могу решить, чтобы создать новый. Если 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'); 
    } 
} 

Я получил эту ошибку после того, как представить:

Catchable Fatal Error: Object of class AppBundle\Entity\Tag could not be converted to string

Я думаю, что это потому, что Tag сущность сохраняется до того Task форма была отправлена.

Как я могу справиться с этой частью?

ответ

3

Поскольку вы не отправил TaskType :: класс, я предполагаю, что вы использовали этот фрагмент кода, чтобы получить теги:

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

Вы видите, как Symfony формы работы, является их сериализовать данные, которые вы получили от пользователя обратно в объект. Когда вы создаете коллекцию тэгов, то, что вы на самом деле делаете, это сериализовать имена тегов обратно в теги объектов internaly. Так что эта часть кода:

$tags = $form->get('tags')->getData(); 

Фактически получает массив объектов тегов вместо простых строк. Вот почему, когда вы перекручивание через массив для проверки существующих тегов:

foreach ($tags as $tagName) {} 

$ Тэг не на самом деле название тега. Это объект класса Tag. Когда вы пытаетесь найти тег по тэгу:

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

, что вы на самом деле делаете, передавая в репозиторий Доктрине объект тегов для запроса имени. Теперь внутренне он, конечно, пытается преобразовать его в строку, поскольку вы не можете сравнивать объект со строкой. Вот почему вы получаете ошибку.

Для того, чтобы достичь того, что вы пытаетесь сделать, вы сначала должны:

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

(также было бы неплохо, если бы вы изменили именование тэгу на данный момент, так как это не на самом деле имя, его объект), то вы, если вы найдете тег в базе данных, вы должны удалить объект, который вы сохранили в этом случае, в переменной tagName с помощью $ em-> remove() и добавить вновь обнаруженный тег к задаче.

+0

да точно и в строке '$ newTag-> setName ($ tagName);' $ tagName пытается искать '__toString()' для преобразования объекта в строку , который не существует и, следовательно, ... хороший улов – sakhunzai

0

Нет, это потому, что вы перенаправляете на tasks_list, который покажет 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; 
} 
+0

привет, нет, это не повод. Я показываю теги как {{tag.name}} на странице task_list – blahblah

0

cascade={"persist"} Вы на $tasks в Tag Entity; тем не менее, вы сохраняете $task после $tag. Удалите cascade={"persist"} по телефону $task и попробуйте положить cascade={"persist"} на $tags в Task Сущность и проверьте, есть ли разница.

1

Вы должны использовать преобразователи данных. Справка: http://symfony.com/doc/current/form/data_transformers.html

// src/AppBundle/Form/DataTransformer/TagToNameTransformer.php 
namespace AppBundle\Form\DataTransformer; 

use AppBundle\Entity\Tag; 
use Doctrine\Common\Persistence\ObjectManager; 
use Symfony\Component\Form\DataTransformerInterface; 
use Symfony\Component\Form\Exception\TransformationFailedException; 

class TagToNameTransformer implements DataTransformerInterface 
{ 
    private $manager; 

    public function __construct(ObjectManager $manager) 
    { 
     $this->manager = $manager; 
    } 

    /** 
    * Transforms an object (tag) to a string (name). 
    * 
    * @param Tag|null $tag 
    * @return string 
    */ 
    public function transform($tag) 
    { 
     if (null === $tag) { 
      return ''; 
     } 

     return $tag->getName(); 
    } 

    /** 
    * Transforms a string (name) to an object (tag). 
    * 
    * @param string $tagName 
    * @return Tag|null 
    * @throws TransformationFailedException if object (tag) is not found. 
    */ 
    public function reverseTransform($tagName) 
    { 
     // empty tag name? It's optional, so that's ok 
     if (empty($tagName)) { 
      return; 
     } 

     $tag = $this->manager 
      ->getRepository('AppBundle:Tag') 
      ->find($tagName) 
     ; 

     if (null === $tag) { 
      // causes a validation error 
      // this message is not shown to the user 
      // see the invalid_message option 
      throw new TransformationFailedException(sprintf(
       'An tag with name "%s" does not exist!', 
       $tagName 
      )); 
     } 

     return $tag; 
    } 
} 

В TagType классе добавить этот код:

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

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

вуаля! Если ваш тег уже существует, он будет найден и связан с вашей задачей.

Смежные вопросы