0

Hi i have that same question as here: Many-to-many self relation with extra fields? but i cant find an answer :/ I tried first ManyToOne and at the other site OneToMany ... but then i could not use something like

    public function hasFriend(User $user)
{
    return $this->myFriends->contains($user);
}  

because there was some this problem:

This function is called, taking a User type $user variable and you then use the contains()      function on $this->myFriends.

$this->myFriends is an ArrayCollection of Requests (so different type than User) and from the doctrine documentation about contains():

The comparison of two elements is strict, that means not only the value but also the type must match.

So what is the best way to solve this ManyToMany relationship with extra fields? Or if i would go back and set the onetomany and manytoone relationship how can i modify the hasFriend method? To example check if ID is in array collection of ID's.

EDIT: i have this table... and what i need is: 1. select my friends... and my followers ...check if i am friend with him or not. (because he can be friend with me and i dont have to be with him... like on twitter). I could make manytomany but i need extra fields like: "viewed" "time when he subscribe me" as you can see at my table.

And make query like this and then be able in twig check if (app.user.hasFriend(follower) or something like that)

           $qb = $this->createQueryBuilder('r')
                  ->select('u')
                  ->innerJoin('UserBundle:User', 'u')
                  ->Where('r.friend_id=:id')
                  ->setParameter('id', $id)
                  ->orderBy('r.time', 'DESC')
                  ->setMaxResults(50);

    return $qb->getQuery()
              ->getResult();

enter image description here

Community
  • 1
  • 1
Lukas Lukac
  • 7,766
  • 10
  • 65
  • 75

2 Answers2

5

I was trying to have a many to many relationship with extra fields, and couldn't make it work either... The thing I read in a forum (can't remember where) was:

If you add data to a relationship, then it's not a relationship anymore. It's a new entity.

And it's the right thing to do. Create a new entity with the new fields, and if you need it, create a custom repository to add the methods you need.

A <--- Many to many with field ---> B

would become

A --One to many--> C (with new fields) <-- One to many--B

and of course, C has ManyToOne relationships with both A and B.

I searched everywhere on how to do this, but in the end, it's the right thing to do, if you add data, it's no longer a relationship.

You can also copy what contains usually do, or try to overwrite it in a custom repository, to do whatever you need it to do.

I hope this helps.

gdlin
  • 106
  • 5
  • Is there any reason (other than wanting to only have one -> in your code when following the relation) that you wouldn't want the third entity? – MrGlass Mar 04 '13 at 16:05
  • hm... so you say... i have user entity where i would have friends property with OneToMany relationship to Friends Entity where i would have the user_id with ManyToOne Relationship to the UserEntity... (as i have now) + i need to create FriendsData entity where i would have... what? :/ ah so confused... – Lukas Lukac Mar 04 '13 at 16:15
  • Please edit the post and tell us what properties would you like to store and where, because maybe it can be solved using only two entities – gdlin Mar 04 '13 at 20:28
  • I posted another answer since it's totally different from this one. – gdlin Mar 04 '13 at 21:38
  • Okey, then how can I generate this third new entity from doctrine command line tool ? This command: `app/console doctrine:mapping:import AppBundle yml` still generate manyToMany relation for the original two tables and simply ignore the third table instead of concidering it as an entity with extra fields `:(` Should it be done by hand ? – Stphane Mar 18 '15 at 23:40
3

I'm adding another answer since it has nothing to do with my original answer. Using the new info you posted, I'm calling the table/entity you posted "Follower". The original entity, "User".

What happens if you create the following associations:


namespace Acme\UserBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * Acme\UserBundle\Entity\User
 *
 * @ORM\Table()
 * @ORM\Entity
 */
class User
{
    /**
     * @var integer $id
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\OneToMany(targetEntity="Acme\FollowerBundle\Entity\Follower", mappedBy="followeduser")
     */
    protected $followers;

    /**
     * @ORM\OneToMany(targetEntity="Acme\FollowerBundle\Entity\Follower", mappedBy="followeeuser")
     */
    protected $followees;

    /**
     * Get id
     *
     * @return integer 
     */
    public function getId()
    {
        return $this->id;
    }
    public function __construct()
    {
        $this->followers = new \Doctrine\Common\Collections\ArrayCollection();
    $this->followees = new \Doctrine\Common\Collections\ArrayCollection();
    }

    /**
     * Add followers
     *
     * @param Acme\FollowerBundle\Entity\Follower $follower
     */
    public function addFollower(\Acme\FollowerBundle\Entity\Follower $follower)
    {
        $this->followers[] = $follower;
    }

    /**
     * Add followees
     *
     * @param Acme\FollowerBundle\Entity\Follower $followee
     */
    public function addFollowee(\Acme\FollowerBundle\Entity\Follower $followee)
    {
        $this->followees[] = $followee;
    }    

    /**
     * Get followers
     *
     * @return Doctrine\Common\Collections\Collection 
     */
    public function getFollowers()
    {
        return $this->followers;
    }

    /**
     * Get followees
     *
     * @return Doctrine\Common\Collections\Collection 
     */
    public function getFollowees()
    {
        return $this->followees;
    }
}


namespace Acme\FollowerBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * Acme\FollowerBundle\Entity\Follower
 *
 * @ORM\Table()
 * @ORM\Entity
 */
class Follower
{
    /**
     * @var integer $id
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\ManyToOne(targetEntity="Acme\UserBundle\Entity\User", inversedBy="followers")
     * @ORM\JoinColumn(name="user_id", referencedColumnName="id")
     */
    protected $followeduser;

    /**
     * @ORM\ManyToOne(targetEntity="Acme\UserBundle\Entity\User", inversedBy="followees")
     * @ORM\JoinColumn(name="followee_id", referencedColumnName="id")
     */
    protected $followeeuser;

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

    /**
     * Set followeduser
     *
     * @param Acme\UserBundle\Entity\User $followeduser
     */
    public function setFolloweduser(\Acme\UserBundle\Entity\User $followeduser)
    {
        $this->followeduser = $followeduser;
    }

    /**
     * Get followeduser
     *
     * @return Acme\UserBundle\Entity\User 
     */
    public function getFolloweduser()
    {
        return $this->followeduser;
    }

    /**
     * Set followeeuser
     *
     * @param Acme\UserBundle\Entity\User $followeeuser
     */
    public function setFolloweeuser(\Acme\UserBundle\Entity\User $followeeuser)
    {
        $this->followeeuser = $followeeuser;
    }

    /**
     * Get followeeuser
     *
     * @return Acme\UserBundle\Entity\User 
     */
    public function getFolloweeuser()
    {
        return $this->followeeuser;
    }
}

I'm not sure if this would do the trick, I really don't have much time to test it, but if it doesn't, I thnk that it's on it's way. I'm using two relations, because you don't need a many to many. You need to reference that a user can have a lot of followers, and a follower can follow a lot of users, but since the "user" table is the same one, I did two relations, they have nothing to do with eachother, they just reference the same entity but for different things.

Try that and experiment what happens. You should be able to do things like:


$user->getFollowers();

$follower->getFollowedUser();

and you could then check if a user is being followed by a follower whose user_id equals $userThatIwantToCheck

and you could search in Followers for a Follower whose user = $user and followeduser=$possibleFriend

gdlin
  • 106
  • 5