Laravel 如何实现自定义资源路由

Laravel 如何实现自定义资源路由

最近在开发过程中,发现总有一些路由需要重复定义,比如切换状态,导出,回收站啊之类的。如果使用 Laravel 自带的资源路由方法,还不足以满足重复劳动得过程。所以是否有方法可以自定义项目得资源路由呢?在 Laravel 中,资源路由一般有两种

服务端渲染

Route::resource('xxxxx')

resource 路由包含以下几个方法

  • index
  • store
  • create
  • show
  • edit
  • upate
  • destroy

Api 资源路由

Route::apiResource('xxxxx')

ApiResource 则是用 Resource 方法生成,仅仅保存了下面几个方法

$only = ['index', 'show', 'store', 'update', 'destroy'];

现在项目一般都采用前后端分离,所以一般都是使用 apiResource 这个方法,这个方法如上所示只提供五个方法,即五个路由。所以如果项目中需要一些特定得每次都加得路由,必须还要自己再添加一条,很不方便。那在 Laravel 中是不是可以自己扩展属于项目独有得 resource 方法呢?答案是当然可以,而且非常简单

如何实现

一般都是在项目中这样定义资源路由的, 通过门面 Route 访问 apiResource 方法进行定义,如下

Route::apiResource('hello', HelloController::class);

实际上通过门面调用的实际是 Illuminate\Routing\RouterapiResource 方法,内容如下

public function apiResource($name, $controller, array $options = [])
{
    $only = ['index', 'show', 'store', 'update', 'destroy'];

    if (isset($options['except'])) {
        $only = array_diff($only, (array) $options['except']);
    }

    // 实际调用的是 resource 方法
    return $this->resource($name, $controller, array_merge([
        'only' => $only,
    ], $options));
}

实际上 apiResource 是用 resource 方法包装的,所以再来看看 resource 方法做了啥

public function resource($name, $controller, array $options = [])
{
    // 这里是关键的地方
    if ($this->container && $this->container->bound(ResourceRegistrar::class)) {
        $registrar = $this->container->make(ResourceRegistrar::class);
    } else {
        $registrar = new ResourceRegistrar($this);
    }

    // 这一步不用关注
    return new PendingResourceRegistration(
        $registrar, $name, $controller, $options
    );
}

最关键的地方就是 ResourceRegistrar,这里就叫资源路由注册器吧。

  • 首先查找容器中是否有资源路由注册器的绑定实现,如果有,直接从容器中 make 出来
  • 如果容器中没有绑定,则直接使用 new 实例化

那就是说,如果自定义自己的资源路由注册器,然后再绑定 ResourceRegistrar 的实现,就可以实现让框架使用自定义的路由注册器了。

这解决了资源路由注册器的问题,还需要一个方法来调用,从上来得知

Route::apiResource('hello', HelloController::class);

实际上就是 Illuminate\Routing\RouterapiResource 方法。那么如何在 Illuminate\Routing\Router 添加自定义方法呢?没错,首先就要想到它支不支持
Macroable?🤣 显而易见,肯定是支持的,那么依葫芦画瓢,去注册一个吧。找到 AppServiceProvider,在里面注册即可

添加自定义的资源路由方法

因为是做后台系统项目,这里就将资源路由方法定义为 adminResource

Router::macro('adminResource', function ($name, $controller, array $options = []) {
    // 这里添加 enable 和 export
    $only = ['index', 'show', 'store', 'update', 'destroy', 'enable', 'export'];

    if (isset($options['except'])) {
        $only = array_diff($only, (array) $options['except']);
    }

    return $this->resource($name, $controller, array_merge([
        'only' => $only,
    ], $options));
});

实现一个资源路由注册器

当然并不是自己去实现,而是集成 Illuminate\Routing\ResourceRegistrar 即可。在它的基础上,再添加 enableexport 两个方法实现就可以,如下

namespace Defined;

use Illuminate\Routing\ResourceRegistrar as LaravelResourceRegistrar;
use Illuminate\Routing\Route;

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

    // 添加 enable 方法路由
    protected function addResourceEnable($name, $base, $controller, $options): Route
    {
        $name = $this->getShallowName($name, $options);

        $uri = $this->getResourceUri($name).'/enable/{'.$base.'}';

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

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

    // 添加 export 方法路由
    protected function addResourceExport($name, $base, $controller, $options): Route
    {
        $uri = $this->getResourceUri($name).'/export';

        unset($options['missing']);

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

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

实现好了之后,还需要绑定到容器里, 还是找到 AppServiceProvider,在里面注册即可

// 资源路由注册器
$this->app->bind(ResourceRegistrar::class, \Defined\ResourceRegistrar::class);

完成之后测试一下看看,我本地使用 UserController 测试

Route::adminResource('users', UserController::class);

完成之后呢,使用 php artisan route:list | grep users 查看

GET|HEAD api/users ................... users.index › UserController@index
POST api/users ....................... users.store › UserController@store
# put 请求 符合预期
PUT api/users/enable/{user} ...........users.enable › UserController@enable
# Get 请求 符合预期
GET|HEAD api/users/export ............. users.export › UserController@export
GET|HEAD api/users/{user} ............. users.show › UserController@show
PUT|PATCH api/users/{user} ............users.update › UserController@update
DELETE api/users/{user} ............... users.destroy › UserController@destroy

原文地址

  • 19
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值