skip to Main Content

I am trying to create a link between two tables with a ManyToMany relation in symfony. I have a Post table with is basically a table to store all post from users (like Facebook post, with comments, likes, users etc) and I also have a tag table that stores all the different tags created by the users. The relation manytomany is to help me have a link between the post and it’s tags.

It works fine for the mentioned users which works exactly the same way as the tags. (The mentioned users are like the tags but you can only tag people). The actual tags are meant to give the users the possibility to tag events and companies to the post. They will then be able to search threw all existing tags, a bit like Instagram.

Here is my Tag Entity:

<?php

namespace AppBundleEntity;

use DoctrineCommonCollectionsArrayCollection;
use DoctrineCommonCollectionsCollection;
use DoctrineORMMapping as ORM;

/**
 * Tag
 *
 * @ORMTable(name="tag", uniqueConstraints={@ORMUniqueConstraint(name="tag_id_uindex", columns={"id"})})
 * @ORMEntity
 */
class Tag
{
    /**
     * @var integer
     *
     * @ORMColumn(name="id", type="integer", nullable=false)
     * @ORMId
     * @ORMGeneratedValue(strategy="IDENTITY")
     */
    private $id;

    /**
     * @var string
     *
     * @ORMColumn(name="libelle", type="string", length=255, nullable=false)
     */
    private $libelle;

    /**
     * @var Collection
     *
     * @ORMManyToMany(targetEntity="Post", mappedBy="tags")
     */
    private $posts;

    /**
     * Constructor
     */
    public function __construct()
    {
        $this->posts = new ArrayCollection();
    }

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

    /**
     * @param int $id
     */
    public function setId($id)
    {
        $this->id = $id;
    }

    /**
     * @return string
     */
    public function getLibelle()
    {
        return $this->libelle;
    }

    /**
     * @param string $libelle
     */
    public function setLibelle($libelle)
    {
        $this->libelle = $libelle;
    }

    /**
     * @return Collection
     */
    public function getPosts()
    {
        return $this->posts;
    }

    /**
     * @param Collection $posts
     */
    public function setPosts($posts)
    {
        $this->posts = $posts;
    }

}

Here is my Post Entity:

<?php

namespace AppBundleEntity;

use DateTime;
use DoctrineCommonCollectionsArrayCollection;
use DoctrineCommonCollectionsCollection;
use DoctrineORMMapping as ORM;
use DoctrineORMMappingOneToMany;

/**
 * Post
 *
 * @ORMTable(name="post", uniqueConstraints={@ORMUniqueConstraint(name="post_id_uindex", columns={"id"})}, indexes={@ORMIndex(name="post_post_type_id_fk", columns={"post_type_id"}), @ORMIndex(name="post_club_id_fk", columns={"club_id"}), @ORMIndex(name="post_user_id_fk", columns={"user_id"})})
 * @ORMEntity(repositoryClass="AppBundleRepositoryPostRepository")
 */
class Post
{
    /**
     * @var integer
     *
     * @ORMColumn(name="id", type="integer", nullable=false)
     * @ORMId
     * @ORMGeneratedValue(strategy="IDENTITY")
     */
    private $id;

    /**
     * @var boolean
     *
     * @ORMColumn(name="enabled", type="boolean", nullable=false)
     */
    private $enabled = true;

    /**
     * @var DateTime
     *
     * @ORMColumn(name="create_date", type="datetime", nullable=false)
     */
    private $createDate;

    /**
     * @var string
     *
     * @ORMColumn(name="content", type="text", length=65535, nullable=false)
     */
    private $content;

    ///**
    // * @var string
    // *
    // * @ORMColumn(name="title", type="string", length=255, nullable=false)
    // */
    //private $title;

    /**
     * @var string
     *
     * @ORMColumn(name="attachment", type="string", length=255, nullable=false)
     */
    private $attachment;

    /**
     * @var Club
     *
     * @ORMManyToOne(targetEntity="Club")
     * @ORMJoinColumns({
     *   @ORMJoinColumn(name="club_id", referencedColumnName="id")
     * })
     */
    private $club;

    /**
     * @var PostType
     *
     * @ORMManyToOne(targetEntity="PostType")
     * @ORMJoinColumns({
     *   @ORMJoinColumn(name="post_type_id", referencedColumnName="id")
     * })
     */
    private $postType;

    /**
     * @var User
     *
     * @ORMManyToOne(targetEntity="User")
     * @ORMJoinColumns({
     *   @ORMJoinColumn(name="user_id", referencedColumnName="id")
     * })
     */
    private $user;

    /**
     * @var Manager
     *
     * @ORMManyToOne(targetEntity="Manager")
     * @ORMJoinColumns({
     *   @ORMJoinColumn(name="manager_id", referencedColumnName="id")
     * })
     */
    private $manager;

    /**
     * @var Collection
     *
     * @ORMManyToMany(targetEntity="Tag", mappedBy="posts")
     * @ORMJoinTable(name="post_has_tag",
     *   joinColumns={
     *     @ORMJoinColumn(name="post_id", referencedColumnName="id")
     *   },
     *   inverseJoinColumns={
     *     @ORMJoinColumn(name="tag_id", referencedColumnName="id")
     *   }
     * )
     */
    private $tags;

    /**
     * @var Collection
     *
     * @ORMManyToMany(targetEntity="User", inversedBy="posts")
     * @ORMJoinTable(name="post_has_user",
     *   joinColumns={
     *     @ORMJoinColumn(name="post_id", referencedColumnName="id")
     *   },
     *   inverseJoinColumns={
     *     @ORMJoinColumn(name="mentioned_user_id", referencedColumnName="id")
     *   }
     * )
     */
    private $mentionedUsers;

    /**
     * @ORMOneToMany(targetEntity="PostComment", mappedBy="post")
     * @ORMJoinColumn(nullable=false)
     */
    private $comments;

    /**
     * @ORMOneToMany(targetEntity="PostLike", mappedBy="post")
     * @ORMJoinColumn(nullable=false)
     */
    private $likes;

    /**
     * Constructor
     */
    public function __construct()
    {
        $this->tags = new ArrayCollection();
        $this->mentionedUsers = new ArrayCollection();
        $this->comments = new ArrayCollection();
        $this->likes = new ArrayCollection();
    }

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

    /**
     * @param int $id
     */
    public function setId($id)
    {
        $this->id = $id;
    }

    /**
     * @return Manager
     */
    public function getManager()
    {
        return $this->manager;
    }

    /**
     * @param Manager $manager
     */
    public function setManager($manager)
    {
        $this->manager = $manager;
    }

    /**
     * @return bool
     */
    public function isEnabled()
    {
        return $this->enabled;
    }

    /**
     * @param bool $enabled
     */
    public function setEnabled($enabled)
    {
        $this->enabled = $enabled;
    }

    /**
     * @return DateTime
     */
    public function getCreateDate()
    {
        return $this->createDate;
    }

    /**
     * @param DateTime $createDate
     */
    public function setCreateDate($createDate)
    {
        $this->createDate = $createDate;
    }

    /**
     * @return string
     */
    public function getContent()
    {
        return $this->content;
    }

    /**
     * @param string $content
     */
    public function setContent($content)
    {
        $this->content = $content;
    }

    /**
     * @return string
     */
    public function getTitle()
    {
        return $this->title;
    }

    /**
     * @param string $title
     */
    public function setTitle($title)
    {
        $this->title = $title;
    }

    /**
     * @return Club
     */
    public function getClub()
    {
        return $this->club;
    }

    /**
     * @param Club $club
     */
    public function setClub($club)
    {
        $this->club = $club;
    }

    /**
     * @return PostType
     */
    public function getPostType()
    {
        return $this->postType;
    }

    /**
     * @param PostType $postType
     */
    public function setPostType($postType)
    {
        $this->postType = $postType;
    }

    /**
     * @return User
     */
    public function getUser()
    {
        return $this->user;
    }

    /**
     * @param User $user
     */
    public function setUser($user)
    {
        $this->user = $user;
    }

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

    /**
     * @param Collection $tags
     */
    public function setTags($tags)
    {
        $this->tags = $tags;
    }

    /**
     * @return Collection
     */
    public function getMentionedUsers()
    {
        return $this->mentionedUsers;
    }

    /**
     * @param Collection $mentionedUsers
     */
    public function setMentionedUsers($mentionedUsers)
    {
        $this->mentionedUsers = $mentionedUsers;
    }

    /**
     * @return string
     */
    public function getAttachment()
    {
        return $this->attachment;
    }

    /**
     * @param string $attachment
     */
    public function setAttachment($attachment)
    {
        $this->attachment = $attachment;
    }

    /**
     * @return mixed
     */
    public function getComments()
    {
        return $this->comments;
    }

    /**
     * @param mixed $comments
     */
    public function setComments($comments)
    {
        $this->comments = $comments;
    }

    /**
     * @return mixed
     */
    public function getLikes()
    {
        return $this->likes;
    }

    /**
     * @param mixed $likes
     */
    public function setLikes($likes)
    {
        $this->likes = $likes;
    }


}

Here is also my User Entity that works fine with the Post Entity:

<?php

namespace AppBundleEntity;

use DoctrineCommonCollectionsArrayCollection;
use DoctrineCommonCollectionsCollection;
use DoctrineORMMapping as ORM;
use SymfonyBridgeDoctrineValidatorConstraintsUniqueEntity;

/**
 * User
 *
 * @ORMTable(name="user", uniqueConstraints={@ORMUniqueConstraint(name="user_email_uindex", columns={"email"}), @ORMUniqueConstraint(name="user_id_uindex", columns={"id"})}, indexes={@ORMIndex(name="user_company_id_fk", columns={"company_id"})})
 * @ORMEntity(repositoryClass="AppBundleRepositoryUserRepository")
 * @UniqueEntity(fields={"email"}, message="username already taken")
 */
class User
{
    /**
     * @var integer
     *
     * @ORMColumn(name="id", type="integer", nullable=false)
     * @ORMId
     * @ORMGeneratedValue(strategy="IDENTITY")
     */
    private $id;

    /**
     * @var string
     *
     * @ORMColumn(name="first_name", type="string", length=50, nullable=false)
     */
    private $firstName;

    /**
     * @var string
     *
     * @ORMColumn(name="last_name", type="string", length=50, nullable=false)
     */
    private $lastName;

    /**
     * @var string
     *
     * @ORMColumn(name="email", type="string", length=50, nullable=false)
     */
    private $email;

    /**
     * @var Company
     *
     * @ORMManyToOne(targetEntity="Company", inversedBy="users")
     * @ORMJoinColumns({
     *   @ORMJoinColumn(name="company_id", referencedColumnName="id")
     * })
     */
    private $company;

    /**
     * @var Collection
     *
     * @ORMManyToMany(targetEntity="Post", mappedBy="mentionedUsers")
     */
    private $posts;

    /**
     * @var string
     *
     * @ORMColumn(name="position", type="string", length=255)
     */
    private $position;

    /**
     * @var string
     *
     * @ORMColumn(name="avatar", type="string", length=255)
     */
    private $avatar;

    /**
     * @var integer
     *
     * @ORMColumn(name="phone_number", type="integer")
     */
    private $phone_number;

    /**
     * @var string
     *
     * @ORMColumn(name="linkedin_url", type="string", length=255)
     */
    private $linkedin_url;

    private $current_club;

    /**
     * Constructor
     */
    public function __construct()
    {
        $this->posts = new ArrayCollection();
    }

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

    /**
     * @param int $id
     */
    public function setId($id)
    {
        $this->id = $id;
    }

    /**
     * @return string
     */
    public function getFirstName()
    {
        return $this->firstName;
    }

    /**
     * @param string $firstName
     */
    public function setFirstName($firstName)
    {
        $this->firstName = $firstName;
    }

    /**
     * @return string
     */
    public function getLastName()
    {
        return $this->lastName;
    }

    /**
     * @param string $lastName
     */
    public function setLastName($lastName)
    {
        $this->lastName = $lastName;
    }

    /**
     * @return string
     */
    public function getEmail()
    {
        return $this->email;
    }

    /**
     * @param string $email
     */
    public function setEmail($email)
    {
        $this->email = $email;
    }

    /**
     * @return Company
     */
    public function getCompany()
    {
        return $this->company;
    }

    /**
     * @param Company $company
     */
    public function setCompany($company)
    {
        $this->company = $company;
    }

    /**
     * @return Collection
     */
    public function getPosts()
    {
        return $this->posts;
    }

    /**
     * @param Collection $posts
     */
    public function setPosts($posts)
    {
        $this->posts = $posts;
    }

    /**
     * @return string
     */
    public function getPosition()
    {
        return $this->position;
    }

    /**
     * @param string $position
     */
    public function setPosition($position)
    {
        $this->position = $position;
    }

    /**
     * @return string
     */
    public function getAvatar()
    {
        return $this->avatar;
    }

    /**
     * @param string $avatar
     */
    public function setAvatar($avatar)
    {
        $this->avatar = $avatar;
    }

    /**
     * @return int
     */
    public function getPhoneNumber()
    {
        return $this->phone_number;
    }

    /**
     * @param int $phone_number
     */
    public function setPhoneNumber($phone_number)
    {
        $this->phone_number = $phone_number;
    }

    /**
     * @return string
     */
    public function getLinkedinUrl()
    {
        return $this->linkedin_url;
    }

    /**
     * @param string $linkedin_url
     */
    public function setLinkedinUrl($linkedin_url)
    {
        $this->linkedin_url = $linkedin_url;
    }

    /**
     * @return mixed
     */
    public function getCurrentClub()
    {
        return $this->current_club;
    }

    /**
     * @param mixed $current_club
     */
    public function setCurrentClub($current_club)
    {
        $this->current_club = $current_club;
    }

}

Here is a snippet from my controllers that handle the relation between the Post and the tags when the post is created :

 /**
     * @RestPost(
     *     path="posts",
     *     name="post_creation"
     * )
     * @RestRequestParam(
     *     name="content",
     *     description="content of post"
     * )
     * @RestRequestParam(
     *     name="postType",
     *     description="type of post: text, image, video or gallery"
     * )
     *
     * @RestView(serializerGroups={"post_creation"})
     */
    public function postCreateAction(Request $request)
    {
        $text = $this->getDoctrine()->getRepository(PostType::class)->find('1');
        $image = $this->getDoctrine()->getRepository(PostType::class)->find('2');
        $video = $this->getDoctrine()->getRepository(PostType::class)->find('3');
        //$gallery = $this->getDoctrine()->getRepository(PostType::class)->find('4');

        $em = $this->getDoctrine()->getManager();

        //$title = $request->request->get('title');
        $content = $request->request->get('content');
        $postType = $request->request->get('postType');

        if ($content == null) {
            return new JsonResponse('invalid post');
        }
        $post = new Post();
        $now = new DateTime('now');

        switch ($postType) {
            case text_type:
                $user = $this->getUser()->getUser();
                $post->setClub($user->getCurrentClub());
                $post->setPostType($text);
                $post->setCreateDate($now);
                $post->setContent($content);
                $post->setUser($user);
                $em->persist($post);
                $em->flush();
                $post_tags = json_decode($request->request->get('tags'), true);

                if ($post_tags != null) {
                    foreach ($post_tags as $post_tag) {
                        $tag = $this->getDoctrine()->getRepository(Tag::class)->findOneBy(['libelle' => $post_tag]);
                        if ($tag == null) {
                            $new_tag = new Tag();
                            $new_tag->setLibelle($post_tag);
                            $em->persist($new_tag);
                            $em->flush();
                            $post->getTags()->add($new_tag);

                        } else {
                            $post->getTags()->add($tag);
                            $em->flush();
                        }
                    }
                }

                //handle mentioned users
                $mentioned_users_id = json_decode($request->request->get('mentioned_users_id'), true);
                if ($mentioned_users_id != null) {
                    foreach ($mentioned_users_id as $mentioned_user_id) {
                        $mentioned_user_input = $this->getDoctrine()->getRepository(User::class)->findOneBy(['id' => $mentioned_user_id]);
                        if ($mentioned_user_input != null) {
                            $post->getMentionedUsers()->add($mentioned_user_input);
                        }
                    }
                }

                $em->flush();
                return $post;
                break;

            case image_type:
                $filePath = tempnam(sys_get_temp_dir(), 'UploadedFile');
                $file = fopen($filePath, "w");
                stream_filter_append($file, 'convert.base64-decode');
                fwrite($file, $request->request->get('attachment'));
                $meta_data = stream_get_meta_data($file);
                $path = $meta_data['uri'];
                fclose($file);
                $fileName = $this->getUser()->getId() . "_" . uniqid() . '.' . $request->request->get("ext");
                $new_path = $this->getParameter('post_directory') . $fileName;
                rename($path, $new_path);
                $user = $this->getUser()->getUser();
                $post->setClub($user->getCurrentClub());
                $post->setPostType($image);
                $post->setCreateDate($now);
                $post->setContent($content);
                $post->setUser($user);
                $post->setAttachment($fileName);
                $em = $this->getDoctrine()->getManager();
                $em->flush();
                return $post;

            case video_type:
                $video_file = $request->request->get('attachment');
                $user = $this->getUser()->getUser();
                $post->setClub($user->getCurrentClub());
                $post->setPostType($video);
                $post->setCreateDate($now);
                $post->setContent($content);
                $post->setUser($user);
                $post->setAttachment($video_file);
                $em = $this->getDoctrine()->getManager();
                $em->flush();
                return $post;

            //case gallery_type:
            //    $gallery_file_array = [];
            //    $gallery_array = explode(',', $request->request->get('attachment'));
            //    foreach ($gallery_array as $image) {
            //        if ($image) {
            //            $filePath = tempnam(sys_get_temp_dir(), 'UploadedFile');
            //            $file = fopen($filePath, "w");
            //            stream_filter_append($file, 'convert.base64-decode');
            //            fwrite($file, $image);
            //            $meta_data = stream_get_meta_data($file);
            //            $path = $meta_data['uri'];
            //            fclose($file);
            //            $fileName = $this->getUser()->getId() . "_" . uniqid() . '.' . $request->request->get("ext");
            //            $new_path = $this->getParameter('post_directory') . $fileName;
            //            rename($path, $new_path);
            //            $gallery_file_array[] = $fileName;
            //        }
            //    }
//
            //    if (count($gallery_file_array)) {
            //        $post->setAttachment(json_encode($gallery_file_array));
            //        $current_user = $this->getUser()->getUser();
            //        $post->setClub($this->getUser()->getManager()->getClub());
            //        $post->setPostType($gallery);
            //        $post->setCreateDate($now);
            //        $post->setTitle($title);
            //        $post->setContent($content);
            //        $post->setUser($current_user);
            //        $em = $this->getDoctrine()->getManager();
            //        $em->persist($post);
            //        $em->flush();
            //        return $post;
            //    }
            //    break;
            default:
                return new JsonResponse('post creation invalid');
        }
    }

I don’t have any error messages. The tag table is created if the tag doesn’t already exist. For the mentioned users, It all works fine. It’s just the link that doesn’t seem to be created and uploaded my post_has_tag table on my database.

Here is a screen of my post_has_tag class in phpmyadmin :
enter image description here

3

Answers


  1. Chosen as BEST ANSWER

    UPDATE: I finally managed to fix my bug. I basically regenerated all my entities and recreated my post_has_tag table (also recreating all the links) and it worked again. Haven't found the source of the bug yet. Will try and update this issue in the future if i find why this issue occured. Thanks again for your help!


  2. Tags are being saved because they are persisted individually on loop.

    To save intermediate entities (relation tables) without calling persist() on intermediate table, you should use cascade={"persist"} on you manyToMany definition.

    https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/reference/working-with-associations.html#transitive-persistence-cascade-operations

    Login or Signup to reply.
  3. You should add a method in Post entity to link tags to post :

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

    And add Tag like that :

    $post->addTag($new_tag);
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search