In life, everything is connected, for example, a book must have an author, or a school must have many classes. Also in the database, tables can also be linked. Laravel has provided us with relationships that can reduce the time and effort of the programmers. It makes it easier to query tables. In this article we learn about the types of relationships together
- One to One
- One to Many
- Many to Many
- Has One Through
- Has Many Through
- Polymorphic Relations
Relationships in Laravel
1. One to One
This is the simplest type of relationship, which we can understand that one depends only on the other and vice versa. For example, to make it easy to imagine, we have the Users
table and the Avatar
table, here one user has only one avatar and this avatar only represents that user. To express this relationship, we use the hasOne
method
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <span class="token php language-php"><span class="token delimiter important"><?php</span> <span class="token keyword">namespace</span> <span class="token package">App</span> <span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Illuminate Database Eloquent Model</span> <span class="token punctuation">;</span> <span class="token keyword">class</span> <span class="token class-name">User</span> <span class="token keyword">extends</span> <span class="token class-name">Authenticatable</span> <span class="token punctuation">{</span> <span class="token punctuation">.</span> <span class="token punctuation">.</span> <span class="token punctuation">.</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">avatar</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token variable">$this</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">hasOne</span> <span class="token punctuation">(</span> <span class="token single-quoted-string string">'AppAvatar'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> </span> |
Above we see that the first parameter passed in the hasOne
method is the name of the model associated with that table. When we declare like that, if we want to get the avatar of the user whose id is 1 for example, we simply do like this.
1 2 | <span class="token variable">$avatar</span> <span class="token operator">=</span> User <span class="token punctuation">:</span> <span class="token punctuation">:</span> <span class="token function">find</span> <span class="token punctuation">(</span> <span class="token number">1</span> <span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token property">avatar</span> <span class="token punctuation">;</span> |
Notice above Eloquent will automatically match the foreign key column with the user_id
name of the Avatar
table corresponding to the id
field of the User
table, if in the case the foreign key is not set to user_id
but sets a different name, we need to pass a second parameter 2.
1 2 | <span class="token keyword">return</span> <span class="token variable">$this</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">hasOne</span> <span class="token punctuation">(</span> <span class="token single-quoted-string string">'AppAvatar'</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'foreign_key'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
Similarly, if the primary key of the table you are linking to is not id
then you need to pass a third argument to make it understand that the foreign key of this column corresponds to the primary key with the other column.
1 2 | <span class="token keyword">return</span> <span class="token variable">$this</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">hasOne</span> <span class="token punctuation">(</span> <span class="token single-quoted-string string">'AppAvatar'</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'foreign_key'</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'local_key'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
Inverse
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <span class="token php language-php"><span class="token delimiter important"><?php</span> <span class="token keyword">namespace</span> <span class="token package">App</span> <span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Illuminate Database Eloquent Model</span> <span class="token punctuation">;</span> <span class="token keyword">class</span> <span class="token class-name">Avatar</span> <span class="token keyword">extends</span> <span class="token class-name">Model</span> <span class="token punctuation">{</span> <span class="token keyword">protected</span> <span class="token variable">$table</span> <span class="token operator">=</span> <span class="token single-quoted-string string">'avatar'</span> <span class="token punctuation">;</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">user</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$this</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">belongsTo</span> <span class="token punctuation">(</span> <span class="token single-quoted-string string">'AppUser'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> </span> |
In the previous example, we can from a user to call the corresponding avatar of that user, now we will also be able to query the same from this avatar to query out the user that belongs to it.
In the above example, Eloquent automatically matches the user_id
column in the Avatar
table with the id
column of the User
table. In Eloquent, the default foreign key confirmation is the omitted table name ‘s’ _id
, in this case the user_id
. If the foreign key in the Avatar
not set in accordance with the previous standard, it will need to declare one more second parameter.
1 2 | <span class="token keyword">return</span> <span class="token variable">$this</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">belongsTo</span> <span class="token punctuation">(</span> <span class="token single-quoted-string string">'AppUser'</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'foreign_key'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
If you do not want the foreign key map of the Avatar table with the id
column in the User
table but another column, for example, continue adding a third parameter as follows.
1 2 | <span class="token keyword">return</span> <span class="token variable">$this</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">belongsTo</span> <span class="token punctuation">(</span> <span class="token single-quoted-string string">'AppUser'</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'foreign_key'</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'other_key'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
2. One to Many
This relationship to signify a parent-child relationship. For example, a user
will have many posts
. Then this relationship will be expressed as follows.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <span class="token php language-php"><span class="token delimiter important"><?php</span> <span class="token keyword">namespace</span> <span class="token package">App</span> <span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Illuminate Database Eloquent Model</span> <span class="token punctuation">;</span> <span class="token keyword">class</span> <span class="token class-name">User</span> <span class="token keyword">extends</span> <span class="token class-name">Authenticatable</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">posts</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token variable">$this</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">hasMany</span> <span class="token punctuation">(</span> <span class="token single-quoted-string string">'AppPost'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> </span> |
Similarly, the One-One Eloquent relationship will automatically find the foreign key on the Post model, in this case the eloquent will find the foreign key “snake case” model name _id
, in the example above will be user_id
, Eloquent will be fake. user_id
is foreign key in the Post model. To query to multiple posts
belonging to a user
is simple by:
1 2 | <span class="token variable">$user</span> <span class="token operator">=</span> App <span class="token package">User</span> <span class="token punctuation">:</span> <span class="token punctuation">:</span> <span class="token function">find</span> <span class="token punctuation">(</span> <span class="token number">1</span> <span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token property">posts</span> <span class="token punctuation">;</span> |
and vice versa
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <span class="token php language-php"><span class="token delimiter important"><?php</span> <span class="token keyword">namespace</span> <span class="token package">App</span> <span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Illuminate Database Eloquent Model</span> <span class="token punctuation">;</span> <span class="token keyword">class</span> <span class="token class-name">Post</span> <span class="token keyword">extends</span> <span class="token class-name">Model</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">user</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token variable">$this</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">belongsTo</span> <span class="token punctuation">(</span> <span class="token single-quoted-string string">'AppUser'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> </span> |
3. Many to Many
This relationship is more complicated than the previous two. For example, a product
will belong to many orders
but an order
has many products
. To represent this relationship, we need to use a third table, we will name order_product
. and also will contain 2 columns, order_id
and product_id
. In this relationship, we will use the belongsToMany
method. Example of representing the Product
method with the order
table
1 2 3 4 5 6 7 8 9 10 11 12 | <span class="token keyword">namespace</span> <span class="token package">App</span> <span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Illuminate Database Eloquent Model</span> <span class="token punctuation">;</span> <span class="token keyword">class</span> <span class="token class-name">Product</span> <span class="token keyword">extends</span> <span class="token class-name">Model</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">orders</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token variable">$this</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">belongsToMany</span> <span class="token punctuation">(</span> <span class="token single-quoted-string string">'AppOrder'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Now want to retrieve a product
how many order
, just need
1 2 | <span class="token variable">$orders</span> <span class="token operator">=</span> App <span class="token package">Product</span> <span class="token punctuation">:</span> <span class="token punctuation">:</span> <span class="token function">find</span> <span class="token punctuation">(</span> <span class="token number">1</span> <span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token property">orders</span> <span class="token punctuation">;</span> |
Note that, Eloquent will automatically find the intermediate table named in alphabetical order, in this case the table will be named order_product
. However, if you want to name something else that is not a convention like product_order
then just pass the second argument to the belongsToMany
method.
1 2 | <span class="token keyword">return</span> <span class="token variable">$this</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">belongsToMany</span> <span class="token punctuation">(</span> <span class="token single-quoted-string string">'AppOrder'</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'product_order'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
Similarly, you can also customize the names of the two names of the associated columns, corresponding to the 3rd and 4th belongsToMany
of the belongsToMany
method. The third parameter will be the foreign key of the table defining the relationship and the fourth parameter is the table we want to join. For example in this case.
1 2 3 4 5 6 7 8 9 10 11 12 | <span class="token keyword">namespace</span> <span class="token package">App</span> <span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Illuminate Database Eloquent Model</span> <span class="token punctuation">;</span> <span class="token keyword">class</span> <span class="token class-name">Product</span> <span class="token keyword">extends</span> <span class="token class-name">Model</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">orders</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token variable">$this</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">belongsToMany</span> <span class="token punctuation">(</span> <span class="token single-quoted-string string">'AppOrder'</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'product_order'</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'product_id'</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'order_id'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
In contrast, for the Order table we define the following:
1 2 3 4 5 6 7 8 9 10 11 12 | <span class="token keyword">namespace</span> <span class="token package">App</span> <span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Illuminate Database Eloquent Model</span> <span class="token punctuation">;</span> <span class="token keyword">class</span> <span class="token class-name">Order</span> <span class="token keyword">extends</span> <span class="token class-name">Model</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">product</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token variable">$this</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">belongsToMany</span> <span class="token punctuation">(</span> <span class="token single-quoted-string string">'AppProduct'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
And we are similar to the definition of the Product
model, we can also pass parameters if we want
1 2 3 4 5 6 7 8 9 10 11 12 | <span class="token keyword">namespace</span> <span class="token package">App</span> <span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Illuminate Database Eloquent Model</span> <span class="token punctuation">;</span> <span class="token keyword">class</span> <span class="token class-name">Order</span> <span class="token keyword">extends</span> <span class="token class-name">Model</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">product</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token variable">$this</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">belongsToMany</span> <span class="token punctuation">(</span> <span class="token single-quoted-string string">'AppProduct'</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'product_order'</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'order_id'</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'product_id'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Get the value of the intermediate table To work with this Many to Many relationship, we need to use an intermediate table. Eloquent also helps us derive the values of this table. To access the intermediate table columns we will use the pivot
attribute. For example :
1 2 3 4 5 6 7 | <span class="token variable">$product</span> <span class="token operator">=</span> App <span class="token package">Product</span> <span class="token punctuation">:</span> <span class="token punctuation">:</span> <span class="token function">find</span> <span class="token punctuation">(</span> <span class="token number">1</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">foreach</span> <span class="token punctuation">(</span> <span class="token variable">$product</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token property">orders</span> <span class="token keyword">as</span> <span class="token variable">$order</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">echo</span> <span class="token variable">$order</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token property">pivot</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token property">created_at</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> |
By default, Eloquent only takes intermediate fields and created_at
, update_at
if we want to retrieve the value of another column, we need to declare more as follows, assuming we need to get additional address
fields.
1 2 | <span class="token keyword">return</span> <span class="token variable">$this</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">belongsToMany</span> <span class="token punctuation">(</span> <span class="token single-quoted-string string">'AppProduct'</span> <span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">withPivot</span> <span class="token punctuation">(</span> <span class="token single-quoted-string string">'address'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
Or when you want the created_at
and update_at
fields of the intermediate table to automatically update values, then declare more
1 2 | <span class="token keyword">return</span> <span class="token variable">$this</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">belongsToMany</span> <span class="token punctuation">(</span> <span class="token single-quoted-string string">'AppProduct'</span> <span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">withTimestamps</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
Sometimes users want to change the name of the pivot
attribute, so what should they do, just use the as
method declared in the model? For example
1 2 3 4 | <span class="token keyword">return</span> <span class="token variable">$this</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">belongsToMany</span> <span class="token punctuation">(</span> <span class="token single-quoted-string string">'AppProduct'</span> <span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token keyword">as</span> <span class="token punctuation">(</span> <span class="token single-quoted-string string">'newname'</span> <span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">withTimestamps</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
Now you want to access the properties of the intermediate table that replace pivot
with newname
.
1 2 3 4 5 6 7 | <span class="token variable">$product</span> <span class="token operator">=</span> App <span class="token package">Product</span> <span class="token punctuation">:</span> <span class="token punctuation">:</span> <span class="token function">find</span> <span class="token punctuation">(</span> <span class="token number">1</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">foreach</span> <span class="token punctuation">(</span> <span class="token variable">$product</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token property">orders</span> <span class="token keyword">as</span> <span class="token variable">$order</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">echo</span> <span class="token variable">$order</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token property">newname</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token property">created_at</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> |
Another question is that if you want to get products with the condition of intermediate tables, it will be like, very simple, Laravel also supports us in this regard.
1 2 3 4 5 | <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">products</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token variable">$this</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">belongsToMany</span> <span class="token punctuation">(</span> Product <span class="token punctuation">:</span> <span class="token punctuation">:</span> <span class="token keyword">class</span> <span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">wherePivot</span> <span class="token punctuation">(</span> <span class="token single-quoted-string string">'price'</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'>'</span> <span class="token punctuation">,</span> <span class="token number">20000</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> |
Here, we will retrieve orders with prices greater than 20,000.
4. Has One Through
This is a relationship that links tables together through an intermediate table. For example, there are 3 tables:
1 2 3 4 5 6 7 8 9 10 11 | users id - integer supplier_id - integer suppliers id - integer history id - integer user_id - integer |
Although the history
table is not supplier_id
, we can still access user's history
by hasOneThrough
relationship as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <span class="token php language-php"><span class="token delimiter important"><?php</span> <span class="token keyword">namespace</span> <span class="token package">App</span> <span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Illuminate Database Eloquent Model</span> <span class="token punctuation">;</span> <span class="token keyword">class</span> <span class="token class-name">Supplier</span> <span class="token keyword">extends</span> <span class="token class-name">Model</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">userHistory</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token variable">$this</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">hasOneThrough</span> <span class="token punctuation">(</span> <span class="token single-quoted-string string">'AppHistory'</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'AppUser'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> </span> |
With the first parameter passed as the name of the model we want to access, the second parameter is the intermediate model. We can also customize the keys related to this relationship as the following parameters to the relationship definition function.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <span class="token keyword">class</span> <span class="token class-name">Supplier</span> <span class="token keyword">extends</span> <span class="token class-name">Model</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">userHistory</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token variable">$this</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">hasOneThrough</span> <span class="token punctuation">(</span> <span class="token single-quoted-string string">'AppHistory'</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'AppUser'</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'supplier_id'</span> <span class="token punctuation">,</span> <span class="token comment">// Khóa ngoại của bảng trung gian user</span> <span class="token single-quoted-string string">'user_id'</span> <span class="token punctuation">,</span> <span class="token comment">// Khóa ngoại của bảng chúng ta muốn truy cập đến</span> <span class="token single-quoted-string string">'id'</span> <span class="token punctuation">,</span> <span class="token comment">// Khóa mà chúng ta muốn liên kết ở bảng supplier</span> <span class="token single-quoted-string string">'id'</span> <span class="token comment">// Khóa mà chúng ta muốn liên kết ở bảng user</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
We have the user
and history
tables defined as usual
1 2 3 4 5 6 7 8 9 10 11 12 13 | <span class="token comment">// User.php</span> <span class="token keyword">namespace</span> <span class="token package">App</span> <span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Illuminate Database Eloquent Model</span> <span class="token punctuation">;</span> <span class="token keyword">class</span> <span class="token class-name">User</span> <span class="token keyword">extends</span> <span class="token class-name">Model</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">supplier</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token variable">$this</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">belongsTo</span> <span class="token punctuation">(</span> Supplier <span class="token punctuation">:</span> <span class="token punctuation">:</span> <span class="token keyword">class</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
1 2 3 4 5 6 7 8 9 10 11 12 13 | <span class="token comment">// Supplier.php</span> <span class="token keyword">namespace</span> <span class="token package">App</span> <span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Illuminate Database Eloquent Model</span> <span class="token punctuation">;</span> <span class="token keyword">class</span> <span class="token class-name">Supplier</span> <span class="token keyword">extends</span> <span class="token class-name">Model</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">user</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token variable">$this</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">hasOne</span> <span class="token punctuation">(</span> User <span class="token punctuation">:</span> <span class="token punctuation">:</span> <span class="token keyword">class</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
5. Has Many Through
This has many through
relationship provides us with an easier way to access linked tables through intermediate tables. For example, a Team
has many Post
through intermediate tables as User
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | teams id - integer name - string users id - integer team_id - integer name - string posts id - integer user_id - integer title - string |
Although board posts
do not contain foreign key team_id
, but with relations hasManyThrough
will give us get all posts
of teams
by $team->posts
. To do this, Eloquent will check team_id
through the users
table. We will show the following relationship:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <span class="token php language-php"><span class="token delimiter important"><?php</span> <span class="token keyword">namespace</span> <span class="token package">App</span> <span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Illuminate Database Eloquent Model</span> <span class="token punctuation">;</span> <span class="token keyword">class</span> <span class="token class-name">Team</span> <span class="token keyword">extends</span> <span class="token class-name">Model</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">posts</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token variable">$this</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">hasManyThrough</span> <span class="token punctuation">(</span> <span class="token single-quoted-string string">'AppPost'</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'AppUser'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> </span> |
The first parameter of this relationship is the model name we want to access, the second parameter is the intermediate model. We can also customize the name of the foreign key by adding parameters, with the third parameter being the foreign key of the intermediate table, the fourth parameter is the foreign key of the table we want to call, the parameter 5th is the field we want to link to in the table we are using, the 6th parameter is the field we want to link to in the intermediate table.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <span class="token keyword">class</span> <span class="token class-name">Tean</span> <span class="token keyword">extends</span> <span class="token class-name">Model</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">posts</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token variable">$this</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">hasManyThrough</span> <span class="token punctuation">(</span> <span class="token single-quoted-string string">'AppPost'</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'AppUser'</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'country_id'</span> <span class="token punctuation">,</span> <span class="token comment">// khóa ngoại của bảng trung gian</span> <span class="token single-quoted-string string">'user_id'</span> <span class="token punctuation">,</span> <span class="token comment">// khóa ngoại của bảng mà chúng ta muốn gọi tới</span> <span class="token single-quoted-string string">'id'</span> <span class="token punctuation">,</span> <span class="token comment">//trường mà chúng ta muốn liên kết ở bảng đang sử dụng</span> <span class="token single-quoted-string string">'id'</span> <span class="token comment">// trường mà chúng ta muốn liên kết ở bảng trung gian.</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
6. Polymorphic
This is a polymorphic relationship in Laravel that allows one Model to belong to many other Models with only one associate.
6.1 One to One Polymorphic
This relationship is similar to the One to One
relationship, but the purpose of this relationship is that one model can belong to one or more other models. For example, a post
has an image
and a product
also has an image
, if normal, you must create two more tables: post_image
to save the image of the post
and product_iamge
to save the image of the product
, if there are billions of tables needed Image has to create more tables to save the image, so it will be too complicated and confusing, thus creating this polymorphic relationship. For example :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | posts id - integer name - string products id - integer name - string images id - integer url - string imageable_id - integer imageable_type - string |
This is the way to build this polymorphic relationship. With imageable_id
id
of the posts
table and the products
table will be saved, while the imageable_type
field will store the Post
and Product
model class names. According to laravel’s convention, the intermediate storage table will require 2 id
and type
fields, but for more clarity, it will save the prefix tên_bảng_bỏ_s +able_
. Model structure
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | <span class="token php language-php"><span class="token delimiter important"><?php</span> <span class="token keyword">namespace</span> <span class="token package">App</span> <span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Illuminate Database Eloquent Model</span> <span class="token punctuation">;</span> <span class="token keyword">class</span> <span class="token class-name">Image</span> <span class="token keyword">extends</span> <span class="token class-name">Model</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">imageable</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token variable">$this</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">morphTo</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">class</span> <span class="token class-name">Post</span> <span class="token keyword">extends</span> <span class="token class-name">Model</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">image</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token variable">$this</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">morphOne</span> <span class="token punctuation">(</span> <span class="token single-quoted-string string">'AppImage'</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'imageable'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">class</span> <span class="token class-name">Product</span> <span class="token keyword">extends</span> <span class="token class-name">Model</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">image</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token variable">$this</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">morphOne</span> <span class="token punctuation">(</span> <span class="token single-quoted-string string">'AppImage'</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'imageable'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> </span> |
To retrieve an image belonging to posts
, it will point to the image
.
1 2 3 4 | <span class="token variable">$post</span> <span class="token operator">=</span> App <span class="token package">Post</span> <span class="token punctuation">:</span> <span class="token punctuation">:</span> <span class="token function">find</span> <span class="token punctuation">(</span> <span class="token number">1</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token variable">$image</span> <span class="token operator">=</span> <span class="token variable">$post</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token property">image</span> <span class="token punctuation">;</span> |
and vice versa from image
can be inferred by post
or product
depending on it.
1 2 3 4 | <span class="token variable">$image</span> <span class="token operator">=</span> App <span class="token package">Image</span> <span class="token punctuation">:</span> <span class="token punctuation">:</span> <span class="token function">find</span> <span class="token punctuation">(</span> <span class="token number">1</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token variable">$imageable</span> <span class="token operator">=</span> <span class="token variable">$image</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token property">imageable</span> <span class="token punctuation">;</span> |
6.1 One to Many Polymorphic
This relationship is similar to the One to Many
relationship. For example, a User
can comment on both Post
and Video
, only need a comments
table in this case
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | posts id - integer title - string body - text videos id - integer title - string url - string comments id - integer body - text commentable_id - integer commentable_type - string |
Model structure
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | <span class="token php language-php"><span class="token delimiter important"><?php</span> <span class="token keyword">namespace</span> <span class="token package">App</span> <span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Illuminate Database Eloquent Model</span> <span class="token punctuation">;</span> <span class="token keyword">class</span> <span class="token class-name">Comment</span> <span class="token keyword">extends</span> <span class="token class-name">Model</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">commentable</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token variable">$this</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">morphTo</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">class</span> <span class="token class-name">Post</span> <span class="token keyword">extends</span> <span class="token class-name">Model</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">comments</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token variable">$this</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">morphMany</span> <span class="token punctuation">(</span> <span class="token single-quoted-string string">'AppComment'</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'commentable'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">class</span> <span class="token class-name">Video</span> <span class="token keyword">extends</span> <span class="token class-name">Model</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">comments</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token variable">$this</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">morphMany</span> <span class="token punctuation">(</span> <span class="token single-quoted-string string">'AppComment'</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'commentable'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> </span> |
Retrieving the value of all the comment
on the post
we do is as follows
1 2 3 4 5 6 | <span class="token variable">$post</span> <span class="token operator">=</span> App <span class="token package">Post</span> <span class="token punctuation">:</span> <span class="token punctuation">:</span> <span class="token function">find</span> <span class="token punctuation">(</span> <span class="token number">1</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">foreach</span> <span class="token punctuation">(</span> <span class="token variable">$post</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token property">comments</span> <span class="token keyword">as</span> <span class="token variable">$comment</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">echo</span> <span class="token variable">$comment</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token property">content</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> |
or from comment
to get back the post
or videos
belong to it
1 2 3 4 | <span class="token variable">$comment</span> <span class="token operator">=</span> App <span class="token package">Comment</span> <span class="token punctuation">:</span> <span class="token punctuation">:</span> <span class="token function">find</span> <span class="token punctuation">(</span> <span class="token number">1</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token variable">$commentable</span> <span class="token operator">=</span> <span class="token variable">$comment</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token property">commentable</span> <span class="token punctuation">;</span> |
6.1 Many to Many Polymorphic
This relationship will be a bit more complicated. For example, a good post
or video
may have lots of tags
. Using a many to many polymorphic
allows you to query to retrieve tags
belong to a post
or video
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | posts id - integer name - string videos id - integer name - string tags id - integer name - string taggables tag_id - integer taggable_id - integer taggable_type - string |
Model structure
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | //post.php <span class="token php language-php"><span class="token delimiter important"><?php</span> <span class="token keyword">namespace</span> <span class="token package">App</span> <span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Illuminate Database Eloquent Model</span> <span class="token punctuation">;</span> <span class="token keyword">class</span> <span class="token class-name">Post</span> <span class="token keyword">extends</span> <span class="token class-name">Model</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">tags</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token variable">$this</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">morphToMany</span> <span class="token punctuation">(</span> <span class="token single-quoted-string string">'AppTag'</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'taggable'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> </span> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | //tag.php <span class="token php language-php"><span class="token delimiter important"><?php</span> <span class="token keyword">namespace</span> <span class="token package">App</span> <span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Illuminate Database Eloquent Model</span> <span class="token punctuation">;</span> <span class="token keyword">class</span> <span class="token class-name">Tag</span> <span class="token keyword">extends</span> <span class="token class-name">Model</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">posts</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token variable">$this</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">morphedByMany</span> <span class="token punctuation">(</span> <span class="token single-quoted-string string">'AppPost'</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'taggable'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">videos</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token variable">$this</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">morphedByMany</span> <span class="token punctuation">(</span> <span class="token single-quoted-string string">'AppVideo'</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'taggable'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> </span> |
Ok now want to retrieve the
tag
belonging to a post
we do the same but the other relationship.1 2 3 4 5 6 7 | <span class="token variable">$post</span> <span class="token operator">=</span> App <span class="token package">Post</span> <span class="token punctuation">:</span> <span class="token punctuation">:</span> <span class="token function">find</span> <span class="token punctuation">(</span> <span class="token number">1</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">foreach</span> <span class="token punctuation">(</span> <span class="token variable">$post</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token property">tags</span> <span class="token keyword">as</span> <span class="token variable">$tag</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">//</span> <span class="token punctuation">}</span> |
or vice versa
1 2 3 4 5 6 | <span class="token variable">$tag</span> <span class="token operator">=</span> App <span class="token package">Tag</span> <span class="token punctuation">:</span> <span class="token punctuation">:</span> <span class="token function">find</span> <span class="token punctuation">(</span> <span class="token number">1</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">foreach</span> <span class="token punctuation">(</span> <span class="token variable">$tag</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token property">videos</span> <span class="token keyword">as</span> <span class="token variable">$video</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">//</span> <span class="token punctuation">}</span> |