rdlowrey/arya

此包已被废弃且不再维护。未建议替代包。

适用于PHP 5.4+的微框架

dev-master 2015-10-28 02:55 UTC

This package is not auto-updated.

Last update: 2017-12-29 07:50:14 UTC


README

Arya是一个提供URI路由、依赖注入和中间件钩子的最小化PHP Web SAPI 框架。该框架利用HTTP协议遵从性和SOLID设计原则,在保持简单性和性能的同时最大化灵活性。

警告: Arya仍在开发中,目前单元测试非常有限。该项目正朝着正式的v0.1.0版本发布迈进,但尚未达到该点。代码可能会随时更改,且没有警告。使用风险自负。

基本示例

<?php
$app = (new Arya\Application)
    ->before(function($request) {...}) // <-- middleware before request handled
    ->route('GET', '/', 'anyFunction')
    ->route('GET', '/lambda', $anyClosure)
    ->route('GET', '/static', 'AnyClass::staticMethod')
    ->route('GET', '/instance', 'AnyClass::instanceMethod') // <-- auto dependency injection
    ->route('GET', '/args/{arg1:\d+}/{arg2:\d+}', 'numericArgsFunction')
    ->after(function($request, $response) { ... }) // <-- middleware before response sent
    ->run()
;

项目目标

  • 按照RFC 2616概述的HTTP/1.1协议模型代码;
  • 使用SOLID、可读和经过良好测试的代码构建组件;
  • 防止供应商锁定和静态耦合;
  • 最小化性能开销。

需求和安装

基本需求

测试需求

  • PHPUnit | 运行自动化测试
  • Artax | 运行自动化测试

下载

Github

您可以从Github仓库随时克隆最新的Arya迭代。使用--recursive选项,git将自动为我们检索依赖子模块。

$ git clone --recursive git://github.com/rdlowrey/Arya.git

Composer

$ php composer.phar create-project rdlowrey/arya /path/to/later/location/Arya dev-master

手动下载

归档的标记版本也适用于(或将要)在项目的标签页面手动下载。

服务器设置

Arya充当前端控制器,用于路由所有请求。为了使这生效,您必须配置您的面向前的服务器,使其将所有请求指向一个文件。

Apache

在Apache 2.2.16或更高版本中,您可以在配置文件(.htaccess/httpd.conf/vhost.conf)中使用FallbackResource指令

FallbackResource /front_controller.php

如果您有较旧的Apache版本,则应将以下块添加到您的配置文件中

<IfModule mod_rewrite.c>
    Options -MultiViews

    RewriteEngine On
    RewriteBase /path/to/app
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^ front_controller.php [QSA,L]
</IfModule>

Nginx

server {
  ...
  index front_controller.php;
  try_files $uri $uri/ /front_controller.php;
  ...
}

PHP服务器

从PHP 5.4开始,您可以使用内置的开发服务器快速运行您的应用程序

$ php -S localhost:8080 front_controller.php

贡献

以拉取请求(PR)形式做出的贡献总是受到欢迎!在提交PR之前,请阅读CONTRIBUTORS文件。

指南

路由

中间件

依赖注入

HTTP协议

其他

服务器设置

路由

标准路由目标

Arya路由定义由三个元素组成

  • HTTP方法动词
  • URI路径
  • 目标可调用

Arya支持任何有效的PHP可调用作为路由目标。这意味着您可以指定函数名、lambda表达式、静态类方法和数组实例方法构造。考虑

<?php
$app = (new Arya\Application)
    ->route('GET', '/', 'myFunctionName')
    ->route('GET', '/lambda-hello', function() { return 'Hello world'; })
    ->route('POST', '/static-method', 'MyClass::myStaticPostHandler')
    ->route('GET', '/array-callback', [$myObject, 'someMethod'])
    ->route('GET', '/instance-method', 'MyController::get') // <-- IMPORTANT
    ->run()
;

路由按照分配的顺序进行匹配,但要注意没有参数的路由总是优先于有参数的路由(见(路由参数)[#route-arguments])。

扩展路由目标

您会注意到在上述示例代码中,特别关注了最后一个路由,SomeClass::someMethod。我们区分这个路由是因为它没有引用静态方法。这是如何实现的?好吧...

Arya使用包含Auryn依赖注入库为您递归实例化和提供类。考虑以下简单示例,其中我们的MyController类会自动实例化和调用对/索引资源的请求。

<?php
class Templater {
    function render($uri) {
        return "<html><body><p>Hello from {$uri}!</p></body></html>";
    }
}
class MyController {
    private $templater;
    function __construct(Templater $tpl) {
        $this->templater = $tpl;
    }
    function get(Request $request) {
        return $this->templater->render($request['REQUEST_URI']);
    }
}

$app = (new Arya\Application)->route('GET', '/', 'MyController::get')->run();

重要: Arya还会递归注入您在控制器方法签名中声明的任何依赖项。在上面的示例中,我们使用构造函数注入来提供渲染我们HTML响应的Templater对象。然而,我们也可以在MyController::get方法签名中声明Templater并在此调用时注入它。

路由参数

Arya使用FastRoute进行路由。

/lol-cats/{catType}/{catId:\d+}
/widgets/{widgetId:\d+}
/kumqats/{kumqatId}

当命名URI参数匹配时,它们以两种不同的方式对路由目标可用

  1. 作为$request['ROUTE_ARGS']数组中的关联数组键
  2. 作为与路由目标方法/函数签名中匹配名称的参数

因此,让我们考虑上面提到的/lol-cats路由的匹配

<?php

use Arya\Application;

function lolcatsFunction($request, $catType, $catId) {
    assert($catType === $request['ROUTE_ARGS']['catType']);
    assert($catId === $request['ROUTE_ARGS']['catId']);

    return '<html><body>woot!</body></html>';
}

$app = (new Application)
    ->route('GET', '/lol-cats/$catType/$#catId', 'lolcatsFunction')
    ->run();

这里要注意的是,如果您愿意,您可以将您的URI路由参数作为与路由目标签名中匹配名称的参数接受,但它们始终也在$request['ROUTE_ARGS']数组中可用。

路由执行路径

每个客户端请求都会通过路由系统中的三条路径之一

  1. 找不到请求URI匹配:404 Not Found
  2. 请求URI已匹配,但HTTP动词不匹配:405 Method Not Allowed
  3. 请求URI和HTTP方法与路由匹配,并调用相关目标

中间件

Arya的目标之一是在保留PHP易用性的同时,仍然提供标准API来修改每个请求前后的中间件。

中间件快速入门

  • Arya为每次页面加载使用通用的Arya\RequestArya\Response实例;
  • 中间件可以在路由处理器前后修改通用请求/响应实例;
  • 中间件必须返回TRUE/FALSE/NULL,并且只能直接修改请求/响应;
  • 如果中间件返回TRUE,则不会执行更多同类型的中间件(之前/之后/最终);
  • "之前"中间件应该在分配响应时返回TRUE,因为Arya会将此结果视为路由处理器不应被调用的指示;
  • "之后"中间件将始终在"之前"中间件和/或路由应用处理器之后执行;
  • @TODO 提及"最终"中间件(尚未启用)

之前

@TODO 添加URL重写示例

之后

中间件概念在修改响应后同样强大,就像在请求到达应用程序之前修改请求一样。让我们考虑一个"之后"中间件的标准用例...

自定义错误页面

Arya没有提供内置的自定义错误页面抽象,因为中间件系统提供了所有必要的工具来实现手动操作。假设我们想捕获所有错误响应并将它们替换为我们的自定义错误页面。我们只需指定一个"之后"中间件可调用对象,在将响应发送到客户端之前捕获并修改此类响应...

<?php
use Arya\Response, Arya\Application;

function myErrorPageMiddleware(Response $response) {
    switch ($response->getStatus()) {
        case 404:
            $response->setBody('my custom 404 html');
            break;
        case 500:
            $response->setBody('my custom 500 html');
            break;
        default:
            // don't bother to modify any others
    }
}

(new Application)
    ->route('GET', '/', function() { return 'Hello World'; })
    ->after('myErrorPageMiddleware')
    ->run();

这个例子中发生了什么?我们只是注册了一个中间件类方法,在应用程序执行后调用。我们的myErrorPageMiddleware函数只是检查是否分配了特定的状态码,如果是,就用我们的自定义HTML替换响应实体体。请注意,中间件可调用对象是以与应用程序相同的方式配置的;我们只需指定依赖项类型提示,它们将自动在构造函数或可调用签名(无论中间件在哪里请求它们)中提供。

最终化

@TODO "最终"中间件尚未启用

依赖注入

Arya内部使用Auyrn依赖注入器。

为了与Arya共享我们的定义、别名等,我们可以将Auryn\Injector实例作为第一个参数传递给Application构造函数。

如果没有传递Auryn\Injector实例,Application类将实例化自己的注入器。

HTTP协议

HTTP请求

Arya将每个请求表示为Arya\Request实例。此类提供了面向对象的方法,以替代PHP Web SAPI环境中默认存在的超全局反模式。

请求可变

Request实例实现了ArrayAccess,为中间件可调用对象提供了可变性。这样,中间件组件就可以修改请求以执行URI重写等操作。

请求提供

由于路由目标会自动配置,因此它们必须在方法签名中指定Arya\Request类(扩展实例方法目标也可以在__construct中指定)。例如,以下路由目标展示了在您的应用程序中请求请求实例的等效方法

<?php
use Arya\Application, Arya\Request;

function myFunctionTarget(Request $request) {
    return "Hello from " . $request['REQUEST_URI'];
}

class MyCtorRouteClass {
    private $request;
    function __construct(Request $request) {
        $this->request = $request;
    }
    function myTarget() {
        return "Hello from " . $this->request['REQUEST_URI'];
    }
}

class MyMethodRouteClass {
    function myTarget(Request $request) {
        return "Hello from " . $request['REQUEST_URI'];
    }
}

$app = (new Application)
    ->route('GET', '/function', 'myFunctionTarget')
    ->route('GET', '/my-ctor-route', 'MyCtorRouteClass::myTarget')
    ->route('GET', '/my-method-route', 'MyMethodRouteClass::myTarget')
    ->run()
;

简单响应

PHP Web SAPI中最受用户欢迎的方面之一是能够简单地将输出作为HTTP响应实体体返回。然而,这种方法在可测试性和企业可持续性方面并不理想。为了简化HTTP,Arya允许应用程序的可调用对象直接返回字符串以生成标准的200响应。考虑以下示例:

<?php
function helloWorld(Arya\Request $request) {
    return "Hello from " . $request['REQUEST_URI'];
}

$app = new Arya\Application;
$app->route('GET', '/', function(Arya\Request $request) {
    return "Hello from " . $request['REQUEST_URI'];
});
$app->run();

Arya会主动防止通过输出缓冲手动输出响应数据。如果您的应用程序生成任何输出(包括错误输出),则结果将是一个500内部服务器错误响应。在DEBUG模式下,您将收到包含输出数据的有帮助的打印输出。在生产环境中,将显示通用的500错误消息。这种行为的目的是将所有输出通过路由目标返回值,以便“after”中间件可调用对象有机会检查/修改输出。请注意,在DEBUG模式下,此行为还简化了运行时n00b-core浏览器输出调试。

HTTP响应

当您的应用程序需要精细控制HTTP响应时,简单的字符串是不够的。在这种情况下,路由目标可以返回Arya\Response类的实例。

@TODO 讨论状态码

@TODO 讨论头部

@TODO 讨论实体体

可调用响应体

@TODO

其他

@TODO 简介

应用选项

@TODO

调试模式

@TODO