【问题标题】:ManyToMany relation with symfony 3.4 (creating link between two tables with api )与 symfony 3.4 的多对多关系(使用 api 在两个表之间创建链接)
【发布时间】:2019-07-29 14:54:59
【问题描述】:

我正在尝试在 symfony 中创建具有 ManyToMany 关系的两个表之间的链接。我有一个 Post 表,它基本上是一个用于存储来自用户的所有帖子(如 Facebook 帖子、带有 cmets、likes、users 等)的表,我还有一个标签表,用于存储用户创建的所有不同标签。 manytomany 的关系是为了帮助我在帖子和它的标签之间建立一个链接。

它适用于上述用户,其工作方式与标签完全相同。 (提到的用户就像标签,但你只能标签人)。实际的标签是为了让用户可以在帖子中标记事件和公司。然后他们将能够搜索所有现有的标签,有点像 Instagram。

这是我的标签实体:

<?php

namespace AppBundle\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;

/**
 * Tag
 *
 * @ORM\Table(name="tag", uniqueConstraints={@ORM\UniqueConstraint(name="tag_id_uindex", columns={"id"})})
 * @ORM\Entity
 */
class Tag
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer", nullable=false)
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $id;

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

    /**
     * @var Collection
     *
     * @ORM\ManyToMany(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;
    }

}

这是我的帖子实体:

<?php

namespace AppBundle\Entity;

use DateTime;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\ORM\Mapping\OneToMany;

/**
 * Post
 *
 * @ORM\Table(name="post", uniqueConstraints={@ORM\UniqueConstraint(name="post_id_uindex", columns={"id"})}, indexes={@ORM\Index(name="post_post_type_id_fk", columns={"post_type_id"}), @ORM\Index(name="post_club_id_fk", columns={"club_id"}), @ORM\Index(name="post_user_id_fk", columns={"user_id"})})
 * @ORM\Entity(repositoryClass="AppBundle\Repository\PostRepository")
 */
class Post
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer", nullable=false)
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $id;

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

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

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

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

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

    /**
     * @var Club
     *
     * @ORM\ManyToOne(targetEntity="Club")
     * @ORM\JoinColumns({
     *   @ORM\JoinColumn(name="club_id", referencedColumnName="id")
     * })
     */
    private $club;

    /**
     * @var PostType
     *
     * @ORM\ManyToOne(targetEntity="PostType")
     * @ORM\JoinColumns({
     *   @ORM\JoinColumn(name="post_type_id", referencedColumnName="id")
     * })
     */
    private $postType;

    /**
     * @var User
     *
     * @ORM\ManyToOne(targetEntity="User")
     * @ORM\JoinColumns({
     *   @ORM\JoinColumn(name="user_id", referencedColumnName="id")
     * })
     */
    private $user;

    /**
     * @var Manager
     *
     * @ORM\ManyToOne(targetEntity="Manager")
     * @ORM\JoinColumns({
     *   @ORM\JoinColumn(name="manager_id", referencedColumnName="id")
     * })
     */
    private $manager;

    /**
     * @var Collection
     *
     * @ORM\ManyToMany(targetEntity="Tag", mappedBy="posts")
     * @ORM\JoinTable(name="post_has_tag",
     *   joinColumns={
     *     @ORM\JoinColumn(name="post_id", referencedColumnName="id")
     *   },
     *   inverseJoinColumns={
     *     @ORM\JoinColumn(name="tag_id", referencedColumnName="id")
     *   }
     * )
     */
    private $tags;

    /**
     * @var Collection
     *
     * @ORM\ManyToMany(targetEntity="User", inversedBy="posts")
     * @ORM\JoinTable(name="post_has_user",
     *   joinColumns={
     *     @ORM\JoinColumn(name="post_id", referencedColumnName="id")
     *   },
     *   inverseJoinColumns={
     *     @ORM\JoinColumn(name="mentioned_user_id", referencedColumnName="id")
     *   }
     * )
     */
    private $mentionedUsers;

    /**
     * @ORM\OneToMany(targetEntity="PostComment", mappedBy="post")
     * @ORM\JoinColumn(nullable=false)
     */
    private $comments;

    /**
     * @ORM\OneToMany(targetEntity="PostLike", mappedBy="post")
     * @ORM\JoinColumn(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;
    }


}

这也是我的用户实体,可以很好地与帖子实体配合使用:

<?php

namespace AppBundle\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;

/**
 * User
 *
 * @ORM\Table(name="user", uniqueConstraints={@ORM\UniqueConstraint(name="user_email_uindex", columns={"email"}), @ORM\UniqueConstraint(name="user_id_uindex", columns={"id"})}, indexes={@ORM\Index(name="user_company_id_fk", columns={"company_id"})})
 * @ORM\Entity(repositoryClass="AppBundle\Repository\UserRepository")
 * @UniqueEntity(fields={"email"}, message="username already taken")
 */
class User
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer", nullable=false)
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $id;

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

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

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

    /**
     * @var Company
     *
     * @ORM\ManyToOne(targetEntity="Company", inversedBy="users")
     * @ORM\JoinColumns({
     *   @ORM\JoinColumn(name="company_id", referencedColumnName="id")
     * })
     */
    private $company;

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

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

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

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

    /**
     * @var string
     *
     * @ORM\Column(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;
    }

}

这是我的控制器中的一个 sn-p,它在创建帖子时处理帖子和标签之间的关系:

 /**
     * @Rest\Post(
     *     path="posts",
     *     name="post_creation"
     * )
     * @Rest\RequestParam(
     *     name="content",
     *     description="content of post"
     * )
     * @Rest\RequestParam(
     *     name="postType",
     *     description="type of post: text, image, video or gallery"
     * )
     *
     * @Rest\View(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');
        }
    }

我没有任何错误消息。如果标签尚不存在,则会创建标签表。对于提到的用户,一切正常。这只是似乎没有创建的链接并将我的 post_has_tag 表上传到我的数据库中。

这是我在 phpmyadmin 中的 post_has_tag 类的屏幕: enter image description here

【问题讨论】:

    标签: php database symfony doctrine many-to-many


    【解决方案1】:

    标签正在保存,因为它们在循环中单独保留。

    要保存中间实体(关系表)而不在中间表上调用 persist(),您应该在 manyToMany 定义上使用 cascade={"persist"}。

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

    【讨论】:

    • 感谢您的快速回复。将尝试您的解决方案并及时更新。
    • 嘿,再次尝试了您的解决方案,但没有运气,仍然有同样的问题。我需要将它们单独保存在循环中,因为如果标签不存在,我需要创建它们,然后将它们与我的帖子链接。无论如何谢谢你;)
    【解决方案2】:

    你应该在 Post 实体中添加一个方法来链接标签到 post :

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

    然后像这样添加标签:

    $post->addTag($new_tag);
    

    【讨论】:

    • 再次感谢您的快速回复。现在将尝试并让您更新。但是,我不知道您的“$this->tags->add($tag)”和我的“$post->getTags()->add($new_tag);”之间有什么变化。对我来说是一样的。我这样做是因为我知道我的所有标签都存在,因为我已经在此之前循环检查它们是否存在,如果不存在,我创建它们。这并不能真正解决我的问题。
    • Estève 表示您可以创建他展示的方法,而不是 $post-&gt;getTags()-&gt;add($new_tag);。也许您在被添加到帖子$post-&gt;getTags()-&gt;add($new_tag); 后并没有坚持发布任何标签,您在分配标签之前坚持并刷新$post。
    • 您好,刚刚试过您的解决方案,还是不行。在我为其分配标签之前或之后持久保存帖子的事实不应修改或干扰数据库如何保存我的两个表之间的链接。无论如何感谢您的帮助!
    • 也许您可以在创建新标签时设置帖子,例如:$new_tag-&gt;setLibelle($post_tag); $new_tag-&gt;addPost($post)
    • 我不能这样做,因为 Post 是所有者而不是标签。如果标签尚不存在,则创建该标签,并将其保存在数据库中。问题是学说不会在我的 post_has_tag 表中保存/创建链接。我认为这是一个教义错误。
    【解决方案3】:

    更新:我终于设法修复了我的错误。我基本上重新生成了所有实体并重新创建了我的 post_has_tag 表(也重新创建了所有链接)并且它再次工作。还没找到bug的根源。如果我找到发生此问题的原因,将来会尝试更新此问题。再次感谢你的帮助!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-08-24
      • 1970-01-01
      • 1970-01-01
      • 2017-09-17
      • 2018-03-06
      • 2019-10-23
      • 2017-06-23
      • 1970-01-01
      相关资源
      最近更新 更多