轻量级URL路由器

v2.0.10 2018-02-12 00:17 UTC

README

轻量级URL路由器,支持依赖注入。

安装

将依赖项添加到 composer.json,然后执行 composer install

{
    "require": {
        "objectiveweb/router": "~2.0"
    }
}

基本用法

在 Objectiveweb 应用程序中,端点指的是响应 URL 路由的 PHP 文件。

底层,route($regex, $callable) 函数将 $regex 与当前请求方法和 URI(例如 "GET endpoint.php/something/([0-9]+)/?") 进行比较,如果匹配,则将捕获的参数传递给 $callable

示例端点

<?php
// include the composer autoloader
require_once('../vendor/autoload.php')

use Objectiveweb\Router;

$app = new Router();

// Routes are matched in order

$app->GET('/?', function() {
    echo "Hello index';
});

$app->GET('/([a-z]+)/?', function($key) {

    switch($key) {
        case 'data':
            // If the callback returns something, it's sent with status 200 (OK)
            // Arrays are automatically encoded to json
            return [ 1, 2, 3 ];
            break;
        default:
            throw new \Exception([ 'key' => $key, 'empty' => true ], 404); // respond with custom code
            break;
    }
});

$app->POST('/panic', function() {
    // Exceptions are captured, message is send with the proper code
    throw new \Exception('Panic!', 500);
});

// catch all
$app->router("([A_Z]+) (.*), function ($method, $path) {
    return "Request matched $method and $path";
});

控制器

PHP 类可以通过在公开端点(index.php)上使用 controller($path, $class) 绑定到 URL。

$app->controller('/', 'ExampleController');

在这种情况下,请求将映射到相应的类方法,如下所示

<?php

class ExampleController {

    // GET /?k=v
    function index($querystring) {
    
    }
    
    // GET /(.*)?k=v
    function get($path1, $path2, ..., $querystring) {
    
    }
    
    // Runs before all actions
    function before() {
        
    }
    
    // Runs before post();
    function beforePost($body) {
    
    }
    
    // POST /
    function post($body) {
    
    }
    
    // Other request methods are also valid, i.e. head(), options(), beforeHead(), etc
    
}

如果控制器上存在与第一个参数($path[0])同名的方法,它将使用剩余的参数被调用

// (GET|POST|PUT|...) /example/(.*)
function example($path[1], $path[2], ...) {
    // check $_SERVER['REQUEST_METHOD'] and process data
}

此函数名称也可以以请求方法为前缀。在这种情况下,查询参数作为最后一个参数传递

// GET /example/(.*)
function getExample($path[1], $path[2], ..., $_GET) {

}

// POST /example/(.*)
function postExample($path[1], $path[2], ..., $decoded_post_body) {

}

其他请求方法也有效(即 HEAD、OPTIONS 等),请查看示例子目录中的其他用法。

自动路由

您可以使用以下方式在特定命名空间上引导应用程序

$app->run('Namespace');

运行时,路由器自动将传入的请求映射到给定的命名空间。例如,对 /products 的请求将实例化 Namespace\ProductsController 类。

如果控制器不存在,请求将被传递到 Namespace\HomeController。请查看 example/app-run.php 以获取一个工作演示。

依赖注入

从版本 2.0 开始,路由器扩展了 Dice,它为应用程序提供了一个依赖注入容器。

<?php
// include the composer autoloader
require_once('../vendor/autoload.php')

use Objectiveweb\Router;

$app = new Router();

// Configure the DI container rules for the PDO class
$app->addRule('PDO', [
    'shared' => true,
    'constructParams' => ['mysql:host=127.0.0.1;dbname=mydb', 'username', 'password'] 
]);

// From now on, you can get a configured PDO instance using
$pdo = $app->create('PDO');

当绑定到路径时,控制器(以及这些控制器的依赖项)将自动解决。例如,如果您定义了控制器

<?php

namespace MyApplication;

class MyController {

    private $pdo;
    
    function __construct(PDO $pdo) {
        $this->pdo = pdo;
    }
    
    function index() {
        // query the database using $this->pdo
    }
}

MyApplication\MyController 被路由器实例化时,一个配置的 PDO 实例将被注入并按需重用。

您可以通过向控制器的构造函数添加类型提示参数来注入依赖项

function __construct(\Util\Gmaps $gmaps, \DB\ProductsRepository $products) {
  $this->gmaps = $gmaps;
  $this->products = $products;
}

// Use $this->gmaps and $this->products on other functions

在另一个示例中,让我们实例化 Twig

// index.php

$app = new \Objectiveweb\Router();

$app->addRule('Twig_Loader_Filesystem', array(
    'shared' => true,
    'constructParams' => [ TEMPLATE_ROOT ]
));

$app->addRule('Twig_Environment', array(
    'shared' => true,
    'constructParams' => [
        [ 'instance' => 'Twig_Loader_Filesystem' ],
        [ 'cache' => APP_ROOT.'/cache' ],
        [ 'auto_reload' => true ]
    ],
    'call' => [
        [ 'addGlobal', [ 'server', $_SERVER['SERVER_NAME'] ] ],
        [ 'addGlobal', [ 'app_name', APP_NAME ] ],
        [ 'addGlobal', [ 'session', $_SESSION ] ],
        [ 'addFunction', [ new Twig_SimpleFunction('url', function ($path) {
            return \Objectiveweb\Router::url($path);
        })]]
    ]
));

$app->controller('/', 'MyController')

然后,在控制器构造函数中注入它

class MyController {

    private $twig;
    private $pdo;
    
    function __construct(Twig_Environment $twig, PDO $pdo) {
        $this->twig = $twig;
        $this->pdo = $pdo;
    }
    
    function index() {
        return $this->twig->render(...);
    }
}

您也可以使用以下方式获取 twig 引用

$twig = $app->create('Twig_Environment');

规则

Dice 规则可以使用以下属性进行配置

  • shared (boolean) - 是否在整个容器中使用单个实例。 查看示例
  • inherit (boolean) - 是否将规则也应用于子类(默认为 true)。 查看示例
  • constructParams (array) - 传递给构造函数的额外参数。 查看示例
  • substitutions (array) - 依赖项的键值替换。 查看示例
  • 调用(多维数组)- 在对象构造后将被调用的方法及其参数列表。 查看示例
  • instanceOf(字符串)- 要初始化的类名。当未将类名传递给 $app->addRule() 时使用。 查看示例
  • shareInstances(数组)- 将在整个单个对象树中共享的类名列表。 查看示例