问题
I'm doing what I want in a certain way and I'm looking for alternatives or better ways of doing. I'm using Resource Controllers in my application. Also I'm using softdelete in several models, so my routes are as follows:
Route::get('users/deleted', array('uses' => 'UserController@trash'));
Route::put('users/{id}/restore', array('uses' => 'UserController@restore'));
Route::resource('users', 'UserController');
The first route is to display objects that have been deleted. The second allows me to restore these deleted elements. The third maps the traditional methods (create, edit, update, etc.).
I have several controllers that work exactly the same way, I wonder if have any way to tell laravel to work with this two methods (trash and delete) by default without the two extra lines.
Is it possible? Or to give a better way that I'm doing? (sorry for bad english)
回答1:
Keeping things simple and DRY.
You can extend the Router and replace the Route Facade in your app/config/app.php
file but seems like a lot of work for not much gain, but don't forget that your routes file is a PHP script and you can do things like:
$routes = [
['users' => 'UserController'],
['posts' => 'PostController'],
];
foreach ($routes as $key => $controller)
{
Route::get("$key/deleted", array('uses' => "$controller@trash"));
Route::put("$key/{id}/restore", array('uses' => "$controller@restore"));
Route::resource($key, $controller);
}
Extending the router
To extend the router you need to create 3 classes:
The Router extended, where you'll add your new methods:
<?php namespace App\Routing;
class ExtendedRouter extends \Illuminate\Routing\Router {
protected $resourceDefaults = array(
'index',
'create',
'store',
'show',
'edit',
'update',
'destroy',
'deleted',
'restore',
);
protected function addResourceDeleted($name, $base, $controller)
{
$uri = $this->getResourceUri($name).'/deleted';
return $this->get($uri, $this->getResourceAction($name, $controller, 'deleted'));
}
protected function addResourceRestore($name, $base, $controller)
{
$uri = $this->getResourceUri($name).'/{resource}/restore';
return $this->get($uri, $this->getResourceAction($name, $controller, 'restore'));
}
}
A Service Provider, to boot your new router, using the same IoC identifier Laravel uses ('router'):
<?php namespace App\Routing;
use Illuminate\Support\ServiceProvider;
class ExtendedRouterServiceProvider extends ServiceProvider {
protected $defer = true;
public function register()
{
$this->app['router'] = $this->app->share(function() { return new ExtendedRouter($this->app); });
}
public function provides()
{
return array('router');
}
}
And a Facade, to replace Laravel's one
<?php namespace App\Facades;
use Illuminate\Support\Facades\Facade as IlluminateFacade;
class ExtendedRouteFacade extends IlluminateFacade {
public static function is($name)
{
return static::$app['router']->currentRouteNamed($name);
}
public static function uses($action)
{
return static::$app['router']->currentRouteUses($action);
}
protected static function getFacadeAccessor() { return 'router'; }
}
Then you need to add your Service Provider and Facade to your app/config/app.php
file, commenting the Laravel original ones.
回答2:
Im using route model bind.
I do this way.
<?php
namespace App\Http\Router;
use Illuminate\Support\Facades\Route;
use Illuminate\Routing\Router;
class CustomRouter extends Router
{
public function customResource($routeName, $controllerPath, $routeBindName = null, $routeBindModel = null) {
$routeBindName = $routeBindName ?? $routeName;
$routeBindNameTrashed = "{$routeBindName}_trashed";
if($routeBindModel && $routeBindName) {
Route::model($routeBindName, $routeBindModel);
Route::bind($routeBindNameTrashed, function($modelId) use ($routeBindModel) {
return app($routeBindModel)->newQuery()->onlyTrashed()->findOrFail($modelId);
});
}
Route::put("$routeName/{{$routeBindNameTrashed}}/restore", "{$controllerPath}@restore")->name("{$routeName}.restore");
Route::delete("$routeName/{{$routeBindNameTrashed}}/force", "{$controllerPath}@forceDelete")->name("{$routeName}.force-delete");
Route::resource($routeName, $controllerPath);
}
}
Alter bootstrap/app.php
$app->singleton(
'router',
App\Http\Router\CustomRouter::class
);
Then usage:
Route::customResource('projects', 'ProjectsController', 'project', \App\Models\Project::class);
Route:list
回答3:
Works like a charm
$routes = [
'posts' => 'PostController',
'posts.comments' => 'PostCommentController',
];
foreach ($routes as $key => $controller)
{
Route::get("$key/deleted", array('uses' => "$controller@trash"));
Route::put("$key/{id}/restore", array('uses' => "$controller@restore"));
Route::resource($key, $controller);
}
来源:https://stackoverflow.com/questions/22559810/extend-resource-controllers