ChatGPT解决这个技术问题 Extra ChatGPT

Add new methods to a resource controller in Laravel

I want to know if it is possible to add new methods to a resource controller in Laravel and how you do it.

I know that these methods are the default (index, create, store, edit, update, destroy). Now I want to add additional methods and routes to the same controller.

Is that possible?


J
Joseph Silber

Just add a route to that method separately, before you register the resource:

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

Note that your new methods have to go above the ::resource otherwise you get an error message, "No query results for model".
How would you pass a parameter like {id}? Currently I've coded my custom method inline in routes.php (like the example here laravel.com/docs/5.1/routing#route-parameters). Ideally I'd like to pass the parameter to run in FooController.
Found the problem - wasn't in the Route syntax. Was actually in some custom Middleware that I'm using! Route::get('foo/{id}/bar', 'FooController@bar'); will pass the id to bar($id) method. Thanks!
Can someone explain why the custom route should go above the resource route ??? I've done some tests and seems to have no diference between putting above or below...
@RicardoVigatti - The resource registers this route: Route::get('foo/{id}', ...). This swallows all routes starting with foo and having one additional segments, including foo/bar.
M
Mathieu Ferre

Yeah, It's possible..

In my case I add method : data to handle request for /data.json in HTTP POST method.

This what I did.

First we extends Illuminate\Routing\ResourceRegistrar to add new method 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);
    }
}

After that, make your new ServiceProvider or use AppServiceProvider instead.

In method boot, add this code :

    public function boot()
    {
        $registrar = new \App\MyCustom\Routing\ResourceRegistrar($this->app['router']);

        $this->app->bind('Illuminate\Routing\ResourceRegistrar', function () use ($registrar) {
            return $registrar;
        });
    }

then :

add to your route :

Route::resource('test', 'TestController');

Check by php artisan route:list And you will find new method 'data'


Your solution works for me.. Can you tell me if you discovered any issue after some months using this code?
Thanks @RicardoVigatti. I used this since laravel 5.2 and now I use this in my recent project with L5.3 and have no issue with it. Let me know if you have one, may be I can help you..
nice, i'm implementing this in my 5.0 project. The solution seems very consistent, but, if any issue come to pass, it will be after some weeks.
@MokhamadRofi'udin I've implemented your solution, the new route is added to the route list but it seems that the corresponding method is not added. Am I missing something ?
@Siavosh just write your method in controller i.e. I add method data() : ` public function data(Request $request) { }`
A
Antonio Carlos Ribeiro

I just did that, to add a GET "delete" method.

After creating your files, you just need to add

'AntonioRibeiro\Routing\ExtendedRouterServiceProvider',

to 'providers' in your app/config.php

Edit the Route alias in this same file:

'Route'           => 'Illuminate\Support\Facades\Route',

changing it to

'Route'           => 'AntonioRibeiro\Facades\ExtendedRouteFacade',

And make sure those files are being autoloaded, they must be in some directory that you have in your composer.json ("autoload" section).

Then you just need to:

Route::resource('users', 'UsersController');

And this (look at the last line) is the result if you run php artisan routes:

https://i.stack.imgur.com/GIvs8.png

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');
    }

}

Can you please provide the same for Laravel 5 and Above? I have been trying to reproduce this... But I can't seem to find where they are registering the 'route' Accessor in the container.
why the file has the extension .pas?
Make sense but provider part seems to not work with laravel 8.0.
Overcomplicated sadly
H
Hassan Jamal
Route::resource('foo', 'FooController');
Route::controller('foo', 'FooController');

Give this a try .Put you extra methods like getData() etc etc .. This worked for me to keep route.php clean


Yas this works . Laravel 5.1 Documentation did't mention that Route::resource and Route::controller can be used together rather they mentioned about Supplementing Resource Controllers. So this is confused. But your ans proved that these are can be used together
I am sorry Hassan jamal, these two are not working together. So now how can I set a custom post method in a controller if I use only Route::resource
M
Mazen Embaby

Using Laravel >5 Find the web.php file in routes folder add your methods

You can use route::resource to route all these methods index, show, store, update, destroy in your controller in one line

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

D
David Buck

Previously I defined my route as:

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

It gave the error:

route foo.bar is not defined

And then after some Googling I added name

Route::get('foo/bar', 'FooController@bar')->name('foo.bar');

And it worked fine.


P
Patrick Lumenus

Just add a new method and a route to that method.

In your controller:

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

And in your web routes

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

Just be sure the method in the controller is public.


D
Dev Lim

I solve by

Create a custom router file that extends the 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);
    }
}

Then register at src/bootstrap/app.php

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

And use it on /routes/web.php

Route::customResource(
    'entries',
    'EntryController'
);

m
mdamia

This works pretty good too. No need to add more routes just use show method of the resource controller like this :

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(){}

I use the default to throw custom error page.


This feels like a real code smell. I wouldnt want my controllers handling multiple actions.
Isn't this breaking the REST concept?
There is no need to do such thing!!! That's why we have routes in the first place. The routing logic can not be placed on the controllers.

关注公众号,不定期副业成功案例分享
Follow WeChat

Success story sharing

Want to stay one step ahead of the latest teleworks?

Subscribe Now