
As we are using Doctrine ORM to ease our database layer programming, it’s very important to understand how to establish the doctrine relationship between entities and do it in the proper way to build a robust relational database design. Here, by the term ‘relationship,’ I meant the x-to-x relations, which can take the form of one-to-one, one-to-many (many-to-one) or many-to-many relationships, etc. I am assuming you have started using doctrine and have at least some basic idea of how to declare and perform Doctrine CRUD operations.
Ways To Establish Relationship:
Well, it is always mandatory that you have a complete synchronization between your entities’ annotation/property declaration and your database structure. You can, though, do that manually, but it’s time-consuming and potentially buggy. Sometimes, you may find yourself messing around but can’t exactly catch the reason for a raised issue. It’s a waste of time and mental torture.
So, it is strongly recommended that you implement on only one side and use a PHP script or CLI tool for transformation between doctrine entities and database.
I usually like to establish the doctrine relationship in entities and then update the database schema, and I will show this method here. There are some specific benefits as well, which you will know later in this article. Keep reading.
One To One Relationship:
Let’s assume we have two entities named ‘Users’ and ‘Profiles’. This can be a good example of a one-to-one relationship, as every user has only one profile, and each profile can be associated with only one user. Now, as a rule of thumb, we will have to add an identity foreign key(as per the database language) to one table that is linked to another table.
Now, which table needs to contain and link to another? To decide this, first think about which entity comes first and which is optional. The secondary entity needs to have a link to its primary entity. In this example scenario, from general knowledge, we know that first, we need to have a user in our system who can later create a profile. So, the user is primary here, and the profile is secondary. So, in the profile entity, we will have property/database column definition as follows:
/**
* UserProfile
*
* @Table(name="user_profile")
* @Entity
*/
class UserProfile
{
/**
* @var integer $id
*
* @Column(name="id", type="integer", nullable=false)
* @Id
* @GeneratedValue(strategy="IDENTITY")
*/
private $id;
//other declarations.....
/**
* @var Users
*
* @OneToOne(targetEntity="Users")
* @JoinColumns({
* @JoinColumn(name="user_id", referencedColumnName="id", onDelete="CASCADE")
* })
*/
private $user;
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
//other getter/setter declarations.....
/**
* Set user
*
* @param Users $user
* @return UserProfile
*/
public function setUser(\Users $user = null)
{
$this->user = $user;
return $this;
}
/**
* Get user
*
* @return Users
*/
public function getUser()
{
return $this->user;
}
}
Code language: PHP (php)
As you can see above, this declaration will create a foreign key on ‘profiles’ and link to the ‘users’ table’s ‘id’ column; now, when we create a new profile, we can set the corresponding user with the use of the setter property, and we should be fine. Also, if you check your database, you will find that a new unique key is also generated on the ‘user_id’ column because of the ‘OneToOne’ relation declaration. See the below example of saving a Profile entity:
$id = 1;
$user = $em->getRepository("Users")->find($id);
$profile = new UserProfile();
$profile->setFirstName("test first name");
$profile->setLastName("test last name");
$profile->setUser($user);
$em->persist($profile);
$em->flush();
Code language: PHP (php)
One To Many Doctrine Relationship:
Let’s say your web application provides specific access level permission to its users. A single role can be assigned to as many users as possible, but each user is associated with only one role at a time. This is a very good example of one-to-many (role to user) or many-to-one (users to role). And here, its easy to guess that we will need to add a property in ‘user’ entity which links to ‘role’ entity’s ‘id’ property as below:
/**
* Users
*
* @Table(name="users")
* @Entity
*/
class Users
{
/**
* @var integer $id
*
* @Column(name="id", type="integer", nullable=false)
* @Id
* @GeneratedValue(strategy="IDENTITY")
*/
private $id;
//other declarations.....
/**
* @var Roles
*
* @ManyToOne(targetEntity="Roles")
* @JoinColumns({
* @JoinColumn(name="role_id", referencedColumnName="id")
* })
*/
private $role;
//other getter/setter declarations.....
/**
* Set role
*
* @param Roles $role
* @return Users
*/
public function setRole(\Roles $role = null)
{
$this->role = $role;
return $this;
}
/**
* Get role
*
* @return Roles
*/
public function getRole()
{
return $this->role;
}
Code language: PHP (php)
After you update the database schema with the above-annotated definition, you should be able to see the foreign key on the ‘users’ table. But you will notice there is no unique key generated. To establish the relationship properly while creating a new user, you can follow the code example below:
$role = $em->getRepository("Roles")->findOneBy(array("name"=>"admin"));
$user = new Users();
$user->setUserName("testusername");
$user->setEmail("testemail@domain.com");
$user->setRole($role);
$em->persist($user);
$em->flush();
Code language: PHP (php)
Many To Many Relationship:
A new story for a new relationship. Suppose our users have some skills. A single user can have multiple skills, and in the same way, a single skill can be acquired by multiple users. So, here we are talking about a many-to-many relationship between users and skills.
From relational database design basics, we know that in such a scenario, in the database, we will have to establish a new table which connects to the user’s table and the expertise table. And a user/skill pair will be unique on that table. Luckily, as we are modifying entities instead of databases, it has become very easy for us to have strong abstraction support.
Let’s see the doctrine relationship establishment in user entity to contain multiple skills.
use Doctrine\ORM\Mapping as ORM;
/**
* Users
*
* @Table(name="users")
* @Entity
*/
class Users
{
//Other declarations
/**
* @var \Doctrine\Common\Collections\ArrayCollection
* @ManyToMany(targetEntity="Expertises", inversedBy="users")
* @JoinTable(name="users_expertises")
**/
private $expertises;
public function __construct() {
$this->expertises = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Get expertises
*
* @return PdExpertises
*/
public function getExpertises()
{
return $this->expertises;
}
}
//expertise entity
use Doctrine\ORM\Mapping as ORM;
/**
* Expertises
*
* @Table(name="expertises")
* @Entity
*/
class Expertises
{
//other declarations.....
/**
* @ManyToMany(targetEntity="Users", mappedBy="expertises")
**/
private $users;
public function __construct() {
$this->users = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Get users
*
* @return Users
*/
public function getUsers()
{
return $this->users;
}
}
Code language: PHP (php)
From the above code, you will see that we haven’t declared any setter method for the properties. Because we won’t need it. We will be able to perform our task by operating on ArrayCollection very fine. Let’s see a basic example of usage:
$expertise = $this->em->getRepository("Expertises")->find(1);
$user = new Users();
//other properties set
$user->getExpertises()->add($expertise);
$this->em->persist($user);
$this->em->flush();
Code language: PHP (php)
Final Words:
So, do some exercises and see how, surprisingly, the doctrine relationship establishment makes it easier for us to do several operations. If you are having any issue to understand, ask me by commenting. Happy coding 🙂
Discover more from CODESAMPLEZ.COM
Subscribe to get the latest posts sent to your email.
Nice tutorial! Thank you, great job!
can u tell something about entity owner side and inverse side ?
Hi Thank you for your tutorial.
i have type table that have Many-to-Many relationship with category and many to many relation table (categoryOftype table) have One-to-Many relationship with items table how i do this with entity relationship in doctrine 2 .
tanks