Reputation: 1753
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?
Upvotes: 174
Views: 134760
Reputation: 1
I just add a new method called (files) and works !!!
Route::get('sections/{section}/files', [SectionController::class,'files'])->name('sections.files'); Route::resource('sections',SectionController::class)->names('sections');
Upvotes: 0
Reputation: 11359
I'm new to Laravel, but as of Laravel 10, I was able to group resource and custom route all together like that. And you can add as many custom route as you would like into that group.
Route::controller(FooController::class)->group(function () {
Route::resource('foos', FooController::class);
// The route to add
Route::get('yourroute/{foo}', 'test')->name('foos.test');
})->middleware(['auth', 'verified']);
If you run artisan route:list you can validate it is working as expected.
Upvotes: 1
Reputation: 366
you can add your macros, in my case it looks like this.
use Illuminate\Routing\Router;
Router::macro('crudResource', function ($name, $controller, array $options = []) {
$only = ['index', 'show', 'store', 'update', 'destroy', 'restore'];
if (isset($options['except'])) {
$only = array_diff($only, (array)$options['except']);
}
if (in_array('restore', $only)) {
$this->put($name . '/restore/{' . ($model = Str::singular($name)) . '}', [$controller, 'restore'])
->name($name . '.restore')
->can('delete', $model)
->withTrashed();
}
return $this->resource($name, $controller, array_merge([
'only' => $only,
], $options))
->withTrashed(['index', 'show']);
});
Route::crudResource('initial_balance_banks', InitialBalanceBankController::class);
Route::crudResource('bank_movements', BankMovementController::class)->except('restore');
Route::crudResource('outcoming_bank_orders', OutcomingBankOrderController::class, ['except' => ['restore']]);
Upvotes: 0
Reputation:
As of Laravel 9 this appears to have been made much simpler. The following works fine, even if you add the new method after the Resource controller was created.
Route::get('/foo/bar', [FooController::class, 'bar']);
Route::resource('/foo', FooController::class);
Just be sure to include the new method on top, as the remaining /foo/[any] namespace will be reserved for the Resource controller on that line. As is the convention for Laravel routes.
Upvotes: 1
Reputation: 21
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'
);
Upvotes: 2
Reputation: 41
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.
Upvotes: 3
Reputation: 1361
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');
Upvotes: 3
Reputation: 1722
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.
Upvotes: 1
Reputation: 559
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'
Upvotes: 42
Reputation: 4557
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.
Upvotes: -3
Reputation: 694
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
Upvotes: 16
Reputation: 220136
Just add a route to that method separately, before you register the resource:
Route::get('foo/bar', 'FooController@bar');
Route::resource('foo', 'FooController');
Upvotes: 337
Reputation: 87789
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
:
Those are my source files:
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');
}
}
Upvotes: 35