Accessors và Mutators trong Laravel 5.5

Xin chào tất cả mọi người. Hôm nay mình sẽ tìm hiểu về Accessors Mutators trong Laravel phiên bản 5.5

Giới thiệu

Accessors và Mutators đều cho phép chúng ta format lại các giá trị thuộc tính của Eloquent khi lấy ra hoặc thêm vào Model. Ngoài việc hỗ trợ tạo accessor và mutator, Eloquent cũng có thể tự động chuyển các trường date thành Carbon instance hoặc thậm chí chuyển trường text thành JSON.

Accessors và Mutators

Định nghĩa 1 accessors

Để định nghĩa 1 accessors, chúng ta hãy cũng tạo một hàm có tên getNameAttribute trong model User tại thư mục app như sau:

<?php

namespace App;

use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    use Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name', 'email', 'password',
    ];

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password', 'remember_token',
    ];
    
    public function getNameAttribute($value)
    {
        return $this->strtoupper($value);
    }
}

Chưa biết nó ra sao, đến đây các bạn cũng có thể đoán được cái hàm bên trong function getNameAttribute rồi phải không. Đây là hàm chuyển chữ thường sang chữ hoa trong PHP. Tiếp theo ta vào mysql và thêm vào cơ sở dũ liệu của chúng ta các bản ghi. Ở đây do mình sẽ thêm 1 hàng bằng tay như sau: Quay sang thư mục routes/web.php, ta tạo một route mới như sau:

    Route::get('/accessors', function() {
	$user = App\User::find(1);
	
	return $upper_name = $user->name;
});

Mở trình duyệt theo đường dẫn localhost:8000/accessors lên. Kết quả là VIỆT NAM VÔ ĐỊCH. Quay lại với model User nào! Ở ví dụ này, các bạn hãy nhìn vào hàm getNameAttribute. Hàm này được viết theo kiểu camelCase để thực hiện việc lấy giá trị cho thuộc tính name. Có thể giải thích rằng nếu bạn muốn định nghĩa một accessors trong một model bất kỳ nào, thì trong function của bạn phải có tiền tố là get và hậu tố là Attribute.

Định nghĩa 1 mutators

Ngược lại với accessors, mutators có nghĩa là khi bạn muốn format lại các giá trị thuộc tính trước khi lưu vào cơ sở dữ liệu. Ví dụ, để định nghĩa một Mutators, mình sẽ định nghĩa một phương thức setPasswordAttribute trong model User

public function setPasswordAttribute($password)
{
    $this->attributes['password'] = bcrypt($password);
}

web.php :

Route::get('/mutators', function() {
    $user = App\User::find(1);

    $user->password = 123456;

    return $user->password;
});

Quay lại trình duyệt và gõ địa chỉ localhost:8000/accessors . Kết quả là một đoạn ký tự đã được mã hóa. Ở ví dụ trên, hàm setPasswordAttribute sẽ được gọi với $password truyền vào là 123456. Vậy nếu bạn muốn định nghĩa một Mutators trong một model, function của bạn phải có tiền tố là set và hậu tố là Attribute Không khó đúng không nào ^^!!

Date Mutators

Mặc định trong Laravel, Eloquent sẽ chuyển đổi hai trườngcreated_at and updated_at thành các instance của Carbon, một thư viện cung cấp rất nhiều hàm hữu ích và mở rộng class DateTime của PHP. Bạn có thể tuỳ chỉnh trường nào sẽ được tự động mutated, và thậm chí có thể disable việc mutation này bằng cách ghi đè lên thuộc tính $date trên model của bạn.

<?php

namespace App;

use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    use Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name', 'email', 'password',
    ];

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password', 'remember_token',
    ];

    protected $dates = [
        'created_at', 
        'update_at', 
        'delete_at', 
    ];
}

Khi một cột là kiểu date, bạn có thể đặt giá trị của nó là một UNIX timestamp, date string (Y-m-d), date-time string và là một instance của DateTime / Carbon, và giá trị của date sẽ tự động được lưu vào trong database:

    $user = App\User::find(1);

    $user->deleted_at = now();

    $user->save();

Và một lưu ý, đó là khi các bạn lấy ra các giá trị nằm trong $date của bạn, chúng sẽ tự động được cast thành các Carbon instance và cho phép bạn sử dụng các method của Carbon trong các attribute.

    $user = App\User::find(1);

    return $user->deleted_at->getTimestamp();

Date Format

Mặc định, timestamp được format dưới dạng Y-m-d H:i:s . Nếu bạn cần tùy chỉnh format cho timestamp, hãy đặt thuộc tính $dateFormat trên model của bạn. Thuộc tính này sẽ quyết định giá trị date được lưu như thế nào trong database, giống như việc format chúng khi mà một model được serialized theo mảng hoặc JSON. Ví dụ:

    <?php

    namespace App;

    use Illuminate\Database\Eloquent\Model;

    class Flight extends Model
    {
        /**
         * The storage format of the model's date columns.
         *
         * @var string
         */
        protected $dateFormat = 'U';
    }

Attribute Casting

Thuộc tính $casts cung cấp một phương thức tiện lợi về việc chuyển đổi các các thuộc tính sang các kiểu dữ liệu bình thường. Thuộc tính $casts nên là một mảng có key là tên của các attribute được cast và giá trị là kiểu dữ liệu bạn muốn cast. Các kiểu dữ liệu để cast được hỗ trợ bao gồm: integer, real, float, double, string, boolean, object, array, collection, date, datetime, và timestamp. VD: cast thuộc tính is_admin từ kiểu integer sang boolean:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
     * The attributes that should be cast to native types.
     *
     * @var array
     */
    protected $casts = [
        'is_admin' => 'boolean',
    ];
}

Giờ đây, thuộc tính is_admin sẽ luôn luôn được cast thành kiểu boolean khi bạn truy cập đến nó, thậm chí nếu giá trị của nó được lưu trong database là kiểu integer:

    $user = App\User::find(1);

    if ($user->is_admin) {
        //
    }

Array & JSON Casting

Cast kiểu array đặc biệt hữu ích khi chúng ta làm việc với các column được lưu dưới dạng JSON. Giả sử database của bạn có 1 trường JSON hoặc TEXT có chứa serialized JSON, thêm vào array cast lên attribute sẽ tự động deserialize các attribute thành PHP array khi bạn truy cập trong Eloquent model:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
     * The attributes that should be cast to native types.
     *
     * @var array
     */
    protected $casts = [
        'options' => 'array',
    ];
}

Một khi cast được định nghĩa, bạn có thể truy cập giá trị options và nó sẽ tự động được deserialize từ JSON thành PHP array. Khi bạn đặt giá trị options, nó sẽ tự động được serialize trở lại thành JSON để lưu vào trong cơ sở dữ liệu:

$user = App\User::find(1);

$options = $user->options;

$options['key'] = 'value';

$user->options = $options;

$user->save();

Kết Luận

Thông thường thì mình thấy trong các project hay sử dụng AccessorsMutators khá nhiều. Hi vọng các bạn có thể xem được những thông tin hữu ích từ bài viết này. Bài viết của mình xin dừng lại tại đây. Mong được sự theo dõi và ủng hộ của các bạn.

Tham khảo thêm về Accessors và Mutators tại : https://laravel.com/docs/5.5/eloquent-mutators