Pipeline Design Pattern là nơi mà các dữ liệu được chuyển qua một chuỗi các nhiệm vụ hoặc giai đoạn.

Pipeline hoạt động giống như một chuỗi dây chuyền lắp ráp, nơi dữ liệu được xử lý và sau đó, sẽ được chuyển sang giai đoạn tiếp theo.

Sử dụng Pipeline trong dự án sẽ là một điểm lợi thế, vì nó sẽ dễ dàng giúp chúng ta trong việc chuyển đổi một quy trình phức tạp ra thành các nhiệm vụ riêng rẻ.

Cũng như, nó cũng dễ dàng giúp chúng ta trong việc thêm, xóa hoặc thay thế một giai đoạn nào đó trong Pipeline mà không làm ảnh hưởng đến toàn bộ quá trình.

Pipeline Design Pattern trong Laravel

Laravel sử dụng Pipeline ở một số nơi trong khuôn khổ của mình, nhưng nối bật nhất trong số đó chính là Middleware.

Trên thực tế, các Middleware này là các Pipeline dùng để thực hiện bất kì nhiệm vụ cần thiết nào khi có một yêu cầu gửi đến ứng dụng của chúng ta.

Mỗi middware sẽ có trách nhiệm cho một hành động duy nhất. Ví dụ như thiết lập cookie, ngăn chặn các cuộc tấn công CSRF.

Mỗi giai đoạn sẽ xử lý yêu cầu và chuyển nó sang giai đoạn tiếp theo hoặc từ chối yêu cầu và trả lại phản hồi HTTP thích hợp.

Nếu xem nhanh mã nguồn Illuminate\Foundation\Http\Kernel, bạn sẽ thấy cách các middware được thực thi thông qua Illuminate\Routing\Pipeline.

/**
 * Send the given request through the middleware / router.
 *
 * @param  \Illuminate\Http\Request  $request
 * @return \Illuminate\Http\Response
 */
protected function sendRequestThroughRouter($request)
{
    $this->app->instance('request', $request);

    Facade::clearResolvedInstance('request');

    $this->bootstrap();

    return (new Pipeline($this->app))
                ->send($request)
                ->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware)
                ->then($this->dispatchToRouter());
}

Cách sử dụng Laravel Pipeline

Request Filters

Giả sử, chúng ta đang trong quá trình phát triển một trang blog cho phép mọi người để lại nhận xét mà chủ đề bạn chia sẻ. Nhưng bạn có một mong muốn là những từ thô tục, phản cảm hay chứa những đoạn script phải được xóa bỏ.

Dựa trên yêu cầu đó, chúng ta có một quy trình trên giấy như sau:

1. Tiếp nhận dữ liệu từ người dùng.

2. Xóa bỏ các từ ngữ thô tục, phản cảm có trong nội dung.

3. Xóa bỏ các tag script có trong nội dung.

Dựa vào quy trình trên, chúng ta sẽ ra các class để xử lý từng nhiệm vụ như sau:

$pipes = [
    RemoveBadWords::class,
    RemoveScriptTags::class
];

Sau khi đã có danh sách các nhiệm vụ cần thực hiện, chúng ta sẽ bắt đầu thực hiện nó trong dự án của mình.

Trong thư mục app của Laravel, bạn hãy tạo một thư mục có tên là Filters.

Trong thư mục Filters, ban tạo tiếp một thư mục có tên là Requests.

Bạn hãy tạo file RemoveBadWords.php nằm trong thư mục app\Filters\Requests và có nội dung như sau:

<?php

namespace App\Filters\Requests;

use Closure;

class RemoveBadWords
{
    public function handle($content, Closure $next)
    {
        $badWords = [
            'ManhDanBlogs',
        ];
        $content = str_replace($badWords, '', $content);
        return  $next($content);
    }
}

Tiếp đó, tạo file RemoveScriptTags.php nằm trong thư mục app\Filters\Requests và có nội dung như sau:

<?php

namespace App\Filters\Requests;

use Closure;

class RemoveScriptTags
{
    public function handle($content, Closure $next)
    {
        $content = preg_replace('#<script(.*?)>(.*?)</script>#is', '', $content);
        return $next($content);
    }
}

Cuối cùng, chúng ta sẽ áp dụng Pipeline trong Controller như sau:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\User;
use Illuminate\Pipeline\Pipeline;
use App\Filters\Requests\RemoveBadWords;
use App\Filters\Requests\RemoveScriptTags;

class RequestController extends Controller
{
     /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index(Request $request)
    {
        $name  = "ManhDanBlogs<script>alert('Website đang bị lỗi XSS!');</script>Đây là những gì còn xót lại";
        $pipes = [
            RemoveBadWords::class, // Input: ManhDanBlogs<script>alert('Website đang bị lỗi XSS!');</script>Đây là những gì còn xót lại
            RemoveScriptTags::class // Input: <script>alert('Website đang bị lỗi XSS!');</script>Đây là những gì còn xót lại
        ];
        $user = app(Pipeline::class)
        ->send($name)
        ->through($pipes)
        ->then(function ($name) {
            // Result: Đây là những gì còn xót lại
            return User::create(['name' => $name]);
        });
    }
}

Query Filters

Trong thư mục app của Laravel, bạn hãy tạo một thư mục có tên là Traits. Trong thư này, bạn hãy tạo file Filterable.php và có nội dung như sau:

<?php

namespace App\Traits;

use Illuminate\Pipeline\Pipeline;

trait Filterable
{
    public function scopeFilter($query, array $through)
    {
        return app(Pipeline::class)
               ->send($query)
               ->through($through)
               ->thenReturn();
    }
}

Tiếp theo, sử dụng Trait Filterable trong Model (trong bài viết này mình sử dụng model User) như sau:

<?php

namespace App\Models;

...
use App\Traits\Filterable;

class User extends Authenticatable
{
    use Filterable;

    ...
}

Trong thư mục Filters, ban tạo tiếp một thư mục có tên là Queries.

Bạn hãy tạo file NameFilter.php nằm trong thư mục app\Filters\Queries và có nội dung như sau:

<?php

namespace App\Filters\Queries;

class NameFilter
{
    public function handle($query, $next)
    {
        if (request()->name) {
           $query->where('name', request()->name);
        }

        return $next($query);
    }
}

Tiếp đó, chúng ta sẽ tạo tiếp file EmailFilter.php nằm trong thư mục app\Filters\Queries và có nội dung như sau:

<?php

namespace App\Filters\Queries;

class EmailFilter
{
    public function handle($query, $next)
    {
        if (request()->email) {
           $query->where('email', request()->email);
        }

        return $next($query);
    }
}

Cuối cùng, chúng ta sẽ áp dụng Pipeline trong Controller như sau:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\User;
use App\Filters\Queries\NameFilter;
use App\Filters\Queries\EmailFilter;

class QueryController extends Controller
{
     /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index(Request $request)
    {
        $pipes = [
            NameFilter::class,
            EmailFilter::class,
        ];
        $users = User::query()->filter($pipes)->get();

        return $users;
    }
}

Tới đây, thì chúng ta đã trải nghiệm và thử áp dụng một vài trường hợp sử dụng Pipeline trong Laravel. Mình hy vọng qua bài viết này, bạn sẽ hiểu rõ Pipeline là gì, và cũng như áp dụng thành công trong dự án của bạn.

Nếu mọi người muốn góp ý cho bài viết này hoàn thiện hơn, bạn có thể liên lạc với mình qua trang contact.

Hy vọng, chúng ta sẽ gặp lại nhau trong bài viết tiếp theo. Cảm ơn bạn.

CÓ THỂ BẠN QUAN TÂM

Laravel Upload File Using Trait

Laravel Upload File Using Trait

Hiện nay, đa số các dự án đều có chức năng upload file, nên tôi đã thử xây dựng một lớp Trait Upload File, để chúng ta dễ dàng sao chép qua các dự án khác để sử dụng, nhằm rút ngắn thời gian phát triể...

Laravel customize your API Versioning Route File

Laravel customize your API Versioning Route File

Trong khuôn khổ của Laravel, các route của api được tách thành một file duy nhất, đó là file api.php nằm trong thư mục routes . Nếu chúng ta muốn thêm version vào route api thì chúng ta sẽ làm như...

Laravel Jobs Batching

Laravel Jobs Batching

Phiên bản Laravel 8 đã được phát hành với một tính năng mà rất nhiều người trong chúng ta đã chờ đợi rất lâu đó là Jobs Batching, nó cho phép chúng ta thực hiện nhiều công việc trong cùng một lúc và t...

Efficient Laravel PDF Export for Large Datasets

Efficient Laravel PDF Export for Large Datasets

Xuất file PDF là một tính năng quan trọng của nhiều ứng dụng web, đặc biệt là các trang thương mại điện tử, giúp người dùng tạo và lưu trữ các bản báo cáo, hóa đơn, v.v.  Tuy nhiên, khi phải xử lý...

Laravel Artisan Console

Laravel Artisan Console

Ngoài các lệnh command mặc định của Laravel được cung cấp bởi Artisan, có rất nhiều tác vụ trong ứng dụng Laravel của bạn có thể được xử lý rất tốt bằng các lệnh command này. Nhưng đôi khi có nhiều tá...

How To Optimize Your Site With GZIP Compression

How To Optimize Your Site With GZIP Compression

GZIP là công nghệ nén thường được sử dụng để truyền dữ liệu một cách nhanh chóng qua Insternet. Hiện nay, GZIP là một tiêu chuẩn để nén các file trên trang web, đa số các website hiện nay hơn 99% sử d...

Fast Paginate in Laravel

Fast Paginate in Laravel

Laravel Fast Paginate là gì? Laravel Fast Paginate là một macro nhanh về phân trang offset/limit cho Laravel. Nó được sử dụng để thay thể paginate trong Laravel.Package này sử dụng phương pháp SQL t...

Laravel One to Many Polymorphic Relationship

Laravel One to Many Polymorphic Relationship

One to Many Polymorphic Model Relationship được sử dụng khi một model thuộc về nhiều model khác trên một model kết hợp duy nhất. Ví dụ: Nếu chúng ta có bảng post và video, cả hai đều cần thêm hệ thống...

Send Slack Notifications In Laravel

Send Slack Notifications In Laravel

Slack là gì? Slack là một công cụ giao tiếp tại nơi làm việc, "một nơi duy nhất cho các tin nhắn, công cụ và file." Điều này có nghĩa là Slack là một hệ thống nhắn tin tức thì với nhiều plug-in cho...

ManhDanBlogs