在 Laravel 中为资源控制器添加新方法
Posted
技术标签:
【中文标题】在 Laravel 中为资源控制器添加新方法【英文标题】:Add new methods to a resource controller in Laravel 【发布时间】:2013-05-15 16:56:37 【问题描述】:我想知道是否可以在 Laravel 的资源控制器中添加新方法以及如何做到这一点。
我知道这些方法是默认的(索引、创建、存储、编辑、更新、销毁)。现在我想为同一个控制器添加额外的方法和路由。
这可能吗?
【问题讨论】:
【参考方案1】:只需为该方法单独添加一个路由,在您注册资源之前:
Route::get('foo/bar', 'FooController@bar');
Route::resource('foo', 'FooController');
【讨论】:
请注意,您的新方法必须高于::resource
,否则您会收到错误消息“模型没有查询结果”。
如何传递像 id 这样的参数?目前我已经在 routes.php 中内联了我的自定义方法(就像这里的例子laravel.com/docs/5.1/routing#route-parameters)。理想情况下,我想传递参数以在 FooController 中运行。
发现问题 - 不在 Route 语法中。实际上是在我正在使用的一些自定义中间件中!路线::get('foo/id/bar', 'FooController@bar');将 id 传递给 bar($id) 方法。谢谢!
有人能解释一下为什么自定义路由应该超过资源路由吗???我做了一些测试,似乎放在上面或下面没有区别......
@RicardoVigatti - 资源注册此路由:Route::get('foo/id', ...)
。这会吞下所有以foo
开头并有一个附加段的路由,包括foo/bar
。【参考方案2】:
我只是这样做,添加一个 GET “删除”方法。
创建文件后,您只需要添加
'AntonioRibeiro\Routing\ExtendedRouterServiceProvider',
到您的 app/config.php 中的“提供者”
在同一文件中编辑 Route 别名:
'Route' => 'Illuminate\Support\Facades\Route',
改成
'Route' => 'AntonioRibeiro\Facades\ExtendedRouteFacade',
并确保这些文件正在被自动加载,它们必须位于您的 composer.json (“自动加载”部分)中的某个目录中。
那么你只需要:
Route::resource('users', 'UsersController');
如果你运行php artisan routes
,这(看最后一行)是结果:
这些是我的源文件:
ExtendedRouteFacade.pas
<?php namespace AntonioRibeiro\Facades;
use Illuminate\Support\Facades\Facade as IlluminateFacade;
class ExtendedRouteFacade extends IlluminateFacade
/**
* Determine if the current route matches a given name.
*
* @param string $name
* @return bool
*/
public static function is($name)
return static::$app['router']->currentRouteNamed($name);
/**
* Determine if the current route uses a given controller action.
*
* @param string $action
* @return bool
*/
public static function uses($action)
return static::$app['router']->currentRouteUses($action);
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor() return 'router';
ExtendedRouter.pas
<?php namespace AntonioRibeiro\Routing;
class ExtendedRouter extends \Illuminate\Routing\Router
protected $resourceDefaults = array('index', 'create', 'store', 'show', 'edit', 'update', 'destroy', 'delete');
/**
* Add the show method for a resourceful route.
*
* @param string $name
* @param string $base
* @param string $controller
* @return void
*/
protected function addResourceDelete($name, $base, $controller)
$uri = $this->getResourceUri($name).'/'.$base.'/destroy';
return $this->get($uri, $this->getResourceAction($name, $controller, 'delete'));
ExtendedRouteServiceProvider.pas
<?php namespace AntonioRibeiro\Routing;
use Illuminate\Support\ServiceProvider;
class ExtendedRouterServiceProvider extends ServiceProvider
/**
* Indicates if loading of the provider is deferred.
*
* @var bool
*/
protected $defer = true;
/**
* Register the service provider.
*
* @return void
*/
public function register()
$this->app['router'] = $this->app->share(function() return new ExtendedRouter($this->app); );
/**
* Get the services provided by the provider.
*
* @return array
*/
public function provides()
return array('router');
【讨论】:
您能否为 Laravel 5 及更高版本提供相同的内容?我一直在尝试重现这个......但我似乎无法找到他们在容器中注册“路由”访问器的位置。 为什么文件的扩展名为 .pas? 有道理,但提供者部分似乎不适用于 laravel 8.0。 可悲的是过于复杂【参考方案3】:Route::resource('foo', 'FooController');
Route::controller('foo', 'FooController');
试一试。给你添加额外的方法,如 getData() 等。这对我保持 route.php 干净
【讨论】:
是的,这行得通。 Laravel 5.1 文档没有提到 Route::resource 和 Route::controller 可以一起使用,而是提到了补充资源控制器。所以这很困惑。但是你的ans证明这些是可以一起使用的 很抱歉,Hassan jamal,这两个人不能一起工作。那么,如果我只使用 Route::resource,那么现在如何在控制器中设置自定义 post 方法【参考方案4】:这也很好用。无需添加更多路由,只需使用资源控制器的 show 方法,如下所示:
public function show($name)
switch ($name)
case 'foo':
$this -> foo();
break;
case 'bar':
$this ->bar();
break;
defautlt:
abort(404,'bad request');
break;
public function foo()
publcc function bar()
我使用默认抛出自定义错误页面。
【讨论】:
这感觉就像是真正的代码味道。我不希望我的控制器处理多个操作。 这不是打破了 REST 的概念吗? 这种事没必要!!!这就是为什么我们首先要有路线。路由逻辑不能放在控制器上。【参考方案5】:是的,有可能……
在我的例子中,我添加了方法:数据来处理 HTTP POST 方法中对 /data.json 的请求。
这是我做的。
首先我们扩展 Illuminate\Routing\ResourceRegistrar 以添加新方法 data
<?php
namespace App\MyCustom\Routing;
use Illuminate\Routing\ResourceRegistrar as OriginalRegistrar;
class ResourceRegistrar extends OriginalRegistrar
// add data to the array
/**
* The default actions for a resourceful controller.
*
* @var array
*/
protected $resourceDefaults = ['index', 'create', 'store', 'show', 'edit', 'update', 'destroy', 'data'];
/**
* Add the data method for a resourceful route.
*
* @param string $name
* @param string $base
* @param string $controller
* @param array $options
* @return \Illuminate\Routing\Route
*/
protected function addResourceData($name, $base, $controller, $options)
$uri = $this->getResourceUri($name).'/data.json';
$action = $this->getResourceAction($name, $controller, 'data', $options);
return $this->router->post($uri, $action);
之后,创建新的 ServiceProvider 或改用 AppServiceProvider。
在方法boot中,添加以下代码:
public function boot()
$registrar = new \App\MyCustom\Routing\ResourceRegistrar($this->app['router']);
$this->app->bind('Illuminate\Routing\ResourceRegistrar', function () use ($registrar)
return $registrar;
);
然后:
添加到您的路线:
Route::resource('test', 'TestController');
检查php artisan route:list
你会发现新方法'data'
【讨论】:
您的解决方案适用于我。您能告诉我您在使用此代码几个月后是否发现任何问题吗? 谢谢@RicardoVigatti。我从 laravel 5.2 开始使用它,现在我在最近的 L5.3 项目中使用它并且没有问题。如果你有,请告诉我,也许我可以帮助你.. 很好,我在我的 5.0 项目中实现了这个。解决方案似乎非常一致,但是,如果有任何问题发生,将在几周后。 @MokhamadRofi'udin 我已经实现了你的解决方案,新路由已添加到路由列表中,但似乎没有添加相应的方法。我错过了什么吗? @Siavosh 只需在控制器中编写您的方法,即我添加方法 data() :` public function data(Request $request) `【参考方案6】:只需添加一个新方法和该方法的路由。
在您的控制器中:
public function foo($bar=“default”)
//do stuff
在你的网络路由中
Route::get(“foo/$bar”, “MyController@foo”);
只要确保控制器中的方法是公开的。
【讨论】:
【参考方案7】:使用 Laravel >5 在 routes 文件夹中找到 web.php 文件添加你的方法
您可以使用 route::resource 在您的控制器中将所有这些方法的索引、显示、存储、更新、销毁在一行中路由
Route::get('foo/bar', 'NameController@bar');
Route::resource('foo', 'NameController');
【讨论】:
【参考方案8】:之前我将路线定义为:
Route::get('foo/bar', 'FooController@bar');
Route::resource('foo', 'FooController');
它给出了错误:
路由 foo.bar 未定义
然后在谷歌搜索后,我添加了名称
Route::get('foo/bar', 'FooController@bar')->name('foo.bar');
而且效果很好。
【讨论】:
【参考方案9】:我解决了
创建一个扩展BaseRouter
的自定义路由器文件
// src/app/Custom/Router.php
<?php
namespace App\Custom;
use Illuminate\Routing\Router as BaseRouter;
use Illuminate\Support\Str;
class Router extends BaseRouter
public function customResource($name, $controller, array $options = [])
$model = Str::singular($name); // this is optional, i need it for Route Model Binding
$this
->get( // set the http methods
$name .'/' . $model . '/audit',
$controller . '@audit'
)->name($name . '.audit');
return $this->resource($name, $controller, $options);
然后在src/bootstrap/app.php
注册
$app->singleton('router', function ($app)
return new \App\Custom\Router($app['events'], $app);
);
并在 /routes/web.php 上使用它
Route::customResource(
'entries',
'EntryController'
);
【讨论】:
以上是关于在 Laravel 中为资源控制器添加新方法的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Laravel 5.6 中向资源控制器添加自定义方法
向 laravel 中的资源 json 响应添加状态和消息键