Photo of author

By Admin

Laravel eloquent tips

Trong bài viết này, chúng ta sẽ tập trung vào một số tips query hữu ích trong Laravel Eloquent. Đây là những gợi ý và kỹ thuật giúp bạn làm việc hiệu quả với cơ sở dữ liệu trong Laravel.

1 – Invisible Database Columns

Cột vô hình là một khái niệm mới trong MySQL 8. Công dụng của nó: khi bạn chạy một truy vấn select *, nó sẽ không truy xuất bất kỳ cột vô hình nào. Nếu bạn cần giá trị của cột vô hình, bạn phải chỉ định nó một cách rõ ràng trong câu lệnh chọn.

Và bây giờ, Laravel hỗ trợ các cột sau:

Schema::table('users', function (Blueprint $table){
  $table->string('password')->invisble();
});

$user = User::first();
$user->secret == null;

2 – saveQuietly

Nếu bạn muốn lưu một model nhưng không muốn kích hoạt model event thì sử dụng method sau:

$user = User::first();
$user->name = "Hamid Afghan";

$user->saveQuietly();

3 – Default Attribute Values

Trong Laravel, bạn có thể xác định giá trị mặc định cho các cột ở hai nơi: Migrations và models.

Schema::create('orders', function(Blueprint $table){
  $table->bigIncrements('id');
  $table->string('status', 20)
    ->nullable(false)
    ->default(App\\Enums\\OrderStatuses::DRAFT);
});

Đây là một tính năng nổi tiếng, cột trạng thái sẽ có giá trị nháp mặc định.

Với trường hợp này thì sao?

$order = new Order();
$order->status = null;

Trong trường hợp này, trạng thái sẽ là null. Và đôi khi nó gây ra lỗi giá trị null khó chịu. Nhưng may mắn thay, bạn cũng có thể chỉ định các giá trị thuộc tính mặc định trong Mô hình:

class Order extends Model
{
  protected $attributes = [
    'status' => App\\Enums\\OrderStatuses::DRAFT,
  ];
}

Nếu mối thay đổi trạng thái cho status chỉ cần gán nó cho giá trị mới.

$order = new Order();
$order->status  === 'draft';

Bạn có thể sử dụng hai cách tiếp cận này cùng nhau và bạn sẽ không bao giờ gặp lỗi có giá trị null nữa.


4 – Attribute Cast

Trước Laravel 8. x chúng tôi đã viết các trình truy cập thuộc tính và trình biến đổi như sau:

class User extends Model{
  public function getNameAttribute(string $value): string
  {
      return Str::upper($value);
  }

  public function setNameAttribute(string $value): string
  {
      $this->attributes['name'] = Str::lower($value);
  }
}

It's not bad at all, but as Taylor says in the pull request:

Đều này không tệ, nhưng Taylor đã ghi chú trong pull request như sau:

Khía cạnh này của khuôn khổ luôn khiến tôi cảm thấy hơi "lỗi thời". Thành thật mà nói, tôi nghĩ đó là một trong những phần kém tinh tế nhất của framework hiện đang tồn tại. Đầu tiên, nó đòi hỏi hai phương pháp. Thứ hai, khung công tác này thường không đặt tiền tố cho các phương thức truy xuất hoặc đặt dữ liệu trên một đối tượng bằng get và set

Và anh ấy đã tạo lại chức năng này như sau:

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

class User extends Model {
  protected function name(): Attribute {
    return new Attribute(
       get: fn (string $value) => Str::upper($value),
       set: fn (string $value) => Str::lower($value)
    );
  }
}

Sự khác biệt chính là:

  • Bạn chỉ cần viết 1 method
  • Nó trả về một thuộc tính thay vì một giá trị vô hướng
  • Bản thân Thuộc tính có một hàm getter và setter

5 – find

Mọi người chắc đã đều biết đến find method trong Laravel, tuy nhiên bạn đã sử dụng qua find arrays IDs. Thường thì chúng ta sử dụng như sau:

$users = User::whereIn('id', $ids)->get();

Tuy nhiên, có thể tìm nhiều như sau:

$users = User::find($ids);

6 – Get Dirty

Trong Eloquent bạn có thể kiểm tra một model là "dirty" hay không. "Dirty" có nghĩa là nó có một số thay đổi chưa được duy trì:

$user = User::first();
$user->name = 'Hamid';
$user->isDirty(); // true
$user->getDirty(); // ['name' => 'Hamid'];

isDirty thì return bool. Còn getDirty sẽ trả về các dirty attribute.


7 – push

Đôi khi bạn cần lưu một model vào relationship của nó. Trong trường hợp này chúng ta có thể sử dụng push method:

$employee = Employee::first();
$employee->name = 'New Name';
$employee->address->city = 'New York';

$employee->push();

Trong trường hợp này, thao tác lưu sẽ chỉ lưu cột tên trong bảng nhân viên chứ không lưu cột thành phố trong bảng địa chỉ. Phương pháp đẩy sẽ lưu cả hai.


8 – Boot Eloquent Traits

Chúng ta viết traits được sử dụng bởi Eloquent models. nếu bạn khởi tạo một thứ gì trên trong trait khi một sự kiện xảy ra trong model, bạn có thể khởi động trait.

Lấy ví dụ, nếu bạn có những models với slug, bạn không mốt viết lại logic trong mỗi model. Hãy define một traint và sử dụng event boot method:

trait HasSlug {
  public static function bootHasSlug() {
      static::creating(function (Model $model) {
        $model->slug = Str::slug($model->title);
      });
  }
}

Do vậy hãy tạo một bootTraitName method, và Eloquent sẽ tự động gọi nó khi bạn tạo model.


9 – updateOrCreate

Để create hoặc update một model nhưng sử dụng cùng một method. Eloquent cung cấp cho chúng ta một phương thức thuận tiện là updateOrCreate:

$flight = Flight::updateOrCreate(
  ['id' => $id],
  ['price' => 99, 'discounted' => 1],
);

Nó nhận vào hai mảng:

Mảng đầu tiên được sử dụng để xác định xem mô hình có tồn tại hay không. Trong ví dụ này, tôi sử dụng id.

Mảng thứ hai là các thuộc tính mà bạn muốn chèn hoặc cập nhật.

Và cách nó hoạt động như sau:

Nếu tìm thấy Chuyến bay dựa trên id được cung cấp, nó sẽ được cập nhật với mảng thứ hai.

Nếu không có Chuyến bay nào có id được cung cấp, nó sẽ được chèn vào với mảng thứ hai.

Tôi muốn cho bạn xem một ví dụ thực tế về cách tôi xử lý việc tạo và cập nhật mô hình.

The Controller:

public function store(UpsertDepartmentRequest $request): JsonResponse {
    return DepartmentResource::make($this->upsert($request, new Department()))
        ->response()
        ->setStatusCode(Response::HTTP_CREATED);
}

public function update( UpsertDepartmentRequest $request, Department $department): HttpResponse {
    $this->upsert($request, $department);

    return response()->noContent();
}

private function upsert(UpsertDepartmentRequest $request, Department $department): Department {

    $departmentData = new DepartmentData(...$request->validated());

    return $this->upsertDepartment->execute($department, $departmentData);
}

Như bạn có thể thấy tôi thường trích xuất một phương thức có tên upsert . Phương pháp này chấp nhận một Department . Trong phương thức lưu trữ, tôi sử dụng một phiên bản Bộ trống vì trong trường hợp này, tôi không có phiên bản thực. Nhưng trong

update Tôi chuyển phiên bản hiện được cập nhật.

class UpsertDepartmentAction {

public function execute( Department $department, DepartmentData $departmentData): Department {

  return Department->updateOrCreate(
      ['id' => $department->id],$departmentData->toArray()
    );
 }
}

Dịch tiếng Việt: Nó cần một Đơn vị là mô hình (một mô hình trống hoặc mô hình đã được cập nhật), và một DTO (đối tượng đơn giản chứa dữ liệu). Trong mảng đầu tiên, tôi sử dụng $department->id với các giá trị sau:

null nếu đó là một mô hình mới.

Một ID hợp lệ nếu đó là một mô hình đã được cập nhật.

Và đối số thứ hai là DTO dưới dạng một mảng, với các thuộc tính của Đơn vị.


10 – upsert

Để gây nhầm lẫn, Laravel sử dụng từ upsert cho nhiều thao tác cập nhật hoặc tạo. Cái này nó thì trông như thế nào:

Flight::upsert(
  [
    ['departure' => 'Oakland', 'destination' => 'San Diego', 'price' =>99],
    ['departure' => 'Chicago', 'destination' => 'New York', 'price' => 150]
  ],
  ['departure', 'destination'],
  ['price']
);

Nó phức tạp hơn một chút:

  • Mảng thứ nhất: Giá trị để insert or update
  • Mảng thứ hai: các cột định danh duy nhất được sử dụng trong câu lệnh chọn
  • Mảng thứ ba: các cột mà bạn muốn cập nhật nếu bản ghi tồn tại

Trong ví dụ này sẽ:

  • Insert or update a flight from Oakland to San Diego with the price of 99
  • Insert or update a flight from Chicago to New York with the price of 150

11 – Order by Mutator

Hãy tưởng tượng bạn có điều này:

function getFullNameAttribute()
{
  return $this->attributes['first_name'] . ' ' . $this->attributes['last_name'];
}

Bây giờ, bạn order theo full_name, nó sẽ không hoạt động:

$clients = Client::orderBy('full_name')->get(); // doesn't work

Để nó hoạt động, bạn đầu get nó rồi sau đó mới order thì sẽ hoạt động tốt.

$clients = Client::get()->sortBy('full_name'); // works!

Lưu ý rằng tên hàm khác nhau – không phải orderBy mà là SortBy.

Lưu ý: điều quan trọng là bạn cần ghi nhớ, nếu truy vấn của bạn Client::get() trả về một hàng lớn, thì hàm ->sortBy() sẽ yêu cầu sử dụng bộ nhớ. Đảm bảo máy chủ không hết bộ nhớ.


12 – Raw query methods

Các phương thức truy vấn thô trong Laravel cho phép bạn thực thi các câu lệnh SQL thô trực tiếp trên cơ sở dữ liệu. Điều này có thể hữu ích khi thực hiện các truy vấn phức tạp mà Eloquent ORM hoặc Query Builder không thể thực hiện được.

// WhereRaw
$order = DB::table('orders')
  ->whereRaw('price < IF(state = "TX", ?, 100 )', [200])
  ->get();

// havingRaw
Product::groupBy('categrory_id')
  ->havingRaw('COUNT(*) > 1')
  ->get();

// orderbyRaw
User::query()
  ->where('created_at', '>', $request->date)
  ->orderByRaw('(updated_at - created_at) DESC')
  ->get();

13 – whereColumn method

Phương thức WhereColumn trong Laravel cho phép chúng ta so sánh hai cột trong cùng một bảng.

Trong ví dụ này, chúng tôi đang sử dụng nó để truy xuất tất cả các sản phẩm có giá nhỏ hơn hoặc bằng giá thành.

// WhereColumn $products = Product::whereColumn('price', '<=', 'cost')->get();

Nguồn: https://github.com/hamidafghan/laravel-eloquent

Đánh giá bài viết

Đánh giá: 0 / 5. Vote: 0

Bài viết liên quan

Viết một bình luận