Search code examples
ormsymfonydoctrine-ormmappingrelationships

How to map many to many relationship with composite key in symfony2 Doctrine ORM


I have this scenario

I have four classes

User
profiles
Activity
Workbook

user can have many profiles based on per year. Every year diff profile
User profile will have many to many with Activities

so there will be profile_activities table with profile_id and activity_id

Now User will do 1 workbook per activity per profile

so i am confused how to map in database

I mean for profile table , i can have

class profile


@many to many
protected $activities

many to one
protected $user

But in class workbook how to define foreign key which belongs to activity and profile relationship table

For every activity child has to complete workbook. How should i define that

@[one to one [PK of activity_profile table]

protected $workbook


Solution

  • Symfony provides you different methods for do this operation.
    One of those methods is annotation. With annotation you can write directly into php classes this relationships and more (like db column's type, specify if an attribute is mandatory and so on ...)

    So, let's took this example (because i dind't understand the relationships of your entities)
    Consider two entities: User and Groups.
    One user can belong to n Groups and a Groups can have m Users. This mean that we have to "break up" m-n cardinality into an m-1-n relationship.
    In symfony (with doctrine; i don't know if with mongodb and similar is the same) you haven't to create this "intermediate table" as a php class. All you have to do is, with annotation into php classes involves, specify what tables are related and in what way.
    Let's see how!

    /**
     * Acme\UserBundle\Entity\User
     *
     * @ORM\Table(name="users")
     * @ORM\Entity()
     */
    class User implements AdvancedUserInterface
    {
        /**
         * @ORM\Column(type="integer")
         * @ORM\Id
         * @ORM\GeneratedValue(strategy="AUTO")
         */
        private $id;
    [...]
       /**
         * @ORM\ManyToMany(targetEntity="Groups", inversedBy="users")
         *
         */
        private $groups;
    [...]
    

    }

    As you can see, this is a part of a php class mapped into db table with doctrine (ORM).
    This class han an attribute $groups that tells (take a look to annotations) that is a many-to-many relationship between this class and another class (identified by targetEntity) and inversedBy tells what attribute (db column; attribute if you talk about class) is involved into the relationship (external key).

    /**
     * @ORM\Table(name="groups")
     * @ORM\Entity()
     */
    class Groups implements RoleInterface
    {
        /**
         * @ORM\Column(name="id", type="integer")
         * @ORM\Id()
         * @ORM\GeneratedValue(strategy="AUTO")
         */
        private $id;
    [...]
        /**
         * @ORM\ManyToMany(targetEntity="User", mappedBy="groups")
         */
        private $users;
    [...]
    }
    

    This entity is group entity and have the "other side" of relationship: $user
    As you can see, there is @ORM\ManyToMany(targetEntity="User", mappedBy="groups") that indicates that realtionship is with class User and field into User class is groups.

    Now you can run doctrine command for entity generation onto db php app/console doctrine:generate:entities Acme where Acme is bundle's name and the trick is done.

    Some words on mappedBy and inversedBy:

    • There are "two" sides: the inverted side and the owning side. Remember that docrine will "observe" changes only into the owning side, so take care to place it into the right class
    • The inversed side is identified by mappedBy keyword and it's value is the name of owning side class
    • The owning side is identified with inversedBy keyword and it's value is the name of the inversed side class
    • manyToOne association has always the owning side
    • oneToMany association has always the inversed side
    • The owning side of oneToOne relationship is always the entity with external key
    • Into manyToMany relationship is the same