aurasidera/sextant

灵活且无偏见的PHP路由库。

v3.3 2023-03-10 11:00 UTC

This package is auto-updated.

Last update: 2024-09-10 14:15:11 UTC


README

灵活且无偏见的PHP路由库。

Sextant 允许用户轻松定义路由,而不强制用户遵循任何特定约定,也不实现过度复杂的模式。您将路由声明为一个对(条件动作):满足第一个路由条件的动作将被执行。

条件是任何可以返回布尔值的 可调用 对象。默认情况下,提供了一些现成的条件模型供您使用,但您可能会最终使用强大的 Simple 条件,它原生支持方法和URL匹配,以及URL中的命名参数。

动作是任何 可调用 对象。真的,这里没有太多花哨的东西。Sextant 已经提供了现成的动作模型,例如 "显示此字符串","显示此JSON","包含此PHP脚本" 等。

您可以定义一个默认动作,在没有任何路由匹配时执行(对于自定义404页面很有用)。

安装

Sextant 可以通过 Composer 安装,尽管也提供了手动安装的方法。

要求

php>= 7.0.0

Composer

aura/sextant 添加到您的 composer.json 文件中,或者运行

composer require aura/sextant

手动

克隆或下载此存储库

git clone https://github.com/AuraSidera/Sextant.git

或者

wget https://github.com/AuraSidera/Sextant/archive/master.zip

文件结构遵循 PSR-4:包含文件时没有太多惊喜。

示例

基本用法:涵盖了大多数用例!

对于大多数应用程序,您只需要一些将动作关联到URL的机制。这太棒了,而且非常简单!您可以复制粘贴这些内容,无需提问

// Initializes just a couple of stuffs
$router = new \AuraSidera\Sextant\Router();
$router->setConditionFactory(new \AuraSidera\Sextant\ConditionFactory\Simple())
       ->setActionFactory(new \AuraSidera\Sextant\ActionFactory\Script());

// Declares routes
$router->addRoute(['GET', '/'], 'homepage.php')
       ->addRoute(['GET', 'users/{id}'], 'user.php')
       ->addRoute(['GET', 'users/{id}/activities/{from:date}/{to:date}'], 'user_activities.php')
       ->setDefaultAction(new \AuraSidera\Sextant\ActionFactory\NotFound());

// Reads request state
$state = \AuraSidera\Sextant\State::getStateFromServer();

// Gets the job done!
$router->match()

这里发生了什么?

  • 首先,我们需要初始化路由器。显然。
  • 然后,我们设置条件和动作的默认抽象工厂。这不是必需的,但可以使事情变得容易得多!
  • 我们声明路由!
    • 我们将 ConditionFactory\Simple 设置为条件的默认工厂,因此我们可以仅将它们写成数组 [method, URL模式]。它还会将值绑定到括号中的占位符,如 {id} 一样!您还可以要求值必须是特定类型,如 {from:date}
    • 我们将 ActionFactory\Script 设置为动作的默认工厂,因此我们可以仅将PHP文件的名称写入其中,它将被执行;GET/POST参数,头部,URL中的命名参数将传递给动作,因此无需担心
  • 我们设置一个默认动作,使用Sextant内置的 ActionFactory\NotFound 工厂
  • 我们告诉路由器继续寻找匹配的路由。就是这样,真的。

高级用法

为了充分利用Sextant,您需要了解一些关于系统的知识。在继续之前,请务必阅读(并理解)概念部分。

使用默认工厂很酷,但有时您需要更多的灵活性。没关系:您仍然可以设置默认工厂,但对于某些路由器,可以使用特定的工厂覆盖它们。假设您大多数情况下对 ConditionFactory\Simple 的行为很满意,但您希望无论条件如何都执行特定的URL模式下的动作:您可以使用基本用法示例并添加

$url_pattern_condition = new \AuraSidera\ConditionFactory\UrlPattern();
...
$router->addRoute($url_pattern_condition('respond-to-any-method'), 'script.php');

对于动作也是如此,假设您想显示JSON文档

$json_action = new \AuraSidera\ActionFactory\Json();
...
$router->addRoute(['GET', 'my-json'], $json_action('path-to-json.json'));

猜猜看?您可以混合条件和动作

$url_pattern_condition = new \AuraSidera\ConditionFactory\UrlPattern();
$json_action = new \AuraSidera\ActionFactory\Json();
...
$router->addRoute($url_pattern_condition('respond-to-any-method'), $json_action('path-to-json.json'));

这会变得更多:这是简洁和灵活之间的权衡。

六分仪提供了一些现成的条件和动作工厂,您可以根据需要进行操作。如果您想更进一步,可以尝试使用元条件:它们是特殊的条件,允许构建任意复杂、基于布尔的条件。以下是一个故意设计得过于复杂的条件

$method = new \AuraSidera\ConditionFactory\Method();
$url = new \AuraSidera\ConditionFactory\UrlPattern();
$and = new \AuraSidera\ConditionFactory\Conjunction();
$or = new \AuraSidera\ConditionFactory\Disjunction();
$not = new \AuraSidera\ConditionFactory\Negation();
...
$route->addRoute(
    $and(
        $or($not($method('GET')), $url('users/{id}')),
        $or($method('GET'), $url('users'), $url('users/{id}/edit')),
        $not($method('POST'))
    ),
    'some-action.php'
);

这是什么东西?这是一条需要

(method != GET OR URL = users/{id}) AND (method = GET OR URL = users OR url = users/{id}/edit) AND (method != POST)

显然这不是一条现实的路,但您可以看到任何在合取范式中的公式都可以通过这些机制来表示。因此,六分仪在布尔代数方面是完备的!太棒了!

TLDR:您可以在不接触代码的情况下动态创建自定义复杂布尔条件。

技术使用

为什么您要这么做?我想,您是那种...

您可以为自定义条件和动作定义自己的。请记住以下咒语

condition: State => bool
action: State => nothing

在实现自定义动作或条件时,匹配这些类型,您将一切顺利。您可以使用函数、匿名函数、闭包或可调用对象(实现__invoke魔法方法)。以下是一个示例

$router->addRoute(
    function (\AuraSidera\Sextant\State $state) {
        if ($state->getUrl() == 'X') {
            $state->addMatch('X') = 42;
            return true;
        }
        else {
            return count($state->getParametersAsDictionary()) < count($state->getHeadersAsDictionary());
        }
    },
    function (\AuraSidera\Sextant\Sate $state) {
        echo "This is the URL: " . $state->getUrl() . "<br>";
        echo "And these are the matches I got: ";
        print_r($state->getMatchesAsDictionary());
    }
);

相当不错,不是吗?

概念

六分仪中的主要概念。

状态

状态是一个表示请求当前状态的对象。状态总是包括

  • URL
  • 方法
  • 请求参数(GET、POST等)作为关联数组
  • HTTP头部作为关联数组
  • 匹配,一个包含URL匹配信息的关联数组(任意)

所有这些都可以通过适当的getter方法检索。状态可以通过使用辅助静态工厂方法getStateFromServer自动从服务器读取

$state = \AuraSidera\Sextant\State::getStateFromServer();
$url = $state->getUrl();
$method = $state->getMethod();
$parameters = $state->getParametersAsDictionary();
$headers = $state->getHeadersAsDictionary();
$matches = $state->getMatchesAsDictionary();

状态可以装饰为命名实体,可以通过成员和数组访问语法访问。尝试读取未定义的实体将返回null

$state = \AuraSidera\Sextant\State::getStateFromServer();
$state->some_name = 42;
echo $state->some_name;  // Displays 42

echo isset($state->fake) ? 'set' : 'unset';  // Displays 'unset'
echo $state->fake;  // Displays '' (a null value is print)

$state['other_name'] = 21;  // Array access works too, both for writing...
echo $state['other_name'];  // ... and reading values
echo $state->other_name;    // It is fine to mix both styles

条件

条件是任何返回布尔值的可调用对象。六分仪将自动传递一个测试路由的状态。六分仪还提供了一些现成的条件,作为抽象工厂的形式,在ConditionFactory命名空间下。工厂可以被实例化并在路由中使用,如下面的示例所示

// Instantiates a condition factory which produces conditions matching methods
$method_factory = new \AuraSidera\ConditionFactory\Method();

// Matches only HTTP/GET requests
$method_condition_get = $method_factory('GET');

// Matches only HTTP/POST requests
$method_condition_post = $method_factory('POST');

// Conditions can be used in routes
$router->addRoute($method_condition_get, 'action_1');
$router->addRoute($method_condition_post, 'action_2');

通常更方便使用以下等效、更简洁、更清晰的语法

$method = new \AuraSidera\ConditionFactory\Method();

$router->addRoute($method('GET'), 'action_1');
$router->addRoute($method('POST'), 'action_2');

请注意,尽管六分仪使用类来实现产生条件的工厂,但这种模式不是强制的。可以使用任何类型的函数(包括匿名函数、闭包和可调用对象)

function my_condition(\AuraSidera\Sextant\State $state): bool {
    return true;
}

$router->addRoute('my_condition', 'action');

动作

动作是可调用的,没有其他特别要求。它们通常在页面上生成某种类型的输出,设置一些头部,操作数据库,或者这些的组合。六分仪在调用动作时将自动注入状态。六分仪提供了一些现成的动作,如默认的404页面设置适当的头部,JSON渲染器,文件渲染器和脚本执行器。《ActionFactory》包含这样的动作工厂。动作工厂是一个构建动作的对象,可以在路由中使用

// Istantiates an action factory rendering a JSON document
$json_action_factory = new \AuraSidera\ActionFactory\Json();

// Renders a JSON when called
$json_action = $json_action_factory('path-to-document.json');

// Actions can be used in routes
$router->addRoute('condition', $json_action);

以下等效且更简洁的语法是首选

$json = new \AuraSidera\ActionFactory\Json();

$router->addRoute('condition', $json('path-to-document.json'));

六分仪使用类来实现产生动作的工厂,但这不是强制的。也可以使用自定义函数

function my_action(\AuraSidera\Sextant\State $state) {
    echo "Hello, world!";
    $state->track = 1;
}

动作可以更改与$state关联的命名实体,但不能修改URL、方法、参数或头部。

路由

路由是条件和动作之间的关联。路由在路由器内声明,最终将尝试在给定上下文中(URL、方法、头部等)匹配它们。第一个条件在上下文中得到满足的路由将被选择,并执行其动作。路由的测试顺序与它们声明的顺序相同。