Giới thiệu
Accessors và Murator cho phép bạn format(định dạng) lại các thuộc tính của Eloquent khi mà chúng ta lấy ra hoặc thêm mới dựa trên Model. Ví dụ, khi thêm mới một user bạn muốn trước khi thêm mới thì nó sẽ tự động mã hóa giá trị của password trước khi được lưu vào cơ sở dữ liệu hay là lấy ra một cái tên trong cơ sở dữ liệu dưới dạng là in hoa thì accessors
và murators
sẽ giúp chúng ta làm điều này.
Ngoài ra Eloquent cũng có thể tự động chuyển trường date thành Carbon instance hay là chuyển 1 đoạn text thành kiểu dữ liệu json.
1. Định nghĩa một Accessors
Nói sơ qua một chút là accessors
sẽ giúp chúng ta định dạng dữ liệu khi chúng ta get dữ liệu từ cơ sở dữ liệu.
Giả sử chúng ta có trường name
trong bảng user
và muốn khi lấy dữ liệu ra nó sẽ ở dạng in hoa. Trước tiên chúng ta cần phải tạo một method để định nghĩa việc này trong model User
dưới dạng get
+ tên trường in hoa chữ cái đầu
+ Attribute
. Ở trường hợp này method được viết sẽ là getNameAttribute
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <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">getNameAttribute</span><span class="token punctuation">(</span><span class="token variable">$value</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token function">strtoupper</span><span class="token punctuation">(</span><span class="token variable">$value</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> </span> |
Giờ thử test xem kết quả như thế nào nhé, các bạn sẽ tạo một route
như sau:
1 2 3 4 5 6 | Route<span class="token punctuation">:</span><span class="token punctuation">:</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token single-quoted-string string">'/accessors'</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <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 punctuation">;</span> <span class="token keyword">return</span> <span class="token variable">$user</span><span class="token operator">-</span><span class="token operator">></span><span class="token property">name</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> |
giờ các bạn truy cập localhost:8000/accessors và xem kết quả.
Hay thậm chí các bạn có thể tự định nghĩa một thuộc tính mới với các thuộc tính có sẵn ví dụ :
1 2 3 4 5 | <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">getFullNameAttribute</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 double-quoted-string string">"<span class="token interpolation"><span class="token punctuation">{</span><span class="token variable">$this</span><span class="token operator">-</span><span class="token operator">></span><span class="token property">first_name</span><span class="token punctuation">}</span></span> <span class="token interpolation"><span class="token punctuation">{</span><span class="token variable">$this</span><span class="token operator">-</span><span class="token operator">></span><span class="token property">last_name</span><span class="token punctuation">}</span></span>"</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> |
cách lấy ra cũng tương tự
1 2 | <span class="token variable">$user</span><span class="token operator">-</span><span class="token operator">></span><span class="token property">fullname</span><span class="token punctuation">;</span> |
2. Định nghĩa một murators.
Khác với accessors
thì murators
dùng để format dữ liệu trước khi lưu vào cơ sở dữ liệu. Để định nghĩa một murators
gần giống với accessors
chỉ khác là tiền tố sẽ là set
. Ví dụ ta sẽ định dạng lại trường name
thành không in hoa trước khi được lưu vào cơ sở dữ liệu. Vậy method ở đây sẽ là setNameAttribute
1 2 3 4 5 6 7 8 9 10 11 12 13 | <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">setNameAttribute</span><span class="token punctuation">(</span><span class="token variable">$value</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 property">attributes</span><span class="token punctuation">[</span><span class="token single-quoted-string string">'name'</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">strtolower</span><span class="token punctuation">(</span><span class="token variable">$value</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Để test chúng ta cũng tạo một route với nội dung:
1 2 3 4 5 6 7 | Route<span class="token punctuation">:</span><span class="token punctuation">:</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token single-quoted-string string">'/murators'</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <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 punctuation">;</span> <span class="token variable">$user</span><span class="token operator">-</span><span class="token operator">></span><span class="token property">name</span> <span class="token operator">=</span> <span class="token double-quoted-string string">"CCC"</span><span class="token punctuation">;</span> <span class="token variable">$user</span><span class="token operator">-</span><span class="token operator">></span><span class="token function">save</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">$user</span><span class="token operator">-</span><span class="token operator">></span><span class="token property">name</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> |
Để kiểm tra dữ liệu được lưu đúng hay không mở php artisan tinker
lên để kiểm tra AppUser::find(1)
, chúng ta sẽ thấy giá tri của trường name
vừa được lưu sẽ là ccc
.
3. Date Murators
Mặc định thì Eloquent sẽ tự động chuyển 2 trường created_at
và update_at
thành Carbon instance, và nó được cung cấp rất nhiều các hàm hữu ích. Chúng ta cũng có thể thêm các thuộc tính date bằng cách sử dụng $date
trong model
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <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">Model</span> <span class="token punctuation">{</span> <span class="token comment">/** * The attributes that should be mutated to dates. * * @var array */</span> <span class="token keyword">protected</span> <span class="token variable">$dates</span> <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token single-quoted-string string">'seen_at'</span><span class="token punctuation">,</span> <span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> </span> |
Khi một trường là kiểu date
bạn có thể đặt giá trị cho nó là một UNIX timestamp
, date string (Y-m-d), date-time string hoặc là một instance của Carbon, và giá trị của date sẽ tự động lưu trong database.
Date formats
Mặc định timestamps được định dạng là Y-m-d H:i:s
, bạn có thể custom lại định dạng này bằng cách sử dụng thuộc tính dateFormat
trong model, thuộc tính này sẽ định dạng lại là kiểu dữ liệu date sẽ được lưu như thế nào trong database.
1 2 3 4 5 6 7 8 9 10 11 | <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">Model</span> <span class="token punctuation">{</span> <span class="token keyword">protected</span> <span class="token variable">$dateFormat</span> <span class="token operator">=</span> <span class="token single-quoted-string string">'Y-m-d'</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> </span> |
4. Attribute Casting
Thuộc tính $cast
giúp chuyển đổi các thuộc tính sang các kiểu dữ liệu bình thường. Thuộc tính $cast
thường là một array với key là tên của thuộc tính cần chuyển và value là kiểu dữ liệu mà bạn muốn chuyển. Các kiểu dữ liệu mà thuộc tính $cast
hỗ trợ : integer, real, float, double, decimal:<digits>, string, boolean, object, array, collection, date, datetime, and timestamp
.
Ví dụ, ta có thuộc tính is_admin
được lưu trong database là 0
và 1
với kiểu dữ liệu integer
nhưng bạn lại muốn sử dụng nó như kiểu dữ liệu boolean
thì làm như sau
1 2 3 4 5 6 7 8 9 10 11 12 13 | <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">Model</span> <span class="token punctuation">{</span> <span class="token keyword">protected</span> <span class="token variable">$casts</span> <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token single-quoted-string string">'is_admin'</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token single-quoted-string string">'boolean'</span><span class="token punctuation">,</span> <span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> </span> |
rồi chúng ta sử dụng is_admin
như một thuộc tính có kiểu dữ liệu boolean
1 2 3 4 5 6 | <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 punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$user</span><span class="token operator">-</span><span class="token operator">></span><span class="token property">is_admin</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span> |
Custom cast
Bạn có thể định nghĩa một thuộc tính cast
cho riêng bạn bằng cách tạo ra một lớp implements từ CastsAttributes
interface. Có một điểm phải chú ý là class mới được tạo ra này phải tồn tại 2 method get
và set
với những nhiệm vụ khách nhau. Phương thức get
dùng để chuyển đổi dữ liệu trong database thành kiểu dữ liệu cast
mà bạn định nghĩa, còn phương thức set
có nhiệm vụ ngược lại để chuyển dữ liệu được chuyển đổi thành kiểu dữ liệu gốc để lưu trong database. Ví dụ chúng ta custom thuộc tính cast
là kiểu dữ liệu json.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <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 class="token punctuation"></span>Casts</span><span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation"></span>Contracts<span class="token punctuation"></span>Database<span class="token punctuation"></span>Eloquent<span class="token punctuation"></span>CastsAttributes</span><span class="token punctuation">;</span> <span class="token keyword">class</span> <span class="token class-name">Json</span> <span class="token keyword">implements</span> <span class="token class-name">CastsAttributes</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">get</span><span class="token punctuation">(</span><span class="token variable">$model</span><span class="token punctuation">,</span> <span class="token variable">$key</span><span class="token punctuation">,</span> <span class="token variable">$value</span><span class="token punctuation">,</span> <span class="token variable">$attributes</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token function">json_decode</span><span class="token punctuation">(</span><span class="token variable">$value</span><span class="token punctuation">,</span> <span class="token boolean">true</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">set</span><span class="token punctuation">(</span><span class="token variable">$model</span><span class="token punctuation">,</span> <span class="token variable">$key</span><span class="token punctuation">,</span> <span class="token variable">$value</span><span class="token punctuation">,</span> <span class="token variable">$attributes</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token function">json_encode</span><span class="token punctuation">(</span><span class="token variable">$value</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> </span> |
Rồi chúng ta sẽ sử dụng nó ở model.
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">App<span class="token punctuation"></span>Casts<span class="token punctuation"></span>Json</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">protected</span> <span class="token variable">$casts</span> <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token single-quoted-string string">'options'</span> <span class="token operator">=</span><span class="token operator">></span> Json<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> </span> |
Array & JSON Casting
Cast
kiểu array rất hữu dụng khi chúng ta sử dụng chúng với column được lưu dưới dạng json.
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">User</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">$casts</span> <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token single-quoted-string string">'options'</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token single-quoted-string string">'array'</span><span class="token punctuation">,</span> <span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> </span> |
Khi khai báo thế này thì chúng ta sẽ sử dụng và xử lý dữ liệu như với array trong PHP. Khi bạn set giá trị cho thuộc tính options
, mảng đã cho sẽ tự động được chuyển hóa hóa trở lại thành JSON để lưu trữ:
1 2 3 4 5 6 7 8 9 10 | <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 punctuation">;</span> <span class="token variable">$options</span> <span class="token operator">=</span> <span class="token variable">$user</span><span class="token operator">-</span><span class="token operator">></span><span class="token property">options</span><span class="token punctuation">;</span> <span class="token variable">$options</span><span class="token punctuation">[</span><span class="token single-quoted-string string">'key'</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token single-quoted-string string">'value'</span><span class="token punctuation">;</span> <span class="token variable">$user</span><span class="token operator">-</span><span class="token operator">></span><span class="token property">options</span> <span class="token operator">=</span> <span class="token variable">$options</span><span class="token punctuation">;</span> <span class="token variable">$user</span><span class="token operator">-</span><span class="token operator">></span><span class="token function">save</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> |
Date Casting
Khi sử dụng cast
với kiểu dữ liệu là date và datetime, chúng ta có thể định dạng lại cho kiểu dữ liệu này
1 2 3 4 | <span class="token keyword">protected</span> <span class="token variable">$casts</span> <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token single-quoted-string string">'created_at'</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token single-quoted-string string">'datetime:Y-m-d'</span><span class="token punctuation">,</span> <span class="token punctuation">]</span><span class="token punctuation">;</span> |
Query Time Casting
Đôi khi bạn có thể sử dụng cả cast
trong các câu truy vấn
1 2 3 4 5 6 7 8 9 | <span class="token keyword">use</span> <span class="token package">App<span class="token punctuation"></span>Post</span><span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">App<span class="token punctuation"></span>User</span><span class="token punctuation">;</span> <span class="token variable">$users</span> <span class="token operator">=</span> User<span class="token punctuation">:</span><span class="token punctuation">:</span><span class="token function">select</span><span class="token punctuation">(</span><span class="token punctuation">[</span> <span class="token single-quoted-string string">'users.*'</span><span class="token punctuation">,</span> <span class="token single-quoted-string string">'last_posted_at'</span> <span class="token operator">=</span><span class="token operator">></span> Post<span class="token punctuation">:</span><span class="token punctuation">:</span><span class="token function">selectRaw</span><span class="token punctuation">(</span><span class="token single-quoted-string string">'MAX(created_at)'</span><span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">></span><span class="token function">whereColumn</span><span class="token punctuation">(</span><span class="token single-quoted-string string">'user_id'</span><span class="token punctuation">,</span> <span class="token single-quoted-string string">'users.id'</span><span class="token punctuation">)</span> <span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token operator">-</span><span class="token operator">></span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> |
Thuộc tính last_posted_at
dựa trên kết quả của câu selectRaw, nó sẽ hợp lý hơn nếu chúng ta set kiểu dữ liệu cho last_posted_at
là kiểu date, đơn giản bằng cách sử dụng phương thức withCasts
.
1 2 3 4 5 6 7 8 | <span class="token variable">$users</span> <span class="token operator">=</span> User<span class="token punctuation">:</span><span class="token punctuation">:</span><span class="token function">select</span><span class="token punctuation">(</span><span class="token punctuation">[</span> <span class="token single-quoted-string string">'users.*'</span><span class="token punctuation">,</span> <span class="token single-quoted-string string">'last_posted_at'</span> <span class="token operator">=</span><span class="token operator">></span> Post<span class="token punctuation">:</span><span class="token punctuation">:</span><span class="token function">selectRaw</span><span class="token punctuation">(</span><span class="token single-quoted-string string">'MAX(created_at)'</span><span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">></span><span class="token function">whereColumn</span><span class="token punctuation">(</span><span class="token single-quoted-string string">'user_id'</span><span class="token punctuation">,</span> <span class="token single-quoted-string string">'users.id'</span><span class="token punctuation">)</span> <span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token operator">-</span><span class="token operator">></span><span class="token function">withCasts</span><span class="token punctuation">(</span><span class="token punctuation">[</span> <span class="token single-quoted-string string">'last_posted_at'</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token single-quoted-string string">'date'</span> <span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token operator">-</span><span class="token operator">></span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> |
Ngoài ra bạn cũng có thể xem cách sự hữu ích khác mà thuộc tính cast
mang lại tại đây.