如何在Laravel 6中扩展Laravel的基本路由资源?

How to extend Laravel's basic route resource in Laravel 6?

我将 Laravel 用作具有许多端点和许多控制器的 API。我正在使用 Route::resource() 方法来定义 REST 端点,但在大多数情况下我需要再添加一个端点,现在我的代码如下所示:

Route::get('product/list', 'ProductController@all');
Route::resource('product', 'ProductController');

Route::get('property/list', 'PropertyController@all');
Route::resource('property', 'PropertyController');

Route::get('customer/list', 'CustomerController@all');
Route::resource('customer', 'CustomerController');

...这个示例不断出现,一遍又一遍。我认为需要有一种实用且更好的方法来在一个地方定义这个 {resource}/list URI。现在我需要重复这个示例:

Route::get('{resource}/list', 'NameOfController@all');

是否有更好的解决方案来只定义一次此端点并在每个控制器中都可用?我能以某种方式避免重复吗?

如果您查看 Illuminate\Routing\Router class 中的 resource 方法,您将看到:

if ($this->container && $this->container->bound(ResourceRegistrar::class)) {
    $registrar = $this->container->make(ResourceRegistrar::class);
} else {
    $registrar = new ResourceRegistrar($this);
}

这意味着你可以绑定一个ResourceRegistrar来覆盖Laravel提供的默认值。因此,要实现您想要的效果,您可以先创建一个新的 class,例如 app/ResourceRegistrar.php,这将扩展 Illuminate\Routing\ResourceRegistrar 并添加一个默认的 'list'

<?php

namespace App;

use Illuminate\Routing\ResourceRegistrar as BaseResourceRegistrar;

class ResourceRegistrar extends BaseResourceRegistrar
{
    protected $resourceDefaults = [
        'index', 'create', 'store', 'show', 'edit', 'update', 'destroy', 'list',
    ];

    /**
     * Add the list method for a resourceful route.
     *
     * @param  string  $name
     * @param  string  $base
     * @param  string  $controller
     * @param  array   $options
     * @return \Illuminate\Routing\Route
     */
    public function addResourceList($name, $base, $controller, $options)
    {
        $uri = $this->getResourceUri($name).'/all';

        $action = $this->getResourceAction($name, $controller, 'list', $options);

        return $this->router->get($uri, $action);
    }
}

然后,您只需在 AppServiceProvider:

中绑定注册商
<?php

namespace App\Providers;

use App\ResourceRegistrar;
use Illuminate\Routing\Router;
use Illuminate\Routing\ResourceRegistrar as BaseResourceRegistrar;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function boot()
    {
        $this->app->bind(BaseResourceRegistrar::class, ResourceRegistrar::class);
    }
}

并且您可以像以前一样注册您的路线,而无需添加额外的行:

Route::resource('product', 'ProductController');
Route::resource('property', 'PropertyController');
Route::resource('customer', 'CustomerController');

然后如果你 运行 php artisan route:list,你应该看到 {resource}/list 路线。

我做到了。您需要扩展注册器

1/2 创建路由器 class

# I made mine in app/Overrides/Router.php
<?php

namespace App\Overrides;

use Illuminate\Routing\Router as BaseRouter;

class Router extends BaseRouter
{
    // You can call it however you want. These are the params you need to pass the original resource() method.
    public function listResource($name, $controller, array $options = [])
    {
        // What make a get route and then a normal resource route you'll be able to call optional methods on.
        $this->get($name.'/all', $controller.'@all')->name($name.'.all');
        return $this->resource($name, $controller, $options);
    }   
}

2/2 绑定在bootstrap/app.php

$app->singleton('router', function ($app) {
    return new \App\Overrides\Router($app['events'], $app);
});

大功告成。

现在举个例子:

Route::listResource('users', 'UserController');
> php artisan r:l
+--------+-----------+----------------------+---------------+---------------------------------------------+--------------+
| Domain | Method    | URI                  | Name          | Action                                      | Middleware   |
+--------+-----------+----------------------+---------------+---------------------------------------------+--------------+
|        | GET|HEAD  | users                | users.index   | App\Http\Controllers\UserController@index   | web          |
|        | POST      | users                | users.store   | App\Http\Controllers\UserController@store   | web          |
|        | GET|HEAD  | users/create         | users.create  | App\Http\Controllers\UserController@create  | web          |
|        | GET|HEAD  | users/list           | users.list    | App\Http\Controllers\UserController@all     | web          |
|        | GET|HEAD  | users/{user}         | users.show    | App\Http\Controllers\UserController@show    | web          |
|        | PUT|PATCH | users/{user}         | users.update  | App\Http\Controllers\UserController@update  | web          |
|        | DELETE    | users/{user}         | users.destroy | App\Http\Controllers\UserController@destroy | web          |
|        | GET|HEAD  | users/{user}/edit    | users.edit    | App\Http\Controllers\UserController@edit    | web          |
+--------+-----------+----------------------+---------------+---------------------------------------------+--------------+