Quay lại

Cải thiện single-method accessors và mutators trong Laravel Chuyên mục PHP và Laravel    2024-01-04    20 Lượt xem    10 Lượt thích    comment-3 Created with Sketch Beta. 0 Bình luận

Cải thiện single-method accessors và mutators trong Laravel

Khi bạn muốn định dạng một số mô hình Eloquent trước khi thiết lập/lấy trong Laravel, bạn nhất định sẽ sử dụng đến các truy cập viên (accessors) và biến đổi viên (mutators).

Mình đã thảo luận chi tiết về điều này trong một trong những bài viết trước đó. Nhưng nếu mình phải đưa ra một tóm tắt, mình sẽ giải thích nó bằng một ví dụ.

Old Accessors & Mutators

Vậy nên, giả sử chúng ta có một trường gọi là "tax" trong bảng "orders" và nếu chúng ta muốn đặt giá trị thuế tính toán cho trường này, chúng ta sẽ cần định nghĩa một biến đổi viên (mutator) với định dạng tên set{Foo}Attribute trong model như sau.

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Order extends Model
{
    /**
     * The table associated with the model.
     *
     * @var string
     */
    protected $table = 'orders';

    public function setTaxAttribute($value)
    {
        return ($value * 20)/100;
    }
}

Vì vậy, từ giờ trở đi, trường "tax" sẽ được lưu trữ với giá trị tính toán.

$order = App\Order::find(5);

$order->tax = 15; // tax in percentage
// will be saved as "3"

Tương tự, khi bạn muốn lấy giá trị thuế nguyên thủy của một đơn đặt hàng, bạn sẽ cần định nghĩa một truy cập viên (accessor) với định dạng tên get{Foo}Attribute trong model như sau.

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Order extends Model
{
    /**
     * The table associated with the model.
     *
     * @var string
     */
    protected $table = 'orders';

    public function getTaxAttribute($value)
    {
        return ($value * 100)/20;
    }
}

Như vậy, khi "tax" được lấy ra cho một đơn đặt hàng, nó sẽ là giá trị raw tax (không tính toán thêm).

$order = App\Inventory::find(5);

$orderTax = $order->tax; 
// retrieved back as 15

The problem

Đây là cách tiêu chuẩn để định nghĩa truy cập viên (accessors) và biến đổi viên (mutators) trong Laravel. Nhưng vấn đề của phương pháp này là không được elegant ( thanh lịch) vì nó đòi hỏi hai phương thức khác nhau để lấy và thiết lập trường model.

Theo Taylor, điều này không phải là "style" mà Laravel làm theo suốt.

Vì vậy, anh ấy đưa ra một giải pháp giảm việc này xuống một phương thức duy nhất sẽ làm cho tính năng này trở nên mượt mà hơn.

Improved Accessors & Mutator

Phiên bản gần đây của Laravel hiện đã đi kèm với một cách thay thế để định nghĩa truy cập viên (accessors) / biến đổi viên (mutators), tất cả chỉ với một phương thức.

Theo đề xuất (PR), framework hiện tại đi kèm với một kiểu trả về là Illuminate\Database\Eloquent\Casts\Attribute, cho phép bạn định nghĩa hành vi truy cập / biến đổi thuộc tính trong một phương thức duy nhất.

Vì vậy, nếu chúng ta muốn viết lại ví dụ trước với cách tiếp cận này, dưới đây là cách chúng ta có thể thực hiện.

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Casts\Attribute;

class Order extends Model
{
    /**
     * The table associated with the model.
     *
     * @var string
     */
    protected $table = 'orders';

    /**
     * Get the order tax.
     */
    protected function tax(): Attribute
    {
        return new Attribute(
            fn ($value) => ($value * 20)/100, // accessor
            fn ($value) => ($value * 100)/20, // mutator
        );
    }
}

Như bạn có thể thấy, bạn có thể trực tiếp định nghĩa một phương thức có cùng tên với trường. Trong trường hợp của chúng ta, đó là phương thức tax.

Từ phương thức này, bạn có thể trả về kiểu Attribute. Trong đó, constructor của Attribute chấp nhận hai hàm gọi như đối số.

  • Đối số đầu tiên là một hàm gọi, trong đó bạn có thể định nghĩa logic cho truy cập viên.
  • Đối số thứ hai là một hàm gọi, trong đó bạn có thể định nghĩa logic để biến đổi/thiết lập giá trị trường.

Ví dụ sử dụng cú pháp arrow method ngắn gọn, nhưng nếu bạn có một business logic không thể thực hiện trong một dòng duy nhất, bạn có thể viết nó bằng cách sử dụng Closures thông thường như sau.

protected function tax(): Attribute
{
    return new Attribute(
        function($value) {
            return ($value * 20)/100; // raw tax
        },
        function($value) {
            return ($value * 100)/20, // computed tax
        } 
    );
}

Bây giờ, nếu bạn đang sử dụng PHP 8+, cú pháp này trở nên ngọt ngào và dễ đọc hơn khi bạn sử dụng nó với các tham số được đặt tên.

protected function tax(): Attribute
{
    return new Attribute(
        get: fn ($value) => ($value * 20)/100, // raw tax
        set: fn ($value) => ($value * 100)/20, // computed tax
    );
}
 

Bình luận (0)

Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough

Bài viết liên quan

Learning English Everyday