iT邦幫忙

2023 iThome 鐵人賽

DAY 26
0
Modern Web

30 天上手! PHP 微服務入門與開發系列 第 26

第二十六章、Anser: 與框架整合,以 CodeIgniter4 為例 - PHP 微服務入門與開發

  • 分享至 

  • xImage
  •  

經歷了將近一個月的分享,筆者已完整地傳達了 Anser 的開發理念,因此在接下來的章節中將會向外擴張一些額外的知識。Anser 在開發的過程中並沒有依賴外部的軟體框架,因此它可以在單純的原生 PHP 環境下透過 Composer 安裝後直接使用。

在很多時候,單純的 PHP 環境是沒有辦法滿足我們的開發需求的。因此本章將示範如何在框架中引入 Anser 並保持架構的整潔。

本章,我們將以 CodeIgniter4 進行示範。

安裝 CodeIgniter4

你可以在你喜歡的地方建立起一個資料夾比如:Anser-CodeIgniter4,接著在底下建立起一個 docker-compose.yml 如下:

version: "3"
services:
    app:
        image: webdevops/php-nginx-dev:8.1
        platform: linux/x86_64
        networks:
            - anser_project_network
        ports:
            - 8084:80
        working_dir: /web
        environment:
            - WEB_DOCUMENT_ROOT=/web/ci4/public
            - PHP_DISPLAY_ERRORS=1
        volumes:
            - './:/web'
    anser_redis:
        image: redis:latest
        networks:
            - anser_project_network
        ports:
            - 6379:6379
networks:
    anser_project_network:
        external: true

這個 docker-compose.yml 基於 Nginx 與 php8.1 ,它與範例微服務一樣使用著同一個 Docker Network。同時,它會將資料夾內的所有檔案掛載到容器內,Nginx 的網頁根目錄則是被鎖定在 /web/ci4/public 裡面。

此時,請在你的終端機中使用 docker compose up -d 啟動容器,再透過 docekr compose exec app bash 進到容器之中,大概像這個樣子:

接著我們就可以透過以下指令取得最新的 CodeIgniter4 框架:

composer create-project codeigniter4/appstarter ci4

上述指令會將 CodeIgniter4 安裝在一個名為 ci4 的資料夾下,在執行後你的資料夾結構與 Command Line 畫面應該會像是這個樣子:

最後,打開你的瀏覽器輸入 localhost:8083 應該可以看到以下畫面:

恭喜,你已經完成安裝 CodeIgniter4 了。

為了在接下來的實作中檢查是否有設定上的失誤,你需要複製 CodeIgniter4 專案根目錄的 env 檔案,並將新的檔案重新命名為 .env ,在其中的 17 行改為 CI_ENVIRONMENT = development。藉由這個設定,我們將開啟 CodeIgniter4 的錯誤顯示功能,

整合 Anser 程式庫

當你看到了歡迎畫面後,我們緊接著進行 Anser 的安裝設定。在 Command Line 介面中我們得先 cd ci4 進入到 CodeIgniter4 的專案根目錄內。為了確認一切是否正常,你可以先執行 php spark 如果一切正確,你應該能看到以下內容:

緊接著,讓我們來執行 Composer 安裝指令:

composer require sdpmlab/anser

當一切安裝結束後,你可以看看 vendor 中是否包含一個 sdpmlab 資料夾,

讓我們來將 Anser 給整合進 CodeIgniter4 的框架啟動週期內。首先,建立ci4/app/Config/Anser.php,這支檔案應該長得像這個樣子:

<?php

use SDPMlab\Anser\Service\ServiceList;
use SDPMlab\Anser\Orchestration\Saga\Cache\CacheFactory;
use SDPMlab\Anser\Orchestration\Saga\Cache\Redis\Config;

ServiceList::addLocalService(
    name: "ProductionService",
    address: "production-service",
    port: 8080,
    isHttps: false
);

ServiceList::addLocalService(
    name: "UserService",
    address: "user-service",
    port: 8080,
    isHttps: false
);

ServiceList::addLocalService(
    name: "OrderService",
    address: "order-service",
    port: 8080,
    isHttps: false
);

CacheFactory::initCacheDriver(CacheFactory::CACHE_DRIVER_PREDIS, new Config(
    host: "anser_redis",
    port: 6379,
    db: 1,
    serverName: 'AnserCi4Service'
));

你應該能在上述檔案發現,我們去除了原先 Anser-Tutorial-Service/init.phprequire_once './vendor/autoload.php'; 這是因為在 CodeIgniter4 執行的生命週期內,它已經替我們處理了所有的類別自動載入規則,因此我們就不需要再引入任何外部 PHP 程式。

接著,讓我們移動到 ci4/app/Config/Autoload.php 中將我們剛才建立的 ci4/app/Config/Anser.php 給宣告進去,你可以在大約第 87 行的地方看到 $files 變數,並將它改變成這個樣子:

public $files = [
    APPPATH . 'Config/Anser.php',
];

此時在 CodeIgniter4 的載入週期內,就已經自動包含了 Anser 的基本設定了。

將 Anser 資料夾結構放入 CodeIgniter4

建立起 ci4/app/Anser 資料夾後,你可以參考 Anser-Tutorial-Service 的設計建立起以下結構:

其中的 .gitkeep 為了是在版本控制系統中能夠保留空白的資料夾。

接著,你可以將前面的章節所練習的相關檔案給移動到這個 CodeIgniter4 的 Anser 資料夾結構中,就像這個樣子:

命名空間改變

這邊需要注意的是 namespace 的問題,CodeIgniter4 與其他主流的 PHP 框架一樣採用了 PSR-4 的自動載入標準,因此我們要將這些類別檔案的命名空間給改成與資料夾結構符合的樣子。

比如本來的 Filters 前後的對比會是這樣子:

//Anser-Tutorial-Service
namespace Filters;
//Anser with CodeIgniter4
namespace App\Anser\Filters;

又或者是 :

//Anser-Tutorial-Service
namespace Orchestrators;
namespace Orchestrators\Sagas;

//Anser with CodeIgniter4
namespace App\Anser\Orchestrators;
namespace App\Anser\Orchestrators\Sagas;

當命名空間改變,use 關鍵字引用的類別宣告方式也會隨之改變,以下是已經修改完畢的 CreateOrderOrchestrator 作為示範:

<?php
namespace App\Anser\Orchestrators;

use SDPMlab\Anser\Orchestration\Orchestrator;
use App\Anser\Services\OrderService;
use App\Anser\Services\ProductionService;
use App\Anser\Services\UserService;
use App\Models\DataModel\OrderProductDetail;
use App\Anser\Orchestrators\Sagas\CreateOrderSaga;

class CreateOrderOrchestrator extends Orchestrator
{
    //hide

Log 記錄方式改變

另外,因為 CodeIgniter4 也提供了 log 的管理機制,因此我們需要改變一下 Anser/Filters/FailHandlerFilter.php 的寫法:

$action->failHandler(static function (
    ActionException $e
) {
    if($e->isClientError()){
        $msg = $e->getAction()->getResponse()->getBody()->getContents();
        log_message("error", $msg);
        $error = json_decode($msg, true)['error'] ?? "unknow error";
        $e->getAction()->setMeaningData([
            "code" => $e->getAction()->getResponse()->getStatusCode(),
            "msg" => $error,
            "requestRawBody" => $msg
        ]);
    }else if ($e->isServerError()){
        $serverBody = $e->getAction()->getResponse()->getBody()->getContents();
        log_message("error", $serverBody);
        $e->getAction()->setMeaningData([
            "code" => 500,
            "msg" => "server error"
        ]);
    }else if($e->isConnectError()){
        log_message("error", $e->getMessage());
        $e->getAction()->setMeaningData([
            "code" => 500,
            "msg" => $e->getMessage()
        ]);
    }
});

將原先手動寫入的原生寫法:

file_put_contents(
    LOG_PATH . "actionClientErrorlog.txt",
    "[" . date("Y-m-d H:i:s") . "] " . $msg . PHP_EOL, FILE_APPEND
);

轉換成框架所提供的 log_message() 機制。

在 CodeIgniter4 中使用 Anser 協作器

當完成了上述的前置設定後,我們就可以在 CodeIgniter4 中使用 Anser 協作器。讓我們先來建立一個 Controller 作為我們的 API 進入點:

以 Command Line 進入到 CodeIgniter4 根目錄後執行以下指令建立 Controller :

php spark make:controller User

你應該可以看到名為 User.php 的控制器隨著指令的生效被建立起來:

就像你熟悉的那樣,建立一個使用 Anser 協作器的方法:

<?php

namespace App\Controllers;

use App\Controllers\BaseController;
use App\Anser\Orchestrators\UserLoginOrchestrator;

class User extends BaseController
{
    public function login()
    {
        $email = $this->request->getPost('email') ?? '';
        $password = $this->request->getPost('password') ?? '';
        $orchestrator = new UserLoginOrchestrator();
        $result = $orchestrator->build($email, $password);
        if($result['success'] == false){
            return $this->response->setStatusCode(400)->setJSON($result);
        }
        return $this->response->setJSON($result);
    }
}

在上述程式碼中,我們透過 CodeIgniter4 的 Request 物件取得了 Post 中的 emailpassword,接著實體化一個 UserLoginOrchestrator 類別,將信箱與密碼傳入後執行這個協作器。透過協作器回傳的內容,判斷該響應何種 HTTP Status Code 給予 Client。

緊接著,讓我們來到 app/Config/Routes.php 增加以下路由設定:

$routes->post('/user/login', 'User::login');

接著,打開你的 Postman 直接進行 API 呼叫:

[POST] http://localhost:8083/user/login

看起來一切順利,文章的最後讓我們試試看錯誤的帳號密碼:

完美!

結語

本篇文章討論的是如何在 PHP 的 CodeIgniter4 框架中進行 Anser 程式庫的整合,從環境的搭建、安裝,到實際地在具體的專案中應用 Anser 並做到相應的組態設定。大多數的現代化 PHP 框架大同小異,因此你可以參考本篇文章的介紹,依樣畫葫蘆地將 Anser 整合到你的專案之中。


上一篇
第二十五章、Anser-Saga:深入執行週期的高可用性元件 - PHP 微服務入門與開發
下一篇
第二十七章、高效能PHP:Workerman - 常駐型 PHP Web 伺服器 - PHP 微服務入門與開發
系列文
30 天上手! PHP 微服務入門與開發30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言