Cài đặt zend-stratigility

zend-stratigility là nền tảng để xây dựng ứng dụng MiddleWare theo chuẩn PSR-7. zend-stratigility tạo ra cơ chế pipeline, để chứa và thi thành các MiddleWare theo nguyên tắc của nó. Ví nó sử dụng zend-diactoros chính là thư viện triển khai chuẩn PSR - 7, nên khi cài đặt Statigility, bạn cũng cần cài cả Diactoros.

Nếu tự tích hợp vào dự án, tải về các thành phần và gộp vào dự án theo địa chỉ:

Để cài đặt chuẩn và nhanh chóng hãy sử dụng composer bằng câu lệnh:

composer require zendframework/zend-diactoros zendframework/zend-stratigility

Sử dụng cách thứ 2 để cài đặt thư viện này, giả sử tạo thư mục dự án là: stratigility và có thể chạy website bằng đường dẫn như http://localhost/stratigility/. Vào thư mục tạo ra đó, và gõ lệnh composer trên tải thư viện về.

Tạo file index.php (đây là nơi thực hành code các ví dụ đơn giản của bài viết này) trong thư mục dự án với nội dung như sau:

<?php
require __DIR__ . '/vendor/autoload.php';

Ngoài ra để đảm bảo các URL gọi đến đều chạy file index.php thì có thể tạo file .htaccess ở thư mục gốc dự án với nội dung

RewriteEngine On
# Cho phép Apache trả về nội dung file yêu cầu nếu tồn tại (image, css, js ...)
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]

#Các truy vấn khác sẽ gọi đến index.php
RewriteCond %{REQUEST_URI}::$1 ^(/.+)(.+)::\2$
RewriteRule ^(.*) - [E=BASE:%1]
RewriteRule ^(.*)$ %{ENV:BASE}index.php [NC,L]

Tạo ứng dụng Middleware

Middleware là code nằm giữa requestresponse (đọc PSR-7 để biết chi tiết về Request và Response), nó nhận request gửi đến, thi hành các tác vụ, cuối cùng nó cần phải trả về response hoặc thi hành Middleware phía sau nó trong hàng đợi pipeline.

Một ứng dụng Middleware PSR-7, đơn giản thì cần phải tạo các thành phần:

  • Tạo đối tượng Zend\Stratigility\MiddlewarePipe là pileline, nó dùng để chứa các Middleware theo thứ tự. Middleware gắn vào nó bằng phương thức pipe()
  • Tạo đối tượng Zend\Diactoros\Server nhận các thông tin HTTP requests rồi chuyển nó đến một callback (chính là MiddlewarePipe), sau đó gửi Response cho Client. Để Zend\Diactoros\Server nhận các Request gửi đến cần gọi phương thức listen

Giờ thực hành, cập nhật index.php như sau:

<?php
require __DIR__ . '/vendor/autoload.php';

use Zend\Stratigility\MiddlewarePipe;
use Zend\Diactoros\Server;
use Zend\Diactoros\Response;
use Zend\Diactoros\ServerRequest;

$app  = new MiddlewarePipe();
$app->setResponsePrototype(new Response());

$homePage = function (ServerRequest $req, Response $res, $next)
{
    $res->getBody()->write('MiddleWare Homepage');
    return $res;
};


$detailPage = function (ServerRequest $req, Response $res, $next)
{
    $res->getBody()->write('MiddleWare Detail');
    return $res;
};



$app->pipe('/stratigility/detail',  $detailPage);
$app->pipe('/stratigility/home',    $homePage);
$app->pipe(new \Zend\Stratigility\Middleware\NotFoundHandler(new Response()));

$server = Server::createServer($app, $_SERVER, $_GET, $_POST, $_COOKIE, $_FILES);
$server->listen(new \Zend\Stratigility\NoopFinalHandler());

Hãy chạy thử kiểm tra code trên với các URL: http://localhost/stratigility/home, http://localhost/stratigility/detail, http://localhost/stratigility/xyz ...

Giải thích code ứng dụng với Middleware ở trên

$app là đối tượng MiddlewarePipe, nó chứa các Middleware mà bạn tạo ra trong hệ thống. $homePage, $detailPage là Middleware, 2 Middleware ở ví dụ này bạn tạo ra theo cấu trúc closure với các tham số theo mẫu:

<?php
function (ServerRequest $req, Response $res, $next)
{
    //$req  - yêu cầu nhận được
    //$res  - đối tượng Response
    //$next - Middleware phía sau trong pileline
    //...
    //..
};

Các Middleware được gắn vào Pile bằng phương thức pipe($path, $middleware), như code trên là đoạn:

$app->pipe('/stratigility/detail',  $detailPage);
$app->pipe('/stratigility/home',    $homePage);
$app->pipe(new \Zend\Stratigility\Middleware\NotFoundHandler(new Response()));

Trong đó tham số $path là đường dẫn. Ví dụ URL là /stratigility/home thì sẽ gọi ngay đến $homePage, bạn nhớ là các đường dẫn con cũng sẽ gọi đến Middleware tương ứng. Ví dụ như /stratigility/home/1, /stratigility/home/2/3 ... đều dẫn tới Middleware $homePage.

Nếu phương thức pipe() chỉ nhận một tham số, thì tham số đó là Middleware, và Middleware đó sẽ có thể được gọi với mọi đường dẫn (Request). Như trường hợp trên:

$app->pipe(new \Zend\Stratigility\Middleware\NotFoundHandler(new Response()));

Cuối cùng tạo Server và lắng nghe các yêu cầu gửi đến, và hệ thống sẽ gọi các Middleware tướng để thi hành.

$server = Server::createServer($app, $_SERVER, $_GET, $_POST, $_COOKIE, $_FILES);
$server->listen(new \Zend\Stratigility\NoopFinalHandler());

Khi ứng dụng Middleware nhận các Request, thì MiddlewarePipe sẽ phân tích đường dẫn và gọi đến Middleware phù hợp trong hàng đợi các Middleware, Middleware có thể trả về Response để Zend\Diactoros\Server gửi về cho client và kết thúc hoặc gọi đến Middleware kế tiếp trong hàng đợi qua tham số $next

Tạo Middleware bằng cách triển khai giao diện MiddlewareInterface

Ngoài cách sử dụng closure để tạo ra Middleware như trên, còn có thể tạo ra các lớp định nghĩa Middleware bằng cách triển khai giao diện Interop\Http\Server\MiddlewareInterface và định nghĩa phương thức process trả về Response phù hợp.

Ví dụ sử file index.php trên thành:

<?php

require __DIR__ . '/vendor/autoload.php';

use Zend\Stratigility\MiddlewarePipe;
use Zend\Diactoros\Server;
use Zend\Diactoros\Response;
use Zend\Diactoros\ServerRequest;


class FirstMiddleware implements \Interop\Http\Server\MiddlewareInterface
{

    public function process(
        \Psr\Http\Message\ServerRequestInterface $request,
        \Interop\Http\Server\RequestHandlerInterface $handler)
    {
        /*
         * Nếu muốn gọi Middleware kế tiếp
         * return $handler->process($request);
         *
         * trả về Response mặc định:
         * $res = new Response();
         * $res
         *    ->withStatus(200)
         *    ->withHeader('Content-Type', 'text/plain; charset=utf-8' )
         *    ->getBody()->write('Test My First Middleware');
         *
         * trả về JSON
         * $data = ['message' => 'JSON RESPONSE'];
         * return new Response\JsonResponse($data);
         *
         * Trả về HTML
         * return new Response\HtmlResponse('HTML Response');
         *
         * Trả về chuyển hướng
         * return new Response\RedirectResponse(
         *       new \Zend\Diactoros\Uri('http://google.com.vn'), 301);
         */

        return new Response\TextResponse('Test My First Middleware');
    }
}

$app  = new MiddlewarePipe();
$app->setResponsePrototype(new Response());



$homePage = function (ServerRequest $req, Response $res, $next)
{
    $res->getBody()->write('MiddleWare Homepage');
    return $res;
};


$detailPage = function (ServerRequest $req, Response $res, $next)
{
    $res->getBody()->write('MiddleWare Detail');
    return $res;
};



$app->pipe('/stratigility/detail',  $detailPage);
$app->pipe('/stratigility/home',    $homePage);
$app->pipe('/stratigility/first',    new FirstMiddleware());

$app->pipe(new \Zend\Stratigility\Middleware\NotFoundHandler(new Response()));

$server = Server::createServer($app, $_SERVER, $_GET, $_POST, $_COOKIE, $_FILES);
$server->listen(new \Zend\Stratigility\NoopFinalHandler());

Kiểm tra với http://localhost/stratigility/first để Middleware: FirstMiddleware được thi hành

NotFoundHandler - Middleware bắt lỗi 404

Ở ví dụ trên, đã sử dụng Middleware có sẵn là Zend\Stratigility\Middleware\NotFoundHandler, Middleware này đặt ở cuối hàng đợi pileline, khi tất cả các đường dẫn không phù hợp thì gọi đến Middleware này để trả về báo lỗi 404.

NotFoundHandler - Middleware bắt lỗi 404

Ở ví dụ trên, đã sử dụng Middleware có sẵn là Zend\Stratigility\Middleware\NotFoundHandler, Middleware này đặt ở cuối hàng đợi pileline, khi tất cả các đường dẫn không phù hợp thì gọi đến Middleware này để trả về báo lỗi 404.

ErrorHandler

Middleware ErrorHandler để bắt các Exception / Error trong ứng dựng, để đăng ký dùng code như sau:

$app->pipe(
    new \Zend\Stratigility\Middleware\ErrorHandler(new Response(),
    new \Zend\Stratigility\Middleware\ErrorResponseGenerator(true)));

Để bắt các lỗi bạn nhớ nó phải là lớp ngoài cùng của Middleware, nghĩa là phải pipe đầu tiên. Giờ ở Middleware nào đó thử phát sinh throw new Exception('Test'); để kiểm tra lỗi bắt được.


Đăng ký nhận bài viết mới