การใช้งาน Middleware ใน Slim framework 4

บทความใหม่ สัปดาห์ที่แล้ว โดย Ninenik Narkdee
php slim php framework middleware route middleware

คำสั่ง การ กำหนด รูปแบบ ตัวอย่าง เทคนิค ลูกเล่น การประยุกต์ การใช้งาน เกี่ยวกับ php slim php framework middleware route middleware



ในเนื้อหาตอนที่แล้วที่พูดถึงวงจรกระบวนการ
ทำงานของ slim framework ไปแล้ว เราได้อธิบายคร่าวๆ
เกี่ยวกับการทำงานของ Middleware ในตอนต่อไปนี้จะมาดู
รายละเอียด และตัวอย่างรวมถึงการทำงานเพิ่มเติมของ
Middleware ใน Slim framework ทบทวนตอนที่แล้วได้ที่
    กระบวนการทำงาน หรือ Life Cycle ของ Slim Framework http://niik.in/1052
 
 

Middleware ใน Slim framework

    คือส่วนที่ใช้สำหรับจัดการกับ request และ response object ในระหว่างขั้นตอนการทำงานของ
slim app ยกตัวอย่างเช่น ชุดการทำงานที่ป้องกันการ Cross-site Request Forgery (CSRF) ชุดคำสั่ง
การทำงานที่ป้องกันการเข้าใช้งาน app ในลักษณะนี้เป็นต้น  การทำงานที่เรียกว่า slim app จะเป็นส่วน
ที่อยู่ใจกลางสุดหรือเข้าใจอย่างง่ายก็คือส่วนการทำงานใน route ดูรูปประกอบจากตอนที่แล้วด้านล่าง

 
 



 
 
เมื่อทำคำสั่ง run() โปรแกรมเริ่มทำงาน ก็จะเริ่มกระบวนการทำงานตามขั้นตอนต่างๆ 
ตั้งแต่ เมื่อเริ่มมี HTTP Request และเข้าสู่ชั้นการทำงานของ  
Middleware โดยจะเริ่มจาก middleware ที่เพิ่มเข้าไปล่าสุด เป็นการจัดการในส่วนของ 
request object ทำงานไปเรื่อยๆตามจำนวนที่มี ไปจนจบที่ส่วนของ slim app หรือส่วนของ route 
ซึ่งเป็นใจกลางการทำงาน เมื่อ route ทำการ กระจาย response object
กลับออกมาก็จะผ่าน middleware จากด้านใน (middleware ที่เพิ่มก่อน) ออกไปจนถึง 
middleware ตัวล่าสุด จากนั้นส่งออกเป็น HTTP response ดูการจำลองจากโค้ดด้านล่าง
 
    ลำดับการทำงานก็คือ  C > B > A > AA > BB > CC

 
 

การกำหนดและใช้งาน Middleware

    ในการกำหนดหรือสร้าง middleware เราต้องใช้งาน request object และ request handler 
object โดยต้องเรียกใช้ class ทั้งสองส่วนนี้เข้ามาจัดการ
 
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Server\RequestHandlerInterface as RequestHandler;
 
    ดูตัวอย่างการกำหนดและใช้งาน Middleware ตามโค้ดด้านล่าง
 
<?php
require './vendor/autoload.php';

use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Server\RequestHandlerInterface as RequestHandler;
use Slim\Factory\AppFactory;

$app = AppFactory::create();
$app->setBasePath('/demo/api');


// Aplication Middleware
// กำหนด middleware ฟังก์ชั่นและเก็บไว้ในตัวแปร
$beforeMiddleware = function (Request $request, RequestHandler $handler) use ($app) {
    echo "C";
    $response = $handler->handle($request);
    $existingContent = (string) $response->getBody();

    $response = $app->getResponseFactory()->createResponse();
    $response->getBody()->write('BEFORE' . $existingContent);
    echo "CC";
    return $response;
};
// กำหนด middleware ฟังก์ชั่นและเก็บไว้ในตัวแปร *เขียนแบบไม่ระบุชนิดข้อมูลกำกับ
$afterMiddleware = function ($request, $handler) {
    echo "D";
    $response = $handler->handle($request);
    $response->getBody()->write('AFTER');
    echo "DD";
    return $response;
};
// เรียกใช้งาน middleware ด้วยคำสั่ง add()
$app->add($beforeMiddleware);
$app->add($afterMiddleware);


// Error Middleware
$app->addErrorMiddleware(false, true, true);

// Routing
// ตัว route เป็น slim app อยู่ด้านในตรงกลาง
$app->get('/', function (Request $request, Response $response, $args) {
    echo "B";
    $response->getBody()->write('Hello World');
    echo "BB";
    return $response;
})->add(function ($request, $handler) { // route middleware
    echo "A";
    $response = $handler->handle($request);
    $response->getBody()->write(' END');
    echo "AA";
    return $response;
});


$app->run();
 
    การกำหนด middleware เราจะกำหนด application middleware ก่อนแล้วตามด้วย error middleware
แล้วตามด้วย routing และ route middleware ถ้ามี ในตัวอย่างเรากำหนด route middleware ด้วย
    ลำดับการทำงานจะเริ่มจากส่วนของ request object
    D > C > A > B
    ต่อด้วยลำดับการทำงานจะเริ่มจากส่วนของ response object
    BB > AA > CC > AA
    ลำดับการทำงานรวม
    D > C > A > B > BB > AA > CC > AA
    ผลลัพธ์การทำงานที่ได้ 'BEFOREHello World ENDAFTER'
 
    จะเห็นว่าส่วน B จะเป็นส่วนของ slim app หรือ เป็นส่วนของใจกลางการทำงาน ส่วน middleware จะทำงาน
ในส่วนของ Application middleware ก่อน แล้วถึงมาทำงานส่วนของ Route middleware
    ในตัวอย่างเราแค่ต้องการเพิ่มข้อความ ก่อนและหลังคำว่า 'Hello World' คำว่า before และ after ไม่ได้
หมายถึงว่าทำงานก่อนหรือหลัง แค่เพียงสื่อว่าข้อความก่อน กับข้อความหลังเท่านั้น
    Middleware จะต้องทำการส่งต่อ request object ไปในแต่ละ middleware ที่มีการใช้งาน
 
    เราสามารถสร้าง middleware เป็น class ไฟล์แยกแล้วเรียกใช้งานก็ได้ โดยกำหนดไว้ใน
__invoke() method เช่น
 

    ไฟล์ BeforeMiddleware.php

 
<?php
// use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Server\RequestHandlerInterface as RequestHandler;
use Slim\Psr7\Response;

class BeforeMiddleware
{
    public function __invoke(Request $request, RequestHandler $handler): Response
    {
        $response = $handler->handle($request);
        $existingContent = (string) $response->getBody();
    
        $response = new Response();
        $response->getBody()->write('BEFORE' . $existingContent);
    
        return $response;
    }
}
 

    ไฟล์ AfterMiddleware.php

 
<?php
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Server\RequestHandlerInterface as RequestHandler;

class AfterMiddleware
{
    public function __invoke(Request $request, RequestHandler $handler): Response
    {
        $response = $handler->handle($request);
        $response->getBody()->write('AFTER');
        return $response;
    }
}
 
    หรือจะรวมไว้ในไฟล์เดียวกัน เช่น
    

    ไฟล์ Middleware.php

 
<?php
// use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Server\RequestHandlerInterface as RequestHandler;
use Slim\Psr7\Response;

class BeforeMiddleware
{
    public function __invoke(Request $request, RequestHandler $handler): Response
    {
        $response = $handler->handle($request);
        $existingContent = (string) $response->getBody();
    
        $response = new Response();
        $response->getBody()->write('BEFORE' . $existingContent);
    
        return $response;
    }
}
class AfterMiddleware
{
    public function __invoke(Request $request, RequestHandler $handler): Response
    {
        $response = $handler->handle($request);
        $response->getBody()->write('AFTER');
        return $response;
    }
}
 
    จากนั้นนำมาใช้งาน ในไฟล์ index.php
 
/* require 'BeforeMiddleware.php';
require 'AfterMiddleware.php'; */
require 'Middleware.php';
 
    เรียกใช้งานในรูปแบบดังนี้
 
// กรณีใช้กับ app
$app->add(new BeforeMiddleware());
$app->add(new AfterMiddleware());

// กรณีใช้กับ route 
$app->get('/', function () { ... })->add(new BeforeMiddleware());
 
 
 

Application Middleware และ Route Middleware

    ความแตกต่างระกว่าง app และ route middleware คือ app middleware จะทำงานกับทุกๆ
HTTP request ที่เข้ามา เข้าใจอย่างง่ายก็คือทำงานกับทุกๆ route ที่เรียกเข้ามา ไม่ว่าจะมีกำหนด
route หรือไม่ก็ตาม ในขณะที่ route middleware จะทำงานเฉพาะ route ที่เรียกใช้เท่านั้น โดยการเรียก
ใช้งาน จะใช้ผ่านคำสั่ง add() ซึ่งถ้าเป็น app ก็จะเรียกใช้ผ่านตัวแปร $app ซึ่งเป็น slim app instance
ในขณะที่ถ้าเป็น route จะเรียกใช้งานจาก route นั้นๆ ตามตัวอย่างที่เห็นไปบ้างแล้วด้านบน
    เนื่องจาก route middleware จะเป็นส่วนที่อยู่ใกล้ slim app หรือใจกลางของโปรแกรมมากที่สุด ดังนั้น
ในขั้นตอนของการ request จะทำเป็นลำดับสุดท้ายก่อนเข้าสู่ app และในขั้นตอนการ response จะทำเป็น
ลำดับแรกหลังออกจาก app ส่งออกไปยัง middleware ด้านนอกสุด แล้วแสดงข้อมูลออกไป
    สำหรับการกำหด route เรายังสามารถจัดกลุ่ม route ได้ ตัวอย่างเช่น สมมติ /product เราก็อาจจะมี
แยกย่อยใน product อีกทีเช่น /product/dress กับ /product/shirt
 
$app->group('/product', function (RouteCollectorProxy $group) {
    $group->get('/dress', function (Request $request, Response $response) {
        $response->getBody()->write('Dress');
        return $response;
    });
    
    $group->get('/shirt', function (Request $request, Response $response) {
        $response->getBody()->write('Shirt');
        return $response;
    });
})->add(new BeforeMiddleware());
 
    การใช้งานในลักษณะนี้ เราสามารถเรียกได้ว่าเป็น group middleware ก็ได้ ซึ่งก็เป็นส่วนหนึ่งของ 
route middleware เพียงแต่เรากำหนดแค่จุดเดียว ก็สามารถใช้ได้ทั้งใน /product/dress และ /product/shirt
 
 

การส่งค่าและใช้งานตัวแปรผ่าน Middleware

    เราสามารถทำการส่งค่าตัวแปรหรือข้อมูลจาก middleware หนึ่งไปยังอีก middleware หนึ่งได้โดย
ใช้คำสั่งดังนี้
 
    กำหนดตัวแปรที่จะส่งค่าใน middleware แรก
 
$request = $request->withAttribute('foo', 'bar');
 
    เรียกใช้งานใน middleware ที่ต้องการ
 
$foo = $request->getAttribute('foo');
 
    เราก็จะได้ตัวแปร $foo มีค่าเป็นข้อความ 'bar' ไปใช้งาน แต่จำไว้ว่า การกำหนด และการเรียกใช้งาน
จะต้องเป็นไปตามลำดับการทำงานของ middleware ในส่วนของ request object นั่นคือ ต้องกำหนดตัวแปร
และตั้งค่าใน middleware ตัวที่ทำงานก่อน และต้องเรียกใช้งานใน middleware ที่ทำงานต่อในลำดับถัดไป
แบบตัวอย่างด้านล่าง
 
$beforeMiddleware = function (Request $request, RequestHandler $handler) use ($app) {
    $foo = $request->getAttribute('foo'); // ใช้งานในนี้
    echo $foo;
    $response = $handler->handle($request);
    $existingContent = (string) $response->getBody();

    $response = $app->getResponseFactory()->createResponse();
    $response->getBody()->write('BEFORE' . $existingContent);
    return $response;
};
// กำหนด middleware ฟังก์ชั่นและเก็บไว้ในตัวแปร *เขียนแบบไม่ระบุชนิดข้อมูลกำกับ
$afterMiddleware = function ($request, $handler) {
    $request = $request->withAttribute('foo', 'bar'); // ตั้งค่าในนี้
    $response = $handler->handle($request);
    $response->getBody()->write('AFTER');
    return $response;
};
// เรียกใช้งาน middleware ด้วยคำสั่ง add()
$app->add($beforeMiddleware);
$app->add($afterMiddleware);
 
    การกำหนดค่าข้อมูลจะใช้เป็นข้อมูลอะไรก็ได้ เช่น ตัวอย่างกำหนดเป็น array ก็จะได้เป็น
 
$myData = ['Hello','World'];
$request = $request->withAttribute('data', $myData); 
 
    ข้อมูลที่กำหนดค่าแล้ว จะถูกส่งต่อผ่าน middlware ที่อยู่ในลำดับถัดไปไปเรื่อยๆ จนถึง slim app
หรือส่วนของ route นั่นก็หมายความว่า เราสามารถดึงค่ามาใช้งานใน route ด้วยคำสังข้างต้นได้เหมือนกัน
 
$app->get('/', function (Request $request, Response $response, $args) {
    $foo = $request->getAttribute('foo'); // ใช้งานในนี้ได้
    echo $foo;    
    $response->getBody()->write('Hello World');
    return $response;
});
 
 
    เนื้อหาเกี่ยวกับ Middleware ใน Slim framework เบื้องต้นก็จะมีประมาณนี้ เราจะยังได้ใช้ หรือได้
ทำความกับ middleware อยู่เรื่อยๆ เพราะเป็นส่วนหนึ่งของ slim สำหรับเนื้อหาตอนหน้าจะเป็นอะไร
นั้น รอติดตาม


กด Like หรือ Share เป็นกำลังใจ ให้มีบทความใหม่ๆ เรื่อยๆ น่ะครับ



อ่านต่อที่บทความ









เนื้อหาที่เกี่ยวข้อง









URL สำหรับอ้างอิง











เว็บไซต์ของเราให้บริการเนื้อหาบทความสำหรับนักพัฒนา โดยพึ่งพารายได้เล็กน้อยจากการแสดงโฆษณา โปรดสนับสนุนเว็บไซต์ของเราด้วยการปิดการใช้งานตัวปิดกั้นโฆษณา (Disable Ads Blocker) ขอบคุณครับ