经验/lucille

轻量级HTTP抽象层

1.1.0 2021-03-09 15:52 UTC

This package is auto-updated.

Last update: 2024-09-12 02:33:07 UTC


README

Lucille是基于CQRS原则的轻量级HTTP抽象层。它旨在快速创建RESTful服务和需要动态请求处理的Web服务/网站。

Integrate

Type Coverage

需求

最低要求

  • PHP 7.2+
    • ext/dom (当使用XML/XHTML组件时)
    • ext/xsl (当使用XSL组件时)

基本概念

请求处理工作流程

Lucille HTTP抽象框架通常遵循CQRS的原则。请求的常规处理分为六个步骤

  1. 请求,通过其HTTP请求方法(GET、POST、...)被路由到一个显式的RoutingChain,以确保与其他请求类型分离
  2. 链中的每个路由器都必须决定是负责处理请求还是通过将其转发到链中的下一个路由器来拒绝它
  3. 链中的匹配路由器(决定负责处理当前请求的路由器)总是返回一个有效的命令查询对象
  4. 查询或命令被执行
  5. 执行结果始终是一个结果对象
  6. 结果对象最终通过一个结果路由链路由,该链组成最终要发送给客户端的响应对象

简而言之,例如对于GetRequest

  1. GetRequest
  2. GetRoutingChain返回查询
  3. 查询被执行并返回一个QueryResult对象
  4. 调用结果路由链并构建最终的Response对象

支持的HTTP请求类型

目前支持以下http请求方法

  • GET
  • POST
  • PUT
  • PATCH
  • DELETE

用法

使用内部RequestProcessor的完整示例

最简单的方法是使用提供的RequestProcessor。当创建HTTP服务时,你可能希望实现自己的请求处理机制以正确实现自己的日志记录和异常处理。

namespace Website;

use Lucille\Factory;

require_once '/lucille/autoload.php';

// create the factory, which helps getting the core features
$factory = new Factory();

// register stream wrapper
$factory->registerStream('xhtml', __DIR__.'/parts');
$factory->registerStream('xsl',   __DIR__.'/xsl');

// create the GET routing chain add a GET router
$chainGet = $factory->createGetRoutingChain();
$chainGet->addRouter(new IndexRouter());

// create the POST routing chain and add a POST router
$chainPost = $factory->createPostRoutingChain();
$chainPost->addRouter(new FormVerifyRouter());

// create an instance of the default request processor
$processor = $factory->createRequestProcessor();

// enable verbose error output for debugging purposes
//$processor->enableVerboseErrors();

// add routing chains to the processor
$processor->addRoutingChain($chainGet);
$processor->addRoutingChain($chainPost);

// create request (based on the request method, headers and parameters)
$request = $factory->createRequestFactory()->createRequest();

// build a response by running the processor with the created request
$response = $processor->run($request);


// dump/send the response to the client
$response->send();

实现路由器、命令和查询

示例路由器(GET请求)

namespace Website;

use Lucille\Query;
use Lucille\Request\GetRequest;
use Lucille\Request\Uri;
use Lucille\Routing\GetRouter;

class IndexRouter extends GetRouter {
    
    public function route(GetRequest $request): Query {
        if (!$request->getUri()->isEqual(new Uri('/'))) {
            return $this->getNext()->route($request);
        }
        
        return new IndexQuery();
    }
    
}

示例查询

namespace Website;
    
use Lucille\Components\Xml\XhtmlContent;
use Lucille\Filename;
use Lucille\Query;
use Lucille\Result\Result;

class IndexQuery implements Query {
    
    public function execute(): Result {
        // load main page
        $page = new XhtmlContent(new Filename('xhtml://design.xhtml'));
        
        // load a part and append it to the html <body> tag (which has the id attribute 'content')
        $part1 = new XhtmlContent(new Filename('xhtml://part1.xhtml'));
        $page->append('content', $part1);
        
        return $page;
    }
    
}

URI匹配和用法示例

// request URI equals another URI
if ($request->getUri()->isEqual( new Uri('/contact') ) {
    ...
}

// check if request URI begins with a specified value
// - example request uri: /articles/my-first-article/view.xml
if ($request->getUri()->beginsWith( new Uri('/articles/') ) {
    ...
}

// check if request URI matches a specified regular expression
// - example request uri: /articles/2020/demo-article/
if ($request->getUri()->matchesRegEx( new UriRegEx('#^/articles/[0-9]{4}/.*#') )) {
    ...
}

// check for a specific URI segment
// - example request uri: /articles/2020/demo-article/
$request->getUri()->getPart(0);    // returns 'articles'
$request->getUri()->getPart(1);    // returns '2020'
$request->getUri()->getPart(2);    // returns 'demo-article'

请求参数示例

按名称的URI参数

示例请求URI: /article?id=123

// cast to string
echo $request->getParam('id')->asString();

// cast to int
echo $request->getParam('id')->asInt();

// cast to float
echo $request->getParam('id')->asFloat();

与参数集合一起工作

// example request uri: /article?id=123&limit=20
$collection = $request->getParameterCollection();
if (count($collection) > 0) {
    foreach ($collection as $param) {
        echo $param->getName()->asString();     // parameter name
        echo $param->asString();                // parameter value
    }
}

// example request uri: /article?list[]=foo&list[]=bar
$collection = $request->getParameterCollection('list');
if (count($collection) > 0) {
    foreach ($collection as $value) {
        echo $value->asString();
    }
}

组件和助手

Lucille附带了一些实用的组件,用于解决一些日常问题。这些组件中的大多数只是标准功能的轻量级包装。因此,当构建复杂的网站或API项目时,这些组件可能无法满足你的扩展需求,应根据你的当前项目范围进行实现。

贡献

Lucille及其组件是开源项目,在BSD许可下发布。欢迎您加入开发团队!