Trong cuộc sống, mọi sự vật đều liên kết với nhau, ví dụ như một cuốn sách phải có tác giả, hay một ngôi trường phải có nhiều lớp học. Ở trong cơ sở dữ liệu cũng vậy, các bảng cũng có thể liên kết với nhau. Ở trong Laravel đã cung cấp sẵn cho chúng ta các mối quan hệ để có thể giảm thiếu thời gian công sức của các lập trình viên. Nó giúp chúng ta truy vấn các bảng trở nên dễ dàng hơn. Ở bài này chúng ta cùng nhau tìm hiểu về các loại quan hệ
- One to One
- One to Many
- Many to Many
- Has One Through
- Has Many Through
- Polymorphic Relations
Các mối quan hệ trong Laravel
1. One to One
Đây là một kiểu quan hệ đơn giản nhất, mà chúng ta có thể hiểu rằng cái này chỉ phụ thuộc vào cái kia và ngược lại. Ví dụ cho dễ hình dung, ta có bảng Users
và bảng Avatar
thì ở đây một người dùng thì chỉ có một cái avatar và chiếc avatar này chỉ đại diện cho user đó. Để biểu diễn mối quan hệ này ta sử dụng method hasOne
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<span class="token punctuation"></span>Database<span class="token punctuation"></span>Eloquent<span class="token punctuation"></span>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> |
Ở trên ta thấy tham số truyền vào đầu tiên trong method hasOne
là tên của model liên quan đến với bảng đó. Khi ta khai báo như vậy, nếu muốn lấy avatar của user có id là 1 chả hạn, ta đơn giản chỉ làm như thế này.
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> |
Chú ý ở trên Eloquent sẽ tự động match cột khóa ngoại có tên user_id
của bảng Avatar
tương ứng với trường id
của bảng User
, nếu trong trường hợp khóa ngoại không đặt là user_id
mà đặt một tên khác thì cần truyền thêm một tham số thứ 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> |
Tương tự với trường hợp nếu khóa chính của bảng mà bạn liên kết, bạn không đặt là id
thì cần truyền tiếp một tham số thứ 3 để cho nó hiểu được là khóa ngoại của cột này tương ứng với khóa chính với cột kia
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<span class="token punctuation"></span>Database<span class="token punctuation"></span>Eloquent<span class="token punctuation"></span>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> |
Ở ví dụ trước thì ta có thể từ một user để gọi tới avatar tương ứng của user đó, giờ chúng ta cũng sẽ có thể truy vấn tương tự từ avatar này để truy vấn ra user thuộc về nó.
Ở ví dụ trên, Eloquent đã tự động match cột user_id
ở bảng Avatar
với cột id
của bảng User
. Trong Eloquent mặc định xác nhận khóa ngoại là tên bảng bỏ ‘s’ _id
, ở trong trường hợp này là user_id
. Nếu khóa ngoại ở bạng Avatar
không đặt đúng theo qui chuẩn trước đó thì sẽ cần phải khai báo thêm 1 tham số thứ 2 nữa.
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> |
Nếu như bạn không muốn map foreign key của bảng Avatar với cột id
ở bảng User
mà lại là 1 cột khác chả hạn thì tiếp tục thêm 1 tham số thứ 3 như sau.
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
Mối quan hệ này để biểu thị một mối quan hệ cha-con. Ví dụ một user
thì sẽ có nhiều bài posts
. Thì mối quan hệ này sẽ được biểu diễn như sau.
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<span class="token punctuation"></span>Database<span class="token punctuation"></span>Eloquent<span class="token punctuation"></span>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> |
Cũng tương tự quan hệ One-One Eloquent sẽ tự động tìm khóa ngoại ở model Post , ở trong trường hợp này eloquent sẽ tìm tới khóa ngoại là “snake case” tên model _id
, ở ví dụ trên sẽ là user_id
, Eloquent sẽ giả định user_id
là khóa ngoại ở model Post. Để truy vấn tới nhiều posts
thuộc một user
quá đơn giản bằng cách:
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> |
và ngược lại
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<span class="token punctuation"></span>Database<span class="token punctuation"></span>Eloquent<span class="token punctuation"></span>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
Quan hệ này thì nó sẽ phức tạp hơn với hai quan hệ trước nó. Ví dụ một product
sẽ thuộc nhiều orders
mà một order
lại có nhiều products
. Để biểu diễn được quan hệ này chúng ta cần sử dụng đến một bảng thế 3, mình sẽ đặt tên là order_product
.
và đồng thời sẽ chứa 2 cột là order_id
và product_id
. Ở mối quan hệ này ta sẽ sử dụng method belongsToMany
. Ví dụ biểu diễn method Product
với bảng order
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<span class="token punctuation"></span>Database<span class="token punctuation"></span>Eloquent<span class="token punctuation"></span>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> |
bây giờ muốn lấy ra được một product
có bao nhiêu order
thì chỉ cần
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> |
Có một chú ý là, Eloquent sẽ tự động tìm đến bảng trung gian đặt tên theo thứ tự alphabet, trong trường hợp này bảng sẽ tên là order_product
. Tuy nhiên nếu bạn muốn đặt 1 cái tên khác mà không theo quy ước ví dụ là product_order
thì chỉ cần truyền thêm tham số thứ 2 vào method belongsToMany
.
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> |
Tương tự bạn cũng có thể custom lại tên của 2 tên của cột liên kết tương ứng với tham số thứ 3 và thứ 4 của method belongsToMany
.
Với tham số thứ 3 sẽ là khóa ngoại của bảng đang định nghĩa quan hệ và tham số thứ 4 là bảng chúng ta muốn join. Ví dụ trong trường hợp này.
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<span class="token punctuation"></span>Database<span class="token punctuation"></span>Eloquent<span class="token punctuation"></span>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> |
Ngược lại, đối với bảng Order ta định nghĩa như sau:
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<span class="token punctuation"></span>Database<span class="token punctuation"></span>Eloquent<span class="token punctuation"></span>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> |
và chúng ta cũng tương tự như định nghĩa model Product
, chúng ta cũng có thể truyền các tham số vào nếu muốn
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<span class="token punctuation"></span>Database<span class="token punctuation"></span>Eloquent<span class="token punctuation"></span>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> |
Lấy giá trị của bảng trung gian
Để làm việc với mối quan hệ Many to Many này thì chúng ta cần sử dụng đến một bảng trung gian. Eloquent cũng hỗ trợ giúp chúng ta lấy được các giá trị của bảng này. Để truy cập đến các cột của bảng trung gian chúng ta sẽ sử dụng thuộc tính pivot
. Ví dụ :
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> |
Theo mặc định thì Eloquent chỉ lấy các trường trung gian và created_at
, update_at
nếu chúng ta muốn lấy ra giá trị của một cột khác thì cần khai báo thêm như sau, giả sử chúng ta cần lấy thêm trường address
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> |
Hoặc là khi bạn muốn hai trường created_at
và update_at
của bảng trung gian tự động cập nhật giá trị thì khai báo thêm
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> |
Đôi khi người dùng lại muốn thay đổi tên của thuôc tính pivot
thì phải làm như thế nào, chỉ cần sử dụng method as
được khai báo trong model là xong. Ví dụ
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> |
giờ muốn truy cập các thuộc tính của bảng trung gian thay thế pivot
thành newname
là được.
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> |
Một câu hỏi nữa được đặt ra là nếu muốn lấy các sản phẩm với điều kiện của bảng trung gian là hợp lệ thì sẽ như thế nào, rất đơn giản, Laravel cũng hỗ trợ chúng ta trong vấn đề này.
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> |
Ở đây sẽ lấy ra các Order có giá lớn hơn 20000.
4. Has One Through
Đây là một mối quan hệ liên kết các bảng với nhau thông qua một bảng trung gian
Ví dụ có 3 bảng:
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 |
Mặc dù bảng history
không chứ supplier_id
nhưng chúng ta vẫn có thể truy cập đến user's history
bới mối quan hệ hasOneThrough
như sau
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<span class="token punctuation"></span>Database<span class="token punctuation"></span>Eloquent<span class="token punctuation"></span>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> |
Với tham số thứ nhất được truyền vào là tên của model mà chúng ta muốn truy cập, tham số thứ 2 là model trung gian. Chúng ta cũng có thể custom các key liên quan đến mối quan hệ này lần lượt là các tham số sau vào hàm định nghĩa quan hệ.
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> |
hai bảng user
và history
chúng ta định nghia như bình thường
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<span class="token punctuation"></span>Database<span class="token punctuation"></span>Eloquent<span class="token punctuation"></span>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<span class="token punctuation"></span>Database<span class="token punctuation"></span>Eloquent<span class="token punctuation"></span>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
Mối quan hệ has many through
này cung cấp cho chúng ta cách truy cập bảng liên kết dễ dàng hơn thông qua bảng trung gian. Ví dụ một Team
có nhiều bài Post
thông qua bảng trung gian là 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 |
Mặc dù bảng posts
không chứa khóa ngoại team_id
, nhưng với quan hệ hasManyThrough
sẽ cung cấp cho chúng ta lấy tất cả posts
của một teams
bằng cách $team->posts
. Để thực hiện việc này thì Eloquent sẽ kiểm tra team_id
thông qua bảng users
. Chúng ta sẽ biểu diễn quan hệ như sau:
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<span class="token punctuation"></span>Database<span class="token punctuation"></span>Eloquent<span class="token punctuation"></span>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> |
Tham số đầu tiên của quan hệ này là tên model mà chúng ta muốn truy cập, tham số thứ hai là model trung gian. Chúng ta cũng có thể custom lại tên của các khóa ngoại bằng cách thêm các tham số, với tham số thứ 3 là khóa ngoại của bảng trung gian, tham số thứ 4 là khóa ngoại của bảng mà chúng ta muốn gọi tới, tham số thứ 5 là trường mà chúng ta muốn liên kết ở bảng đang sử dụng, tham số thứ 6 là trường mà chúng ta muốn liên kết ở bảng trung gian.
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
Đây là mối quan hệ đa hình trong Laravel cho phép 1 Model có thể belongsTo nhiều Model khác mà chỉ cần dùng 1 associate.
6.1 One to One Polymorphic
Mối quan hệ này tương tự quan hệ One to One
, tuy nhiên mục đích của mối quan hệ này là 1 model có thể belongsTo 1 hay nhiều model khác. Ví dụ một bài post
có một image
và một product
cũng có một image
, nếu như bình thường thì các bạn phải tạo thêm 2 bảng là post_image
để lưu ảnh của post
và product_iamge
để lưu ảnh của product
, nếu có ti tỉ các bảng cần đến image thì lại phải tạo thêm bấy nhiêu bảng để lưu ảnh, vậy thì sẽ quá phức tạp và rối, vậy nên mới sinh ra mối quan hệ polymorphic này. Ví dụ :
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 |
Đây là cách để xây dựng mối quan hệ polymorphic này. Với imageable_id
sẽ lưu id
của bảng posts
và bảng products
, còn trường imageable_type
sẽ lưu tên class model Post
và Product
. Theo convention của laravel thì bảng lưu trung gian sẽ bắt buộc phải có 2 trường id
và type
nhưng để rõ ràng hơn thì sẽ lưu thêm tiền tố tên_bảng_bỏ_s +able_
.
Cấu trúc model
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<span class="token punctuation"></span>Database<span class="token punctuation"></span>Eloquent<span class="token punctuation"></span>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> |
Để lấy ra image thuộc bài posts
thì sẽ trỏ tới image
là được.
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> |
và ngược lại từ image
có thể suy ngược lại post
hay product
phụ thuộc vào nó.
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
Mối quan hệ này cũng gần giống với quan hệ One to Many
. Ví dụ một User
có thể comment ở cả Post
lẫn Video
thì chỉ cần 1 bảng comments
trong trường hợp này
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 |
Cấu trúc model
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<span class="token punctuation"></span>Database<span class="token punctuation"></span>Eloquent<span class="token punctuation"></span>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> |
Lấy ra các giá trị tất cả các comment
của post
ta làm như sau
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> |
hay là từ comment
để lấy ngược lại cái post
hay videos
thuộc về nó
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
Quan hệ này sẽ phức tạp hơn một chút. Ví dụ một post
hay là video
có thể có nhiều tags
. Sử dụng mối quan hệ many to many polymorphic
cho phép bạn truy vấn lấy ra các tags
thuộc về một post
hay 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 |
Cấu trúc model
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<span class="token punctuation"></span>Database<span class="token punctuation"></span>Eloquent<span class="token punctuation"></span>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<span class="token punctuation"></span>Database<span class="token punctuation"></span>Eloquent<span class="token punctuation"></span>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 bây giờ muốn lấy ra các tag
thuộc về một post
ta cũng làm tương tự nhưng mối quan hệ khác.
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> |
hoặc là ngược lại
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> |