I would like to know if there is a possibility in Laravel 4 to actually call function of controller based on parameter given. For example if I have route like :
'auth/{action}
then is there a way to call controller action based on 'action' param ? In Kohana I could write something like:
'auth/<action>' -> defaults (controller=>'UserController',action=>'<action>'
Well not exacly like that but you know what I mean :) Anyway if there is no chance to do that then do I have to split my route to single routes ?
Sounds like you just need to route to the controller with auth being the base URI.
Route::controller('auth', 'AuthController');
This controller (AuthController) now expects your methods to be prefixed with the HTTP verb they should respond to. You can also use the getIndex method to respond to the base URI, which in this case is auth.
An example controller might look something like this:
class AuthController extends Controller {
public function getIndex()
{
return 'Index page'; // Responds to localhost/auth
}
public function getLogin()
{
return 'Login page'; // Responds to localhost/auth/login
}
}
There is one thing you should be aware of. If you do Route::controller('/', 'HomeController'); then it should be LAST. Any routes after it will not get called because of Laravel automatically adding a "missing method" route that will catch anything that isn't matched by a routable method on the controller.
More on RESTful controllers at the official documentation.
I haven't tested this exact code, but I used something similar and it worked:
Route::any('auth/{action}', function($action){
$controller = new UserController();
$controller->$action();
});
You might find you also need to handle parameters, like this:
Route::any('auth/{action}/{param}', function($action, $param){
$controller = new UserController();
$controller->$action($param);
});
You could even tweak it to cover all your controllers:
Route::any('{controller}/{action?}/{param?}', function($controller,$action='index',$param=null)
{
$controller = str_replace(' ', '', ucwords(str_replace('-', ' ', $controller))).'Controller';
$controller = new $controller;
$action = lcfirst(str_replace(' ', '', ucwords(str_replace('-', ' ', $action))));
return $controller->$action($param);
});
If you wanted to have an index action with a parameter, that wouldn't work, but otherwise, it seems to work well enough. It's also not going to handle a second parameter, if you were wanting to do that.
Lots of ways you could extend this idea.
Jason's answer is more correct, (matches the docs, cleaner code, etc.) but if you didn't want to think about HTTP methods, or you wanted a sort of master route to handle nearly every request, this is an option.
Related
I have seen/worked on lot of projects where a Laravel POST route looking like this:
Route::post('/some-url', [SomeController::class, 'someMethod']);
And the controller with its method which takes care of the route looking like this:
class SomeController extends Controller
{
public function someMethod(Request $request) {
// My Logic to do something with the post data - $request
return redirect("/some-other-url");
}
}
have always redirected to a specific URL after doing something with the POST data, by convention.
I would like to know, if after processing a POST request, if it's okay to just return a view like what we do with GET requests? I know it works, but is it just convention or are there any issues in doing so?
Eg:
class SomeController extends Controller
{
public function someMethod(Request $request) {
// My Logic to do something with the post data - $request
return view("somebladeview")->with(["result" => $result ]);
}
}
The pattern is called post-redirect-get, or PRG. It is convention because POST should be used for requests that change data, whereas GET should be used to simply display data.
If you return a view after a POST, the user can hit reload, and (probably unintentionally) change data again, eg buy something a second time. By using PRG, the user hitting reload simply reloads the last GET, which just re-displays something.
NOTE: There is some advice in the comments on your question to ignore this convention. I think that is unwise and dangerous, these conventions exist for good reasons.
May I know how can I make just a single route so I don't have to repeat it? Thanks in advance.
Route::get('/url', 'CtcFormController#index' )->name('CtcForm.ch');
Route::post('/url/submit', 'CtcFormController#submit')->name('CtcForm.submit');
Route::view('/url/submitted', 'form.submit')->name('CtcForm.submit');
Route::get('/url2','CtcFormController#store')->name('CtcForm.eng');
Route::post('/url2/submit', 'CtcFormController#submit')->name('CtcForm.submit');
Route::view('/url2/submitted', 'form.submit')->name('CtcForm.submit');
As per your given example, you want to handle the variable part of the route which is /url/ and /url12/. Yes! you can handle there both different route using a single route in ways:
Use route variable to handle dynamic url values i.e. url, url2,url3...url12 and so on.
Route::get('/{url}', 'CtcFormController#index' )->name('CtcForm.ch');
Route::post('/{url}/submit', 'CtcFormController#submit')->name('CtcForm.submit');
Route::view('/{url}/submitted', 'form.submit')->name('CtcForm.submit');
Now in your controller methods handing above routes receive extra parameter $url like:
In controller CtcFormController.php class:
public function index(Request $request, string $url) {
//$url will gives you value from which url request is submitted i.e. url or url12
//method logic goes here ...
}
Similarly, method handling /{url}/submit route will be like:
public function submit(Request $request, string $url) {
//method logic goes here ...
}
Let me know if you have any further query regarding this or you face any issue while implementing it.
I am new to Laravel so am uncertain of the notation. The Laravel documentation shows you can pass a parameter this way:
Route::get('user/{id}', function ($id) {
return 'User '.$id;
});
Which is very intuitive. Here is some existing coding in a project I'm undertaking, found in routes.php:
Route::get('geolocate', 'Api\CountriesController#geolocate');
# which of course will call geolocate() in that class
And here is the code I want to pass a variable to:
Route::get('feed/{identifier}', 'Api\FeedController#feed');
The question being, how do I pass $identifier to the class as:
feed($identifier)
Thanks!
Also one further sequitir question from this, how would I notate {identifier} so that it is optional, i.e. simply /feed/ would match this route?
You should first create a link which looks like:
/feed/123
Then, in your controller the method would look like this:
feed($identifier)
{
// Do something with $identifier
}
Laravel is smart enough to map router parameters to controller method arguments, which is nice!
Alternatively, you could use the Request object to return the identifier value like this:
feed()
{
Request::get('identifier');
}
Both methods have their merits, I'd personally use the first example for grabbing one or two router parameters and the second example for when I need to do more complicated things.
So basically, I have a setup of restful controller in my route. Now my problem is how can I call the Index page if there is a parameter.. it gives me an error of Controller not found
Im trying to call it like this www.domain.com/sign-up/asdasdasd
Route::controller('sign-up','UserRegisterController');
then in my Controller
class UserRegisterController extends \BaseController {
protected $layout = 'layouts.unregistered';
public function getIndex( $unique_code = null )
{
$title = 'Register';
$this->layout->content = View::make( 'pages.unregistred.sign-up', compact('title', 'affiliate_ash'));
}
By registering:
Route::controller('sign-up','UserRegisterController');
You're telling the routes that every time the url starts with /sign-up/ it should look for corresponding action in UserRegisterController in verbAction convention.
Suppose you have:
http://domain.com/sign-up/social-signup
Logically it'll be mapped to UserRegister#getSocialSignup (GET verb because it is a GET request). And if there is nothing after /sign-up/ it'll look for getIndex() by default.
Now, consider your example:
http://domain.com/sign-up/asdasdasd
By the same logic, it'll try looking for UserRegister#getAsdasdasd which most likely you don't have. The problem here is there is no way of telling Route that asdasdasd is actually a parameter. At least, not with a single Route definition.
You'll have to define another route, perhaps after your Route::controller
Route::controller('sign-up','UserRegisterController');
// If above fail to find correct controller method, check the next line.
Route::get('sign-up/{param}', 'UserRegisterController#getIndex');
You need to define the parameter in the route Route::controller('sign-up/{unique_code?}','UserRegisterController');. The question mark makes it optional.
Full documentation here: http://laravel.com/docs/routing#route-parameters
In Laravel 3, you could call a controller using the Controller::call method, like so:
Controller::call('api.items#index', $params);
I looked through the Controller class in L4 and found this method which seems to replace the older method: callAction(). Though it isn't a static method and I couldn't get it to work. Probably not the right way to do it?
How can I do this in Laravel 4?
You may use IoC.
Try this:
App::make($controller)->{$action}();
Eg:
App::make('HomeController')->getIndex();
and you may also give params:
App::make('HomeController')->getIndex($params);
If I understand right, you are trying to build an API-centric application and want to access the API internally in your web application to avoid making an additional HTTP request (e.g. with cURL). Is that correct?
You could do the following:
$request = Request::create('api/items', 'GET', $params);
return Route::dispatch($request)->getContent();
Notice that, instead of specifying the controller#method destination, you'll need to use the uri route that you'd normally use to access the API externally.
Even better, you can now specify the HTTP verb the request should respond to.
Like Neto said you can user:
App::make('HomeController')->getIndex($params);
But to send for instance a POST with extra data you could use "merge" method before:
$input = array('extra_field1' => 'value1', 'extra_field2' => 'value2');
Input::merge($input);
return App:make('HomeController')->someMethodInController();
It works for me!
bye
This is not the best way, but you can create a function to do that:
function call($controller, $action, $parameters = array())
{
$app = app();
$controller = $app->make($controller);
return $controller->callAction($app, $app['router'], $action, $parameters);
}
Route::get('/test', function($var = null) use ($params)
{
return call('TestController', 'index', array($params));
});
Laurent's solution works (though you need a leading / and the $params you pass to Request::create are GET params, and not those handled by Laravel (gotta put them after api/items/ in the example).
I can't believe there isn't an easier way to do this though (not that it's hard, but it looks kinda hackish to me). Basically, Laravel 4 doesn't provide an easy way to map a route to a controller using a callback function? Seriously? This is the most common thing in the world...
I had to do this on one of my projects:
Route::controller('players', 'PlayerController');
Route::get('player/{id}{rest?}', function($id)
{
$request = Request::create('/players/view/' . $id, 'GET');
return Route::dispatch($request)->getContent();
})
->where('id', '\d+');
Hope I'm missing something obvious.
$request = Request::create('common_slider', 'GET', $parameters);
return Controller::getRouter()->dispatch($request)->getContent();
For laravel 5.1
It's an Old question. But maybe is usefull. Is there another way.
In your controller: You can declare the function as public static
public static function functioNAME(params)
{
....
}
And then in the Routes file or in the View:
ControllerClassName::functionNAME(params);