注册控制器路径时防止编号参数

时间:2014-03-12 11:23:09

标签: php laravel-4

Laravel有一个了不起的路由系统,但我特别挣扎了一点。

我想删除为路由定义控制器时创建的额外可选路由。

在Laravel 3中,您显然可以执行以下操作,但从未使用过v3我不知道这是否是我正在寻找的,无论如何,它在v4中都不起作用。

Router::$segments = 0;

例如,当我像这样定义我的路线时:

Route::group(array('prefix' => 'monitoring'), function() {
    // Handle hosts
    Route::controller('hosts/', 'Apm\Controllers\Monitoring\Hosts\Index');
    Route::controller('hosts/{host}', 'Apm\Controllers\Monitoring\Hosts\Host');
    Route::controller('hosts/{host}/{service}', 'Apm\Controllers\Monitoring\Hosts\Service');
});

我的路线将在artisan routes命令中显示如下:

+--------+------------------------------------------------------------------------------------------------+------+---------------------------------------------------------+----------------+---------------+
| Domain | URI                                                                                            | Name | Action                                                  | Before Filters | After Filters |
+--------+------------------------------------------------------------------------------------------------+------+---------------------------------------------------------+----------------+---------------+
|        | GET|HEAD /                                                                                     |      | Closure                                                 |                |               |
|        | GET|HEAD monitoring/hosts/status/{one?}/{two?}/{three?}/{four?}/{five?}                        |      | Apm\Controllers\Monitoring\Hosts\Index@getStatus        |                |               |
|        | GET|HEAD monitoring/hosts/details/{one?}/{two?}/{three?}/{four?}/{five?}                       |      | Apm\Controllers\Monitoring\Hosts\Index@getDetails       |                |               |
|        | GET|HEAD monitoring/hosts/report/{one?}/{two?}/{three?}/{four?}/{five?}                        |      | Apm\Controllers\Monitoring\Hosts\Index@getReport        |                |               |
|        | GET|HEAD monitoring/hosts/thresholds/{one?}/{two?}/{three?}/{four?}/{five?}                    |      | Apm\Controllers\Monitoring\Hosts\Index@getThresholds    |                |               |
|        | GET|HEAD monitoring/hosts/timeline/{one?}/{two?}/{three?}/{four?}/{five?}                      |      | Apm\Controllers\Monitoring\Hosts\Index@getTimeline      |                |               |
|        | GET|HEAD monitoring/hosts/index/{one?}/{two?}/{three?}/{four?}/{five?}                         |      | Apm\Controllers\Monitoring\Hosts\Index@getIndex         |                |               |
|        | GET|HEAD monitoring/hosts                                                                      |      | Apm\Controllers\Monitoring\Hosts\Index@getIndex         |                |               |
|        | GET|HEAD monitoring/hosts/{host}/status/{one?}/{two?}/{three?}/{four?}/{five?}                 |      | Apm\Controllers\Monitoring\Hosts\Host@getStatus         |                |               |
|        | GET|HEAD monitoring/hosts/{host}/details/{one?}/{two?}/{three?}/{four?}/{five?}                |      | Apm\Controllers\Monitoring\Hosts\Host@getDetails        |                |               |
|        | GET|HEAD monitoring/hosts/{host}/report/{one?}/{two?}/{three?}/{four?}/{five?}                 |      | Apm\Controllers\Monitoring\Hosts\Host@getReport         |                |               |
|        | GET|HEAD monitoring/hosts/{host}/thresholds/{one?}/{two?}/{three?}/{four?}/{five?}             |      | Apm\Controllers\Monitoring\Hosts\Host@getThresholds     |                |               |
|        | GET|HEAD monitoring/hosts/{host}/timeline/{one?}/{two?}/{three?}/{four?}/{five?}               |      | Apm\Controllers\Monitoring\Hosts\Host@getTimeline       |                |               |
|        | GET|HEAD monitoring/hosts/{host}/index/{one?}/{two?}/{three?}/{four?}/{five?}                  |      | Apm\Controllers\Monitoring\Hosts\Host@getIndex          |                |               |
|        | GET|HEAD monitoring/hosts/{host}                                                               |      | Apm\Controllers\Monitoring\Hosts\Host@getIndex          |                |               |
|        | GET|HEAD monitoring/hosts/{host}/{service}/status/{one?}/{two?}/{three?}/{four?}/{five?}       |      | Apm\Controllers\Monitoring\Hosts\Service@getStatus      |                |               |
|        | GET|HEAD monitoring/hosts/{host}/{service}/details/{one?}/{two?}/{three?}/{four?}/{five?}      |      | Apm\Controllers\Monitoring\Hosts\Service@getDetails     |                |               |
|        | GET|HEAD monitoring/hosts/{host}/{service}/report/{one?}/{two?}/{three?}/{four?}/{five?}       |      | Apm\Controllers\Monitoring\Hosts\Service@getReport      |                |               |
|        | GET|HEAD monitoring/hosts/{host}/{service}/thresholds/{one?}/{two?}/{three?}/{four?}/{five?}   |      | Apm\Controllers\Monitoring\Hosts\Service@getThresholds  |                |               |
|        | GET|HEAD monitoring/hosts/{host}/{service}/timeline/{one?}/{two?}/{three?}/{four?}/{five?}     |      | Apm\Controllers\Monitoring\Hosts\Service@getTimeline    |                |               |
|        | GET|HEAD monitoring/hosts/{host}/{service}/self-healing/{one?}/{two?}/{three?}/{four?}/{five?} |      | Apm\Controllers\Monitoring\Hosts\Service@getSelfHealing |                |               |
|        | GET|HEAD monitoring/hosts/{host}/{service}/index/{one?}/{two?}/{three?}/{four?}/{five?}        |      | Apm\Controllers\Monitoring\Hosts\Service@getIndex       |                |               |
|        | GET|HEAD monitoring/hosts/{host}/{service}                                                     |      | Apm\Controllers\Monitoring\Hosts\Service@getIndex       |                |               |

简单地说,我想摆脱{one?}/{two?}/{three?}/{four?}/{five?}部分,因为我总能预测我的参数,而且我经常想要指定必须使用的控制器并命名它们。

更新 我们决定不隐式列出所有路由,因为这会使我们的routes.php极度膨胀(如果不是数千条路线就必须制作数百条)。除了路由器解析的额外参数之外,控制器设置就像我们现在完美地工作一样,当隐式定义具有Route::get的路由时,这些参数不存在。

我应该提一下,我们稍微修改了Router类,以便能够使子资源成为可能。

2 个答案:

答案 0 :(得分:1)

要回答我自己的问题,我们已经做的是对Router类进行覆盖。我现在明白这也是解决这个问题的关键。

Route::controller基本上允许您将其中的所有方法隐式注册为路由的终点。如上所述,这不是您通常要做的事情,但我们在采取这种方式之前做出了明智的决定。为了解决不能正确地说哪些参数可以传递给函数的问题,他们添加了这些5'通配符'参数。我们在问题中使用类,这些参数不是必需的。

我想指出,使用ReflectionMethod::getParameters可能会使用更多反射法来解决这个问题。虽然,也有很多人可以反对使用类似的东西。

所以,正如您可能已经猜到的那样,简而言之,Laravel使用您传递给Route::controller的类的反射类,并以这种方式从代码中提取路径端点。

参数被添加到类Illuminate\Routing\ControllerInspector@addUriWildcards中,因此为了防止添加这些参数,我们需要覆盖此类。因为此类已实例化,然后在Illuminate\Routing\Router类中使用,我们还需要覆盖Router

在Laravel中,您需要创建IoC container来为核心类创建覆盖。对于Router,这没有什么不同。虽然标准文档(目前)并不是特别清楚如何做到这一点。

(我们实现了psr-4并将名称空间Apm设置为app/以自动加载我的类)

app/Lib/Routing/RoutingServiceProvider.php

<?php namespace Apm\Lib\Routing;
use Illuminate\Routing\RoutingServiceProvider as LaravelRoutingServiceProvider;

class RoutingServiceProvider extends LaravelRoutingServiceProvider
{
    protected function registerRouter()
    {
        $this->app['router'] = $this->app->share(function($app)
        {
            $router = new Router($app['events'], $app);

            // If the current application environment is "testing", we will disable the
            // routing filters, since they can be tested independently of the routes
            // and just get in the way of our typical controller testing concerns.
            if ($app['env'] == 'testing')
            {
                $router->disableFilters();
            }

            return $router;
        });
    }
}

这将路由器类设置为Apm\Lib\Routing\Router,替换Illuminate\Routing\Router

所以app/Lib/Routing/Router.php我们有

<?php namespace Apm\Lib\Routing;
use Illuminate\Routing\Router as LaravelRouter;

class Router extends LaravelRouter
{
    /**
     * Get a controller inspector instance.
     *
     * @return \Apm\Lib\Routing\ControllerInspector
     */
    public function getInspector()
    {
        return $this->inspector ?: $this->inspector = new ControllerInspector;
    }
}

将Controller Inspector设置为Apm\Lib\Routing\ControllerInspector而不是Illuminate\Routing\ControllerInspector

最后在app/Lib/Routing/ControllerInspector.php我们有:

<?php namespace Apm\Lib\Routing;
use Illuminate\Routing\ControllerInspector as LaravelControllerInspector;

class ControllerInspector extends LaravelControllerInspector
{
    /**
     * Add wildcards to the given URI.
     *
     * @param  string  $uri
     * @return string
     */
    public function addUriWildcards($uri)
    {
        return $uri;//.'/{one?}/{two?}/{three?}/{four?}/{five?}';
    }
}

然后为了确保Laravel使用我们的类而不是它自己的类,我们需要在app/config/app.php数组的'providers'中注册服务提供者。

'providers' => array(
        'Apm\Lib\Routing\RoutingServiceProvider',
),

当然,以某种方式能够明确地传递要用于每个端点/函数方法的参数会更好,但是这会破坏隐式设置端点的点。

如果仍然使用此机制,您可能希望更进一步,根据方法接受的参数获取/使用路径参数。虽然没有添加已在被检查控制器的基本路径模式中设置的参数。

Enfin,这解决了我们的问题,因为我们不需要在任何地方添加到路线末尾的参数。

答案 1 :(得分:0)

我不熟悉您可以摆脱这些额外参数的方法,但使用隐式路由不被视为最佳做法,可能会导致许多问题。查看this post了解详情。如果您可以预测参数,我认为最好用Route::get等明确定义您的路线。