inanepain/routing

使用属性进行 HTTP 路由。

0.1.2 2022-08-13 17:37 UTC

This package is auto-updated.

Last update: 2024-09-20 09:41:56 UTC


README

()

使用 php 属性 进行 HTTP 路由。

简介:属性

什么是 属性?它是一个类,就像任何其他类一样,只是有一个 Attribute 属性。那么为什么你更像是对待一个只能持有几个值的 enumMap 呢?你不会用你在自定义属性上使用的类这样做!但是我不怪你,这都归咎于文档中使用的某些糟糕的措辞。

那么我应该怎么想 属性 呢?就像类一样。更确切地说,是那些执行任务的对象的类。像 #[Route(name: 'home', path: '/')] 这样的用法,当你这样看待它时可能会更有意义:$route = new Route('/', 'home');。这里有一个有趣的实验可以尝试;从 Route 中移除 Attribute,然后让 Router 接受一个包含 Route 参数的数组作为参数。很简单,不是吗?通过练习,你会发现在更多类上可以这样做。

希望这能让您以新的、更现实的方式思考 属性,从而在更多类中添加 #[Attribute] 行。

安装

composer require inanepain/routing

使用方法

快速概述显示两个示例中与 Route 属性 相关的部分。虽然它们都不是完整的,但简单的示例可以轻松运行。请参阅附录以获取您将需要与 index.php 文件一起使用的 .htaccess 文件。

示例:简单

使用 php 内置的 web 服务器的一个简单示例,php -S localhost:8080 -t public index.php

MainController.php

class MainController {
    ...

    #[Route(path: '/', name: 'home')]
    public function home(): void {
        ...
        echo <<<HTML
...
HTML;
    }

    ...

    #[Route(path: '/product/{product}', name: 'product', )]
    public function productTask(array $params): void {
        $sql = "...where product_id = '{$params["product"]}'";
        ...
        echo <<<HTML
...
HTML;
    }

    ...
}

index.php

use App\Controller\MainController;
use Inane\Routing\Router;

require_once 'vendor/autoload.php';

$file = 'public' . $_SERVER['REQUEST_URI'];

// Server existing files in web dir
if (file_exists($file) && !is_dir($file)) return false;

$router = new Router();
$router->addRoutes([MainController::class]);

if ($match = $router->match()) {
    $controller = new $match['class']();
    $controller->{$match['method']}($match['params']);
} else {
    throw new Exception('Request Error: Unmatched `file` or `route`!');
}

示例:应用程序

一个稍微复杂一些的示例。

各个部分

IndexController.php

class IndexController extends AbstractController {
    ...

    #[Route(path: '/', name: 'home')]
    public function indexTask(): array {
        ...
    }

    ...

    #[Route(path: '/product/{product}', name: 'product', )]
    public function productTask(): array {
        ...
    }

    ...

    #[Route(path: '/product/{product}/review/{id<\d+>}', name: 'product-review')]
    public function reviewTask(): array {
        ...
    }

    ...
}

index.phtml(视图模板)

...
<a class="menu-item" href="<?=$route->url('product', ['product' => $item['id']])?>"><?=$item['name_long']?></a>
...

website(渲染的视图)

<a class="menu-item" href="/product/mega-maid">Mega Maid (Household Robot Helper)</a>

将所有部分组合起来

Application.php

class Application {
    ...

    protected function initialise(): void {
        ...
        $this->router = new Router([
            IndexController::class,
            ...
            WhoopsController::class,
            ...
        ]);
        ...
    }

    ...

    public function run(): void {
        ...
        if ($match = $this->router->match()) {
            $controller = new $match['class']($match['params']);
            $data = $controller->{$match['method']}();
            ...
            $body = $this->renderer->render($template, $data);
            ...
        }
        ...
    }

    ...
}

附录:.htaccess

您还需要在您的 .htaccess 文件中进行一些魔法操作,以便 index.php 处理所有请求。

RewriteEngine On
# The following rule tells Apache that if the requested filename exists, simply serve it.
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [L]

# The following rewrites all other queries to index.php. The 
# condition ensures that if you are using Apache aliases to do
# mass virtual hosting or installed the project in a subdirectory,
# the base path will be prepended to allow proper resolution of
# the index.php file; it will work in non-aliased environments
# as well, providing a safe, one-size fits all solution.
RewriteCond %{REQUEST_URI}::$1 ^(/.+)/(.*)::\2$
RewriteRule ^(.*) - [E=BASE:%1]
RewriteRule ^(.*)$ %{ENV:BASE}/index.php [L]

<Limit GET HEAD POST PUT DELETE OPTIONS>
# Deprecated apache 2.2 syntax:
# Order Allow,Deny
# Allow from all
# Apache > 2.4 requires:
Require all granted
</Limit>