Quay lại

Sử dụng Eloquent - Global và Local scopes trong Laravel Chuyên mục PHP và Laravel    2023-07-27    653 Lượt xem    26 Lượt thích    comment-3 Created with Sketch Beta. 0 Bình luận

Sử dụng Eloquent - Global và Local  scopes  trong Laravel

Eloquent ORM của Laravel đi kèm với bộ tính năng độc đáo này được gọi là “scopes” có thể được sử dụng để sử dụng lại một số ràng buộc truy vấn đối với tất cả các truy vấn của một model nhất định. Điều này có thể hữu ích để giảm thiểu code trong khi viết truy vấn và là một cách dễ dàng để đảm bảo mọi truy vấn cho một model nhất định đều nhận được các ràng buộc nhất định.

Về cơ bản có hai loại phạm vi có sẵn trong Laravel: “Global Scopes” và “Local Scopes”. Bây giờ chúng ta hãy hiểu những phạm vi này là gì và cách sử dụng chúng

Global Scopes

Global Scopes hữu ích khi bạn chắc chắn về tập hợp các ràng buộc truy vấn mà bạn cho rằng sẽ áp dụng được cho tất cả các truy vấn mà các phạm vi này sẽ được chỉ định.

Để xác định Global Scopes, tất cả những gì bạn cần làm là xác định một lớp triển khai interface Illuminate\Database\Eloquent\Scope. Interface này yêu cầu bạn triển khai một phương thức: apply. Bên trong phương thức apply này, bạn có thể thêm ràng buộc where sẽ được áp dụng cho truy vấn. Bạn có thể xác định tất cả phạm vi của mình trong namespace  App\Scopes như thế này.

<?php

namespace App\Scopes;

use Illuminate\Database\Eloquent\Scope;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;

class PublishedScope implements Scope
{
    /**
     * Apply the scope to a given Eloquent query builder.
     *
     * @param  \Illuminate\Database\Eloquent\Builder  $builder
     * @param  \Illuminate\Database\Eloquent\Model  $model
     * @return void
     */
    public function apply(Builder $builder, Model $model)
    {
        $builder->where('published', 1);
    }
}

Áp dụng Global Scopes vào models

Để gán một Global Scopes nhất định cho một model, bạn cần ghi đè phương thức boot của model cụ thể và sau đó sử dụng phương thức addGlobalScope.

<?php

namespace App;

use App\Scopes\PublishedScope;
use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    /**
     * The "booting" method of the model.
     *
     * @return void
     */
    protected static function boot()
    {
        parent::boot();

        static::addGlobalScope(new PublishedScope);
    }
}

Bây giờ, khi phạm vi PublishedScope được gán cho Post model, bất cứ khi nào một truy vấn được đưa ra cho model này, nó sẽ được đính kèm với ràng buộc được gán trong phạm vi. Ví dụ: Post::all() sẽ tạo truy vấn sau:

select * from `posts` where `published` = 1

Anonymous (Ẩn danh) Global Scopes

Bạn cũng có thể sử dụng các global scopes bằng cách chỉ định chúng dưới dạng các Closures/Anonymous functions. Điều này đặc biệt hữu ích cho các phạm vi đơn giản không yêu cầu một lớp riêng biệt. Đây là cách bạn có thể làm điều đó.

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;

class Post extends Model
{
    /**
     * The "booting" method of the model.
     *
     * @return void
     */
    protected static function boot()
    {
        parent::boot();

        static::addGlobalScope('published', function (Builder $builder) {
            $builder->where('published', 1);
        });
    }
}

Ở đây trong trường hợp này, tham số đầu tiên của phương thức addGlobalScope là tên của Closure mà chúng ta đã chuyển vào tham số thứ hai có thể được sử dụng để xóa phạm vi trong khi đưa ra truy vấn. Mình sẽ thảo luận điều này trong phần tiếp theo.

Xóa Global Scopes

Nếu bạn muốn loại bỏ một global scope cho một truy vấn nhất định, bạn có thể sử dụng phương thức withoutGlobalScope. Phương thức chấp nhận tên lớp của global scope làm đối số duy nhất của nó:

Post::withoutGlobalScope(PublishedScope::class)->get();

Nếu bạn muốn xóa tất cả các global scope, bạn chỉ cần sử dụng withoutGlobalScope mà không cần bất kỳ tham số nào

Post::withoutGlobalScope()->get();

Hoặc nếu có nhiều global scope và bạn muốn loại bỏ một số global scope, bạn có thể thực hiện việc này bằng cách chỉ định mảng của các global scope đã chọn.

// Remove some of the global scopes...
User::withoutGlobalScopes([
    FirstScope::class, SecondScope::class
])->get();

Local Scopes

Một loại scope khác có sẵn trong Eloquent là “Local Scopes”. Chúng đặc biệt hữu ích khi bạn muốn sử dụng một số hạn chế nhất định dưới dạng các phần nhỏ hơn có thể được sử dụng trên các truy vấn model .

Chẳng hạn, đối với ví dụ trước về model Post, nếu bạn muốn tìm nạp tất cả các bài đăng đã được "starred", bạn có thể thực hiện việc này bằng cách xác định Local Scopes. Để xác định phạm vi Local Scopes, hãy thêm tiền tố vào một phương thức model Eloquent với scope. scope luôn trả về một query builder instance:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    /**
     * Scope a query to only include most starred posts.
     *
     * @param  \Illuminate\Database\Eloquent\Builder  $query
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeStarred($query)
    {
        return $query->where('starred', '>', 30);
    }

    /**
     * Scope a query to only include published posts.
     *
     * @param  \Illuminate\Database\Eloquent\Builder  $query
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopePublished($query)
    {
        return $query->where('published', 1);
    }
}

Nếu bạn muốn chuyển tham số động cho scopes để làm cho scopes local trở nên động, bạn có thể thực hiện việc này bằng cách chỉ cần thêm tham số bổ sung vào phạm vi của mình. Các tham số phạm vi phải được xác định sau tham số $query:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    /**
     * Scope a query to only include most starred posts.
     *
     * @param  \Illuminate\Database\Eloquent\Builder  $query
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeOfCategory($query, $category)
    {
        return $query->where('category', $category);
    }
}

Bây giờ, bạn có thể truyền tham số khi gọi scope:

$posts = App\Post::ofCategory('php')->get();

Sử dụng Local Scope

Để sử dụng local scope đã xác định trên truy vấn model, tất cả những gì bạn cần làm là gọi các phương thức scope trên mô hình truy vấn mà không cần sử dụng prefix scope.

$posts = App\Post::starred()->get();

Bạn cũng có thể chain (xâu chuỗi) các phương thức scope để tổng hợp các ràng buộc khác nhau như thế này

$posts = App\Post::starred()->published()->get();

Nếu bạn muốn sử dụng OR truy vấn trên mô hình bằng cách sử dụng scopes, bạn có thể thực hiện việc này bằng cách sử dụng phương pháp "higher order" orWhere cho phép bạn xâu chuỗi các phạm vi một cách trôi chảy.

$posts = App\Post::starred()->orWhere->published()->get();

Phần kết luận

Vì vậy, điểm mấu chốt ở đây là, hãy sử dụng “Global Scopes” khi bạn muốn áp dụng một khối các ràng buộc truy vấn trên các truy vấn model và nếu bạn muốn sử dụng các khối ràng buộc truy vấn nhỏ hơn để có thể thực hiện một thao tác cụ thể, hãy sử dụng “Local Scopes” trong đó trường hợp.

 

áp dụng

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