在Laravel中向资源控制器添加新方法


141

我想知道是否有可能在Laravel中向资源控制器添加新方法,以及如何实现。

我知道这些方法是默认方法(索引,创建,存储,编辑,更新,销毁)。现在,我想向同一控制器添加其他方法和路由。

那可能吗?

Answers:


261

注册资源之前,只需分别向该方法添加路由:

Route::get('foo/bar', 'FooController@bar');
Route::resource('foo', 'FooController');

7
请注意,您的新方法必须高于此方法,::resource否则您将收到错误消息“没有模型的查询结果”。
mpen 2014年

您将如何传递{id}之类的参数?目前,我已经在route.php中内联编码了自定义方法(如此处的示例 laravel.com/docs/5.1/routing#route-parameters)。理想情况下,我想传递参数以在FooController中运行。
ATutorMe 2016年

1
发现了问题-不在Route语法中。实际上是我正在使用的某些自定义中间件中!路线:: get('foo / {id} / bar','FooController @ bar'); 会将id传递给bar($ id)方法。谢谢!
ATutorMe 2016年

有人可以解释为什么自定义路由应该超出资源路由吗?我已经进行了一些测试,放在上方还是下方之间似乎没有
区别

3
@RicardoVigatti-资源注册此路由:Route::get('foo/{id}', ...)。这会吞噬所有以开头foo并具有另外一段的路线,包括foo/bar
约瑟夫·西尔伯

32

我只是这样做,添加了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');
    }

}

3
您能为Laravel 5及更高版本提供相同的功能吗?我一直在尝试重现这一点...但是我似乎找不到他们在容器中注册“ route”访问器的位置。
TipuZaynSultan's

为什么文件的扩展名为.pas?
Thiago Dias

22

是的,可能

在我的情况下,我添加了method:data来处理HTTP POST方法中对/data.json的请求。

这就是我所做的。

首先,我们扩展Illuminate \ Routing \ ResourceRegistrar以添加新的方法数据

<?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

在方法启动中,添加以下代码:

    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 您会发现新方法“数据”


您的解决方案对我有用。.能告诉我使用此代码几个月后是否发现任何问题?
里卡多·维加蒂

谢谢@RicardoVigatti。我从laravel 5.2开始使用它,现在在最近的L5.3项目中使用了它,并且没有问题。让我知道,如果你有一个,可能是我可以帮你..
Mokhamad Rofi'udin

很好,我正在5.0项目中实现此功能。解决方案似乎非常一致,但是,如果出现任何问题,将在几周后解决。
里卡多·维加蒂

@ MokhamadRofi'udin我已经实现了您的解决方案,新的路由已添加到路由列表中,但似乎未添加相应的方法。我想念什么吗?
Siavosh

@Siavosh只是在控制器中编写您的方法,即我添加了方法data():`public function data(Request $ request){}`
Mokhamad Rofi'udin

13
Route::resource('foo', 'FooController');
Route::controller('foo', 'FooController');

尝试一下。给您额外的方法,例如getData()等。。这对我来说可以保持route.php干净


是的,这可行。Laravel 5.1文档并没有提到Route :: resource和Route :: controller可以一起使用,而是提到了补充资源控制器。所以这很困惑。但是您的事实证明,它们可以一起使用
Amir 2015年

对不起,哈桑·贾马尔(Hassan Jamal),这两个人没有一起工作。因此,如果我仅使用Route :: resource
Amir 2015年

3

使用Laravel> 5在routes文件夹中找到web.php文件,添加您的方法

您可以使用route :: resource路由所有这些方法,在一行中索引,显示,存储,更新,销毁控制器中的所有方法

Route::get('foo/bar', 'NameController@bar');
Route::resource('foo', 'NameController');

1

只需添加一个新方法和该方法的路由。

在您的控制器中:

public function foo($bar=“default”)
{
      //do stuff
}

并在您的网络路线中

Route::get(“foo/{$bar}”, MyController@foo”);

只要确保控制器中的方法是公共的即可。


-1

这也很好。无需添加更多路由,只需使用资源控制器的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(){}

我使用默认设置来抛出自定义错误页面。


2
感觉就像是真正的代码气味。我不想让我的控制器处理多个动作。
罗尼·诺克斯维尔,
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.