Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Extend Resource Controllers

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)

like image 933
Luís Henrique Faria Avatar asked Dec 19 '22 16:12

Luís Henrique Faria


1 Answers

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.

like image 189
Antonio Carlos Ribeiro Avatar answered Apr 03 '23 05:04

Antonio Carlos Ribeiro