Laravel 4 Route Filter Never Called - filter

I am sure that I am doing something wrong that is very obvious, but for some reason I cannot get any filters except App::before to work in my test application.
//routes.php
Route::get('site/login',
array(
'before'=>'science',
'as'=>'site/login',
'uses'=>'HomeController#getLogin',
)
);
Route::controller(site, 'HomeController');
//filters.php
App::before(function($request){
//var_dump("Before"); exit;
});
Route::filter('science',function(){
dd("Science B!TCH!");
exit;
});
//HomeController.php
public function getLogin(){
$this->layout->body = View::make('home.login');
}
The object was first to ensure that a user was not logged in so I was trying to use the built-in "guest" filter, but it was never being called. So I later created the "science" filter to test if ANY routes would work. If I uncomment the var_dump line in App::before, it displays "Before" and exits as expected.
Can anyone see what I am doing wrong here? When I go to the /site/login page I should see my Breaking Bad movie quote instead of the actual page. However, I am seeing my login form as if nothing was happening.
Thanks!
UPDATE:
I changed the route to look like this now:
//routes.php
Route::get('site/login', 'HomeController#getLogin')->before('science');
... and it works. I get the debugging string "SCIENCE ..." on the screen.
It also works if I do the following
//HomeController.php
public function __construct(){
$this->beforeFilter('science');
}
Are there any use cases or conditions in which the array version of routes gets ignored?
UPDATE 2:
In my efforts to simplify my original description I neglected to show other routes that were in routes.php. Take a look below.
//routes.php
Route::get('site/login',
array(
'before'=>'science',
'as'=>'site/login',
'uses'=>'HomeController#getLogin'
)
);
Route::post('site/login',
array(
'as'=>'site/login',
'uses'=>'HomeController#postLogin'
)
);
Having the POST route AFTER the GET route is what is causing the problem. When I put the POST route BEFORE the GET route, the GET route works with the filter as expected.
Now, I was under the impression that Laravel treated GET and POST requests differently, hence the usage of the different static methods in Route. However, apparently, this is not true as the filter on the latter affects the filter of the former.
Is this a correct assumption? Should I start a different thread about this? I would love to understand why this is working this way.
Thanks!
UPDATE 3
---- SOLVED ---
This tidbit of information is not specifically stated in the documentation but you cannot have identical route names even though those route names are going to different REST verbs.
//routes.php BEFORE
Route::get('site/login', array('as'=>'site/login','uses'=>'HomeController#getLogin', 'before'=>'science'));
Route::post('site/login', array('as'=>'site/login', 'uses'=>'HomeController#postLogin',));
In the above solution, the 2nd Route OVERRIDES the previous route because the "as" uses the same name. I thought that these would be treated differently since one is GET and the other POST, but this is not the case. The filter assignments must happen by name in the backend and, as such, using identical names will override each other.
//routes.php AFTER
Route::get('site/login', array('as'=>'site/login','uses'=>'HomeController#getLogin', 'before'=>'science'));
Route::post('site/login', array('as'=>'site/postLogin', 'uses'=>'HomeController#postLogin',));
As you can see here, I renamed the 'as' part of the array to 'site/postLogin' and I can now use different filters for each the POST, GET, and probably PUT, DELETE and etc.

For better practice if two or more routes use the same filter, those routes should belong in a group. I have a feeling that will correct the issue.
From http://laravel.com/docs/routing#route-groups
Route::group(array('before' => 'auth'), function()
{
Route::get('/', function()
{
// Has Auth Filter
});
Route::get('user/profile', function()
{
// Has Auth Filter
});
});

---- SOLVED ---
This tidbit of information is not specifically stated in the documentation but you cannot have identical route names even though those route names are going to different REST verbs.
//routes.php BEFORE
Route::get('site/login', array('as'=>'site/login','uses'=>'HomeController#getLogin', 'before'=>'science'));
Route::post('site/login', array('as'=>'site/login', 'uses'=>'HomeController#postLogin',));
In the above solution, the 2nd Route OVERRIDES the previous route because the "as" uses the same name. I thought that these would be treated differently since one is GET and the other POST, but this is not the case. The filter assignments must happen by name in the backend and, as such, using identical names will override each other.
//routes.php AFTER
Route::get('site/login', array('as'=>'site/login','uses'=>'HomeController#getLogin', 'before'=>'science'));
Route::post('site/login', array('as'=>'site/postLogin', 'uses'=>'HomeController#postLogin',));
As you can see here, I renamed the 'as' part of the array to 'site/postLogin' and I can now use different filters for each the POST, GET, and probably PUT, DELETE and etc.

Related

Laravel. Conflict when building routes

There are two routes:
Route::get('/{article:slug}', [ArticleController::class, 'showArticlePage']);
and
Route::get('/{user:nickname}', [ProfileInfoController::class, 'getUserByNickname']);
Is there any way for each of the routes to perform its function?You can't change uri
For example:
domain.com/nickname => I have to get the user
There is a search in the table "users"
2.domain.com/my-first-article => I have to get the article
There is a search in the table "articles"
Note that each routes has its own controller and action, but they have a similar uri
You need something to distinguish them it'll be a lot more helpful. E.g use an # in front of usernames.
Another approach would be if you know for sure all slugs will have a hyphen, then you can chain ->where('slug', '...')
See https://pineco.de/handy-regex-constraints-in-laravel-routes/
Otherwise, it'll go through the first defined route.

Laravel 8 route order from bottom to top

I have installed Laravel 8 and work perfectly, and then i tried to learn about routing and try to make some routes like this
Route::view('testing', 'welcome')->name('testingWelcome');
Route::get('testing',[TestingController::class, 'noParameter'])->name('testingNoParam');
Route::view('testing', 'dashboard')->name('testingDashboard');
Some post in here said that routes in web.php work from top to bottom. But, thats not what i get when i called in url http://localhost/laraps/public/testing. it always called the bottom one. i tried to change the order, but still the last one always get called.
Any explanation for this one? or am i made any wrong configuration?
thanks for any help
A short explanation for this would be that each call to Route::{verb} creates a new route entry under your route collection (relevant code). {verb} ban be any HTTP verb e.g. get, or post etc. This entry is created under an array entry [{verb}][domain/url].
This means that when a new route is registered that matches the same URL with the same method it will overwrite the old one.
So in the case
Route::view('testing', 'welcome')->name('testingWelcome');
Route::get('testing',[TestingController::class, 'noParameter'])->name('testingNoParam');
Route::view('testing', 'dashboard')->name('testingDashboard');
Only the 3rd declaration actually "sticks". There are cases where multiple route definitions can match the same URL for example assume you have these routes:
Route::view('testing', 'welcome')->name('testingWelcome');
Route::get('testing/{optionalParameter?}',[TestingController::class, 'parameter'])->name('testingNoParam');
Route::view('testing/{otherParameter?}', 'dashboard')->name('testingDashboard');
In this case all 3 routes are added to the route collection, however when accessing URL example.com/testing the first matched route will be the one that will be called in this case the welcome view. This is because since all 3 routes are declared, once the router finds one matching route, it stops looking for more matches.
Note: There's generally no point in declaring multiple routes with the exact same URL so this is mainly an academic exercise. However there is often a use case for cases like e.g. model/{id} and model/list` to differentiate between getting info for a specific model and getting a list of models. In this case it's important to declare the routes as:
Route::get('model/list', [ ModelController::class, 'list' ]);
Route::get('model/{id}', [ ModelController::class, 'view' ]);
However you can be more explicit in route declarations using:
Route::get('model/{id}', [ ModelController::class, 'view' ])->where('id',
'\d+');
Route::get('model/list', [ ModelController::class, 'list' ]);
in this case the order does not matter because Laravel knows id can only be a number and therefore will not match model/list

Removing /profile/ from /profile/{username} keyword from Route Web.php does not work

I have a Route
Route::get('/{username}', 'ProfileController#profile')->name('profile.view');
If I keep it in the middle of the file, all the route after this does not work.
If I keep this in the bottom, then everything works.
Also, If I add any work like Profile, it works.
Route::get('profile/{username}', 'ProfileController#profile')->name('profile.view');
How to solve this?
That's the way it is supposed to work as you are using a wildcard to match everything. So either you put it at the bottom of the file and it will be used as a fallback route, which means nothing above it should match, then it will fallback to that route. Or you can use a regex to match the username to something which makes it different then the other routes, something like:
Route::get('{username}', 'ProfileController#profile')
->name('profile.view')
->where('username', 'YOUR REGEX HERE');
I would go with the one you showed and already works:
Route::get('profile/{username}', 'ProfileController#profile')
->name('profile.view');
// or
Route::get('user/{username}', 'ProfileController#profile')
->name('profile.view');

Laravel Controller Delegation

Trying to keep my Laravel project organized here, while letting it grow.
Currently I use:
Route::controller('/admin', 'AdminController');
...in order to allow the controller to service general admin pages. This is working fine, however I'd like to delegate specific subqueries to other controllers for cleanliness reasons.
For example, I'd like /admin/dashboard to resolve to AdminController#getDashboard. I'd also like /admin/gallery/ to resolve to AdminGalleryController#getIndex, and /admin/foo/bar to resolve to AdminFooController#getBar.
Is there a simple way to slowly expand functionality like this?
We've migrated to Laravel 5 and 5.1, and this still remains a good way to do things. If you aren't using route groups in Laravel, then you aren't doing Laravel right.
You can define those others as controller routes as well. Just do it before Route::controller('admin') because Laravel searches the registered routes in the other you define them. Since /admin/gallery would match Route::controller('admin') as well as Route::controller('admin/gallery') latter has to be defined first:
Route::controller('admin/gallery', 'AdminGalleryController');
Route::controller('admin/foo', 'AdminFooController');
Route::controller('admin', 'AdminController');
Instead of writing admin every time a route group might be a nice improvement as well:
Route::group(['prefix' => 'admin'], function(){
Route::controller('gallery', 'AdminGalleryController');
Route::controller('foo', 'AdminFooController');
Route::controller('/', 'AdminController');
});
Yes. Simply declare your "exception" routes before your main controller route.
Route::get('/admin/gallery','AdminGalleryContoller#getIndex');
Route::get('/admin/dashboard','AdminController#getDasboard');
Route::controller('/admin','AdminController');

Laravel 4.x, using both controller & resource routing

I'm trying using this:
Route::resource('users', 'UserController');
Route::controller('users', 'UserController');
When I'm using one of them - WORK,
otherwise - only resource work.
There is an option to using them both?
Which ever is on-top will take priority so if you put Route::controller on-top then that's the one that would work. I would post this as a comment but I don't have the rep to do it. Also why would you wanna use both of them at the same time?
Try moving Route::controller declaration above Route::resource:
Route::controller('users', 'UserController');
Route::resource('users', 'UserController');
The thing is that Laravel tries to match request with your defined routes by going from top to bottom and stops when it finds one.
localhost/users/example in your example actually hits show method in your UserController class as explained in documentation (see Actions Handled By Resource Controller).
Therefore Route::controller('users', 'UserController'); is ignored in this case.
I believe it's only working with one because once you use Route::resource(), all routes starting with users is going to be grabbed, and since Route::resource() does not work by prepending the action with the last segement in the uri (public function getUsers()), it's failing.
With your example provided, all you should need to use is Route::controller(). If there are some cases where that won't do, before it, add whatever routes you need using Route::get(), Route::post() or Route::any()
Route::resource() and Route::controller() were I believe not designed to work together and there shouldn't be much need to actually use them together.

Resources