Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Proposal] Route parameter injection into controller constructor instead of controller methods #1025

Closed
twarlop opened this issue Apr 21, 2013 · 3 comments

Comments

Projects
None yet
4 participants
@twarlop
Copy link
Contributor

commented Apr 21, 2013

Either i'm missing something or something similar is not possible:

example routes:
domain.com/clientApp/client1
domain.com/clientApp/client2
domain.com/clientApp/client1/contact
domain.com/clientApp/client1/products/007

the goal:
to avoid the need to specify my first parameter in every action-method in all my controllers and allowing the constructor to prepare stuff needed on every request within the clientApp routes. This implementation would seem the most clean one to me, but there is an alternative at the bottom.

Clean:

example route defintions

Route::bind('ClientApp', function($value, $route){
    return ClientApp::where('name', $value)->first();
});

/**
 * Note the {{ClientApp}} notation:
 * my suggestion to make this parameter (or bound model) 
 * to be injected into the controller constructor instead of being passed to action
 * methods as the first parameter
 */
Route::group(array('prefix' => 'clientApp/{{ClientApp}}'), function(){
    Route::controller('products','ClientApp\ProductsController');
    Route::controller('','ClientApp\HomeController');
});

example controller

namespace ClientApp;
use BaseController as Controller;

/**
 * ClientApp BaseController
 */
class BaseController extends Controller
{

    protected $app;

    public function __construct(ClientApp $app){
            parent::__construct();
            $this->app = $app;
            //do a bunch of stuff like setting layout files depending on the $app,
            //or loading correct modules specific to the $app

    }
}


namespace ClientApp;
/**
* ClientApp HomeController
*/
class HomeController extends BaseController
{

    public function getIndex(){

    }

    public function getContact(){

    }
}

namespace ClientApp;
/**
 * ClientApp ProductsController
 */
class ProductsController extends BaseController
{

    public function getIndex($productList){

    }
}

Alternative: half solution

allow for routes to match a pattern without injecting the pattern as a parameter into controller action methods.

Route::group(array('prefix' => 'clientApp/:ClientApp:'), function(){
    Route::controller('products', 'ClientApp\ProductsController');
    Route::controller('','ClientApp\HomeController');
});

This would be the same as a regular {parameter}, but simply not pass it to the controller methods, again {{parameter}} could be used instead of :parameter: as suggested in my first solution.

now i could use IoC dependency injection manually to do layout and other logics in my controller constructor.

Currently this is what is possible:

/*
 * BaseController
 */
namespace ClientApp;
use Request;
use BaseController as Controller;

class BaseController extends Controller{
    /**
     * Use dependency injection and manally search for parameter
     */
    public function __construct(ClientApp $app){
        $this->app = $app->where('name', Request::segment(2))->first();
        $this->setup();
        parent::__construct();
    }

    // OR        

    /**
     * Helper init function that uses first parameter from every action-method
     */
    protected function _init($firstParameter){
        $this->app =  $firstParameter //was bound using Route::bind('ClientApp', closure returning model based on name)
        $this->setup();
    }

    protected function setup(){
        //setup layout for this clientApp
        //load user data for this clientApp
    }


}

/*
 * HomeController
 */
namespace ClientApp;

class HomeController extends BaseController{

    public function getIndex($firstParameter){ //shouldn't need to pass this to the method

        $this->_init($firstParameter); //should only be used when init implementation used

        //action specifics
    }

    public function getContact($firstParameter){ //shouldn't need to pass this to the method

        $this->_init($firstParameter); //should only be used when init implementation used

        //action specifics
    }

}


/*
 * ProductsController
 */
namespace ClientApp;

class ProductsController extends BaseController{

    public function getIndex($firstParameter, $productList){ //should only need $productList

        $this->_init($firstParameter); //should only be used when init implementation used

        //action specifics
        $products = Product::where('listid', $productList)->where('clientAppId', $this->app->id);

        //etc...
    }

}

The thought of needing to repeat my parameter in every action, and call that same _init() helper method in every action makes me shiver.

I'm sorry if this doesn't make any sense, i've tried my best to keep things clean and simple. Feel free to ask more info if my intentions would be unclear.
This feature would, as i see it, allow for even more complex routes while keeping things DRY.

Regards,

Thomas

@taylorotwell

This comment has been minimized.

Copy link
Member

commented Apr 21, 2013

You would probably need to intercept the building of the controller in the IoC container in combination with overriding a method in the base controller to do this. I think it's a little beyond the scope of what should be done out of the box. Might be better suited as forum question.

@asim42

This comment has been minimized.

Copy link

commented Aug 16, 2015

Found this issue while Googling for the very same thing. It should be implemented in Laravel.

@markwinters

This comment has been minimized.

Copy link

commented Jul 26, 2016

I have the same issue and was looking for this solution. Bad that Laravel does not support this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.