What does the 'uses' keyword mean in regards to laravel routing? - php

I'm new to laravel and trying my best to RTM but having difficulty understanding a few things. I think there is an expected level on context that I am not aware of when it comes to routing. In reviewing the documentation for routing I see that the uses keyword allows one to Attach(ing) A Filter To A Controller Action, but what does that mean? I have an existing site that is using the uses keyword but I am at a loss at to what it is actually doing. Can someone explain (a tab more thoroughly than the laravel documentation does) and show a very simple example what this actually does?

The keyword uses of routing is where you define which action (controller method or anonymous function) will be used to process that particular route. Take this controller method example:
Route::get('user', array('uses' => 'UserController#showProfile'));
It says that uses will call the method showProfile in your UserController class, this would be the class:
class UserController extends Controller {
public function showProfile
{
return "Hi! I'm the showProfile method!";
}
}
So, if you hit the
http://localhost/user
You should see the message
Hi! I'm the showProfile method!
Because your route execute that action you defined in the uses.
An anonymous function (closure) example would be:
Route::get('user', array('uses' => function() {
return "Hi, I'm a closure!";
}));

Antonio's answer answers your (exact) question pretty perfectly, but I figured I'd add my comments to the wider context of the question, as I feel you don't actually want to know what uses is for, but instead are generally confused by the way routing works (you mention uses is for filters, which it isn't, but its use is a side-effect of adding filter configuration). So allow me to explain:
The router methods are actually kinda simple, but you just need to know what syntax they expect. There are two main forms, the unconfigured and the configured:
Unconfigured:
// syntax:
Route::get($route, $action);
// controller method
Route::get('some/route', 'Controller#action');
// closure
Route::get('some/route', function () {
return View::make(/* etc. */);
});
But as soon as you need to add configuration to a given route (including filters, naming, etc.) you need to use a slightly different syntax:
// syntax:
Route::get($route, $config); // where $config is an array
// controller method
Route::get('some/route', array(
'as' => 'my.route.name',
'uses' => 'Controller#action',
));
// closure
Route::get('some/route', array(
'before' => 'some.filter',
'uses' => function () {
return View::make(/* etc. */);
}
));
// closure alternative
Route::get('some/route', array(
'before' => 'some.filter',
function () {
return View::make(/* etc. */);
}
));
So, as soon as you need to name your route (using as) or add a filter (using before and after) you need to turn that more simple syntax into the slightly more complex array syntax. And when you make it an array, you still need a way to tell Laravel what to actually use for the execution - that's what uses is for.

Related

Using a different controller for GET and POST in Laravel but using the same name

I am writing route and controller rules for a web application. In a number of rules, a problem has emerged, which is that I need to match both GET and POST verbs, and send them to the controller, but different methods.
I considered using Route::controller('tracking', 'TrackingController') for this, but then it requires different names for each internal route, whereas I want to specify one name for both. Besides, I've read nothing but negativity regarding the usage, suggesting that it is not a good idea.
Here's what I have currently:
Route::match(['get', 'post'], '/tracking', [
'as' => 'tracking',
'uses' => 'TrackingController#index'
]);
While implementing this, I have discovered that I need to have two controller methods, index and track. How can I efficiently route GET to index and POST to track, while maintaining the same controller (TrackingController) and the same name (tracking)?
I considered using two separate routes, e.g. Route::get and Route::post, but that doesn't feel very eloquent.
you can use easily Route Controller,like this
Route::controller('tracking', 'TrackingController')
In here if you wanna use same method for both get and post,just use any prefix in method,like
//for both get and post
public function anyUrl();
//only get
public function getUrl();
//only post
public function postUrl();
Or use
Route::any('/url', function () {
return 'Hello World';
});

Laravel sub-domain routing without passing variable to URL::route()

In a Laravel 4 app, i'm using subdomain routing around a bunch of Route::resource's like this:
Route::group(['domain' => '{account}.my.app'], function()
{
Route::group(['before' => 'auth'], function($account)
{
Route::resource('organisations', 'OrganisationsController');
Route::resource('clients', 'ClientsController');
Route::resource('domains', 'DomainsController');
});
});
In my auth filter i'm doing the following:
Route::filter('auth', function($route)
{
// you could now access $account in a controller if it was passed as an argument to the method
$account = $route->getParameter('account');
// share account variable with all views
View::share('account', $account);
// Auth::guest Returns true if the current user is not logged in (a guest).
if (Auth::guest()) return Redirect::guest('login');
});
Within my views I can now access $account, but if I want a call to URL::route() to be correct I have to manually pass the account variable, like URL::route('clients.show',['account' => $account]) otherwise it generates URLs like %7Baccount%7D.my.app.
This is a bit of a pain and doesn't seem that elegant, is there any other or better way to achieve this? I guess I could create my own route helper to use instead of the built-in one.
However, I also do redirects with Redirect::route() within controllers so I would also need to make updates here.
EDIT
As suggested in the comments it may be that extending the Route API is the best approach here. Does anyone have any suggestions how this should be done?
Thanks.

Laravel and routes with multiple "nested" tasks and parameters

I have just started tinkering with Laravel (PHP newbie alert) and I have a doubt on how to implement my REST JSON APIs on this framework.
The desired URL path should be:
http://api.mysite.com/APIKEY/FUNCTION/(ARGUMENTS)*
But what is the best way to do it?
I did not find any enough explanatory guide, because it is assumed that each feature (authentication, search, and so on) are on different routes.
At the moment I managed to create migrations and models for the needed data and I also set a route this way:
Route::get('/{apikey}/{function}/{arg1}/{arg2}/{arg3?}',
//The first two arguments are mandatory, the 3rd optional
function($apikey,$function,$arg1,$arg2)
{
return Response::json(array(
'status'=>'200'),
200);
})
->where(array('function'=>'[A-Za-z]+'));
This should be the correct action flow, but I have some doubts.
Check that apikey is valid, if not return a 404 json response. How do I call such function, where do I define it?
If key check is successful, understand which function is needed (should I use a switch construct or is there a better way to implement this, like a route group? In all examples with Route::group there is a static prefix, but here the prefix is apikey, a variable)
Return data - if available - getting it from the database. I suppose that for each function i should code a specific controller that gets data from the database using the Models.
#1. I think I'd probably use a route filter for this, like so:
Route::filter('apikey', function(){
if (Shared\API::checkIfKeyIsValid(Input::get('key') != true){
return Shared\Errors::handleError("bad-api-key");
}
});
You can see this filter checks to make sure some session variables are set and match, and if it returns ANYTHING, that's failing, and it won't send the user where the route normally goes. You'd call it in the route like so:
Route::get('play/{id}', array('before' => 'loggedin', 'uses' => 'ThingController#doThing'));
#2. I think a route group is how I'd structure this (if I understand what you're asking).
Edit: You've changed the question since I answered, regarding the prefix being a variable. I'd reorder your arguments so the API key is at the end, or you could take a look at this, which might do what you want: https://github.com/jasonlewis/enhanced-router
Route::group(array('prefix' => 'api'), function()
{
//the routes for all API calls
Route::group(array('prefix' => '/v1'), function()
{
//for version 1
Route::group(array('prefix' => '/thing', 'before' => 'loggedin'), function()
{
//for things only
Route::get('/getThing/{id}', 'APIController#getThing');
Route::get('/getDifferentThing/{id}/{aux}/{optional?}', 'APIController#getDifferentThing');
});
});
});
#3. The returning of the data should be done via your controller with the data coming from the model. Either return it as a view, or just return it as JSON like so:
return Response::json($data);

Laravel 4 RESTful API - resource controller - deeper request hierarchy

I'm building my frontend part of the API system.
Using default Resource Controller's by Laravel you can achieve this type of requests:
http://superapi.com/v1/soccer/10
Which will call the:
/app/controllers/SoccerController.php # show($id) method
I need at least one more level of depth, to be able to do it like this:
http://superapi.com/v1/soccer/player/10
So it will resolve to:
/app/controllers/SoccerController.php # show() method having both, "player" and "10" arguments.
public function show($model)
{
return Response::json(array('success' => true, 'message' => 'Test ' . $model));
}
Laravel passes only 1 parameter to method, and I cannot find anything about how to pass more.
I'm doing this basically because my 1 controller is responsible for talking to a few Models, not just one. Either SoccerPlayer or SoccerTeam or SoccerSchedule, it all should be nicely put under
/v1/<controller>/<type>/<id>
Advices?
Thanks!
You can have the best of both worlds anyway, by placing a custom route before the resource route:
Route::get('soccer', 'SoccerController#show');
Route::resource('soccer', 'SoccerController', array('except' => array('show')));
Now the show() method will be escluded from the resource controller control (thus calling soccer/10 or soccer/player will lead to a NotFoundHttpException), and placed into your custom route.
You'll need to edit the show() method to accept the second parameter though:
public function show($type, $id)
{
}
you can use route prefixing
Route::group(array('prefix' => 'soccer'), function()
{
Route::resource('player', 'PlayerController');
});
then, you can put all soccer relavant controllers in the same namespace (and same folder) like Soccer. in this case, change the above route to
Route::resource('player', 'Soccer\PlayerController');

How to set up case insensitive routes with Slim framework?

I have the following association between a route and a callback in my application:
$api->slim->post('/:accountId/Phone-Numbers/', function($accountId) use ($api) {
$api->createPhoneNumber($accountId);
});
What I want to avoid is having the route myhost/a7b81cf/phone-numbers/ return a 404 response because Slim understands the route myhost/a7b81cf/Phone-Numbers/ as being different, due to the usage of uppercase letters.
How can I avoid setting up two separate routes that trigger the same callback function?
This is an old question, but I wanted to provide a clear answer for this problem.
There is a 'routes.case_sensitive' configuration that allows you to do that. I don't know exactly why this is not in the docs (http://docs.slimframework.com/#Application-Settings), but if you look at the framework's source code (specifically, in getDefaultSettings() at Slim.php) you can see that is there.
I just tested it and it works fine.
Summarizing, the solution is to apply the 'routes.case_sensitive' configuration like this:
$configurations = [
// ... other settings ...
'routes.case_sensitive' => false
];
$app->config($configurations);
You could try with route validation/conditions:
$api->slim->post('/:accountId/:phoneNumbers/', function ($accountId) {
$api->createPhoneNumber($accountId);
})->conditions(array('phoneNumbers' => '(p|P)hone\-(n|N)umbers'));
Or if you want more global change you could override Route->matches method in Route class to be case insensitive but it will affect whole application.
You can mimic case-insensitive routing in Slim by registering a hook and modifying the incoming routes to match the case of your defined routes.
In the example, all of your defined routes should be lowercase and strtolower is called on all incoming paths:
$app->hook('slim.before.router', function () use ($app) {
$app->environment['PATH_INFO'] = strtolower($app->environment['PATH_INFO']);
});

Categories