exedron/routeller

基于注解的Exedra路由控制器

dev-master 2019-06-25 06:57 UTC

This package is not auto-updated.

Last update: 2024-09-15 01:32:31 UTC


README

- Deprecated : This package has already been merged with https://github.com/rosengate/exedra

\Exedron\Routeller

Exedra的一个基于注解和反射的瘦路由控制器。

简单来说,这是在steroid中用于路由的组件。

简介

为深层嵌套的路由编写大量的\Closure会使代码变得混乱,并且随着代码量的增加,IDE的支持性也不够友好。这个包就是为了解决这一问题,并为你的路由组提供了一个优雅的路由控制器。

控制器是瘦的、扁平的,不能构建,但对路由设计非常了解。

注解设计相当简单,只是@property-value映射。没有太多内容!

要求

这个包只为Exedra工作。它不能独立使用,因为……当然,它是Exedra路由组件的一部分。

安装和用法

安装

通过composer安装

composer require exedron\routeller dev-master

通过服务提供商添加

设置服务提供商

// your application instance
$app->provider->add(\Exedron\Routeller\Provider::class);

通过路由工厂添加

或者,你也可以手动添加处理程序,并设置其他一些内容。

$app->routingFactory->addGroupHandler(new \Exedron\Routeller\Handler($app));

$app->map->addExecuteHandler('routeller_execute', ExecuteHandler::class);

启用缓存

启用基于文件的缓存

$options = array(
    'auto_reload' => true
);

$cache = new \Exedron\Routeller\Cache\FileCache(__DIR__ .'/routing_caches')

$app->provider->add(new \Exedron\Routeller\Provider($cache, $options));

当控制器发生变化时,auto_reload选项允许它重新加载缓存。

用法

在你的路由上,使用group()方法添加控制器。

$app->map['web']->group(\App\Controller\WebController::class);

控制器必须是\Exedron\Routeller\Controller\Controller的类型。

<?php
namespace App\Controller;

use Exedron\Routeller\Controller\Controller;

class WebController extends Controller {

}

添加可执行路由

使用路由属性注解方法。方法名必须以前缀execute开头。

<?php
namespace App\Controller;

use Exedra\Runtime\Context;

class WebController extends \Exedron\Routeller\Controller\Controller
{
    /**
     * @path /
     */
    public function executeIndex(Context $context)
    {
        return 'This is index page';
    }
    
    /**
     * @name about-us
     * @path /about-us
     * @method GET|POST
     */
    public function executeAboutUs(Context $context)
    {
        return 'This is about page';
    }
}

上面的操作与下面的操作类似

use Exedra\Routing\Group;
use Exedra\Runtime\Context;

$app->map['web']->group(function(Group $group) {
    $group['index']->any('/')->execute(function(Context $context) {
        return 'This is index page';
    });
    
    $group['about-us']->any('/about-us')->execute(function(Context $context) {
        return 'This is about page';
    });
});

添加普通路由

你可能想要以面向对象的方式自定义路由,前缀为route

/**
 * @path /faq
 */
public function routeFaq(\Exedra\Routing\Route $route)
{
    $route->execute(function() {
    
    });
}

中间件

通过在方法名前缀为middleware为当前组的路由添加中间件。此方法不需要注解。

public function middlewareAuth(Context $context)
{
    if(!$context->session->has('user_id'))
        return $context->redirect->route('@web.login');

    return $context->next($context);
}

尽管中间件名称是可选的,但你仍然可以设置它。

/**
 * @name csrf
 */
public function middlewareCsrf()
{
    return $context->next($context);
}

子路由/嵌套路由

添加子组路由。方法名必须以前缀group开头。

该方法必须返回路由组模式。

/**
 * @path /products
 */
public function groupProducts()
{
    return \App\Controller\ProductController::class;
}

立即子路由

group前缀类似,但这个方法会立即解析其组。

/**
 * @path /:product-id
 */
public function subProduct(Group $group)
{
    $group['get']->get('/')->execute(function() {
        // do your things
    });
    
    $group['update']->post('/')->execute(function() {
        // do your things
    });
}

普通路由

你也可以通过在方法名前缀为setup来执行通常的路由。此方法不需要注解。

public function setup(Group $group)
{
    $group->get('/')->execute(function() {
    });
}

public function setupCustom(Group $group)
{
    // do another thing
}

此方法还接收Exedra\Application作为第二个参数。

/**
 * @path /comments
 */
public function setup(Group $group, \Exedra\Application $app)
{
    $group->get('/')->execute(function() {
    });
}

RESTful动词

此包还支持简单的RESTful映射。

GET、POST、PUT、PATCH、DELETE动词

根据需要将每个方法前缀为HTTP动词。

/**
 * Get all products
 * @path /
 */
public function getProducts(Context $context)
{
}
/**
 * Create a new product
 * @path /
 */
pubic function postProducts(Context $context)
{
}
/**
 * GET the product
 * @path /[:id]
 */
pubic function getProduct(Context $context)
{
}
/**
 * DELETE the product
 * @path /[:id]
 */
pubic function getProduct(Context $context)
{
}

仅动词方法名

你还可以有一个只有动词的路由。

public function get(Context $context)
{
}

public function post(Context $context)
{
}

当然,这只是一个示例。在Exedra中进行资源设计最佳的方式是通过子路由。

依赖注入

使用已知服务(s)注入

use Exedra\Url\UrlGenerator;

/**
 * @inject context.url
 * @path /
 */
public function get(UrlGenerator $url)
{
    echo $url->current();
}

多个服务

use Exedra\Runtime\Context;
use Exedra\Application;
use Exedra\Routing\Group;

/**
 * @inject context, url, self.response, app, app.map
 * @path /
 */
 public function post(Context $context, $url, $response, Application $app, Group $map)
 {
 }
注意
  • selfcontext是同一类型,是\Exedra\Runtime\Context,当前运行时的上下文。
  • app.前缀的服务将在Exedra\Application容器中查找
  • 没有前缀,如 context.self.app.,解析器将只查找注册了 Context 对象的服务。

其他路由属性

标记和 AJAX

/**
 * @tag users
 * @ajax true
 * @middleware \App\Middleware\Auth
 */
pubic function executeUsers()
{
}

属性(以及示例中间件)

public function middlewareAuth(\Exedra\Runtime\Context $context)
{
    if($context->attr('need_auth', false) && !$context->session->has('user_id'))
        throw new NotLoggedInException;
        
    return $context->next($context);
}

/**
 * @attr.need_auth true
 * @path /admin
 * @method any
 */
public function groupAdmin()
{
    return Admin::class;
}

所有可能的属性

/**
 * @name admin_default
 * @method GET|POST
 * @path /admin/:controller/:action
 * @middleware \App\Middleware\Auth
 * @middleware \App\Middleware\Csrf
 * @middleware \App\Middleware\Limiter
 * @tag admin_default
 * @attr.session_timeout 36000
 * @config.request_limit 15
 */
public function executeAdminDefault($context)
{
    // nah, just a sample.
    $controller = $context->param('controller');
    $action = $context->param('action');
    
    return (new $controller)->{$action}($context);
}

异常

非路由属性标签,如 returnparamthrows 标签将不会被解析。

控制台命令

此包还提供了一个类似的命令在原始路由列表中,只是它增加了更多关于结果细节。

$app = new \Exedra\Application(__DIR__);

//... do some routing

$console = new \Symfony\Component\Console\Application();

$console->add(new \Exedron\Routeller\Console\Commands\RouteListCommand($app, $app->map));

$console->run();

注意

路由名称

对于某些类型的用法,如 executablegrouped 类型的路由,如果未注解 @name 属性,则路由名称将从剩余的小写方法名称中获取。

RESTful 控制器的路由名称

它结合了动词和方法名称。例如,

public function postProducts()
{
}

public function get()
{
}

上述路由将具有类似 .post-products 的方法名称。(@web.products.post-products)

对于只有动词的方法名称,它将只是动词作为名称。其绝对名称可能看起来像: @web.products.get

排序

路由顺序是从上到下读取的。因此,你的路由编写方式很重要。