Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should I re-use controllers in laravel between admin & api ? or have my admin consume my API?

New to laravel and trying to work out the best way to structure my app.

It has both an admin interface and an API (JSON, angularjs front-end).

my routes currently look like:

Route::group(array('prefix' => 'admin', 'before' => 'auth.admin'), function()
{
    Route::any('/', array('as' => 'admin.index', function() {
        return View::make('admin.index');
    }));

    Route::resource('countries.products', 'ProductsController');

    Route::resource('countries', 'CountriesController');

    Route::resource('orders', 'OrdersController');

});

// Route group for API versioning
Route::group(array('prefix' => 'api/v1'), function()
{
    Route::resource('products', 'APIProductsController', array('only' => array('index', 'show')));

    Route::resource('orders', 'APIOrdersController', array('only' => array('store', 'update')));

});

There is a lot of duplicated logic in eg, the OrdersController & APIOrdersController. Should I re-use a single controller somehow, maybe with content-negotation? or is it better to modify OrdersController to query the API routes instead of using eloquent?

or is there another, better way?

like image 897
Jacob Dorman Avatar asked Oct 02 '22 01:10

Jacob Dorman


1 Answers

As I see it, I would extract all object creation logic to a proper class (sounds like a good case for a repository). This class should only know about the parameters it has to receive, and respond accordingly. For example:

class EloquentOrder implements OrderRepositoryInterface {

    // Instance of OrderValidator, 
    // assuming we have one
    protected $validator; 

    public function create($params)
    {
        // Pseudo-code
        $this->validator = new Ordervalidator($params);
        if ($this->validator->passes())
            create and return new Order
        else
            return validator errors
    }

}

Then, each of your modules can use this functionality inside its controllers.

In your API, you could have this:

class APIOrderController extends APIController {

    protected $repository;

    public function __construct(OrderRepositoryInterface $repository)
    {
        $this->repository = $repository;
    }

    public function create()
    {
        // Let's imagine you have an APIAuth class which 
        // authenticates via auth tokens:
        if (APIAuth::check()) {
            $params = Input::all();
            return $this->repository->new($params);
        }

        return Response::json(['error' => 'You are not authorized to create orders'], 401);
    }

}

While in your administration module, you could have:

class AdminOrderController extends AdminController {

    protected $repository;

    public function __construct(OrderRepositoryInterface $repository)
    {
        $this->repository = $repository;
    }

    public function create()
    {
        // Now, let's imagine Auth uses a different authentication
        // method, and can check for specific permissions
        if (Auth::check() && Auth::hasPermission('create.orders')) {
            $params = Input::all();
            return $this->repository->new($params);
        }

        return Redirect::home()->with('message', 'You are not authorized to create orders');
    }

}

As you can see, this allows you to reuse your object creation logic in different contexts. In the example I've used different authentication methods and responses just to show flexibility, but this will really depend on your project requirements.

like image 127
Manuel Pedrera Avatar answered Oct 19 '22 04:10

Manuel Pedrera