Search code examples
tagssulu

How to store tags to custom entity?


I have custom entity and tag field defined as:

/**
 * @ORM\ManyToMany(targetEntity="Sulu\Bundle\TagBundle\Tag\TagInterface")
 * @ORM\JoinTable(name="venue_tags",
 *      joinColumns={@ORM\JoinColumn(name="venue_id", referencedColumnName="id")},
 *      inverseJoinColumns={@ORM\JoinColumn(name="idTags", referencedColumnName="id")}
 *      )
 */
private $tags;

Then I have setter (adder actually) like this:

public function addTag(TagInterface $tag)
{
    $this->tags[] = $tag;

    return $this;
}

Field is added to form details XML like:

    <property name="tags" type="tag_selection">
        <meta>
            <title lang="de">Tags</title>
            <title lang="en">Tags</title>
        </meta>

        <tag name="sulu.search.field" type="tags"/>
    </property>

And inside my admin controller class I have mapping method:

    protected function mapDataToEntity(array $data, Venue $entity): void
    {  
        ....
        foreach ($data['tags'] as $tag) {
           $entity->addTag($tag);
        }
        ....

However as $data['tags'] I receive here array of string and my addTag() requires instance of TagInterface object. How can I create that object from string I have and generally is this the proper way for storing tags.

Update:

As @Johannes suggested added field:

/**
 * @var TagManagerInterface
 */
private $tagManager;

and to constructor like:

public function __construct(
    ViewHandlerInterface $viewHandler,
    ...
    TagManagerInterface $tagManager
) {
    $this->viewHandler = $viewHandler;
    ...
    $this->tagManager = $tagManager;
    parent::__construct($viewHandler);
}

And then trying to add tags like this:

    $tagEntities = $this->tagManager->resolveTagNames($data['tags']);
    foreach ($tagEntities as $tagEntity) {
       $entity->addTag($tagEntity);
    }

But then I get error:

Argument 1 passed to App\Entity\Venue::addTag() must implement interface Sulu\Bundle\TagBundle\Tag\TagInterface, int given, called in /var/www/html/src/Controller/Admin/VenueController.php on line 147

What I'm doing wrong? Like I'm getting tag ids? Should I load tags somehow?

Update 2:

After adding findById() saving tags works. However, now I found 2 more problems:

  1. Even relations are saved well in database just after saving tags are not displayed any more in tags field. Also if I go to overview page and get back to edit entity selected (saved) tags are not re-populated. What else I have to add so saved tags in database would be used actually?

  2. If I fist select "Tag1" and click "Save" it's saved well. But if I edit entity again and select "Tag1" again Sulu tries to create new row with same keys and I get error message: "SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '4-1' for key 'venue_tags.PRIMARY'". I guess previously saved keys should be deleted first but how and where would be the optimal way?


Solution

  • You can use the TagManager service (id: sulu_tag.tag_manager or Sulu\Bundle\TagBundle\Tag\TagManagerInterface):

    $tagIds = $tagManager->resolveTagNames($data['tags']);
    foreach ($tagIds as $tagId) {
       $entity->addTag($tagManager->findById($tagId));
    }