Laravel exclude route in nested Middleware group - php

I have (schematically) the following situation:
MiddlewareGroup1{
MiddlewareGroup2{
Route::resource(...);
...
Route::post('some-ajax-request', 'SomeController#action');
}
OtherNestedMiddlewareGroups{
...
}
}
I have the problem that I want MiddlewareGroup2 to apply for the ajax route, but not MiddlewareGroup1. How can I make MiddlewareGroup1 not apply, but keep MiddlewareGroup2?

I guess there is not built in solution here. You can put this route outside MiddlewareGroup1 or you could check current request url in MiddlewareGroup1, like:
....
if ($request->is('some-ajax-request')) {
return $next($request);
}
....
This will skip MiddlewareGroup1 middleware for defined URL(s).
If you have many similar ajax routes, you could use similar URLs for them ('ajax-add-stuff', 'ajax-do-some-stuff' etc) and check them like this:
if ($request->is('ajax*')) { .... }

Related

Laravel routing strange behavior

I have a single domain/subdomain project. In order to see the event by slug, I made this route:
Route::prefix('events')->namespace('Content\Controller')->group(function () {
Route::get('/', 'EventController#getIndex')->name('event.index');
Route::get('{slug}', 'EventController#getView')->name('event.show');
Route::get('{slug}/edit', 'EventController#getEdit')->name('event.edit');
Route::post('load-more-ajax/{region?}', 'EventController#postLoadMoreAjax');
Route::any('sorted-ajax/{region?}', 'EventController#anySortedAjax');
Route::get('category/{category_slug}/{subcategory_slug?}', 'EventController#getCategory');
});
After my page didn't load correctly, I did a dump in the controller:
public function getView($slug)
{
return $slug;
}
To get to the route I am using this URL: https://example.com/events/slug-example.
The problem is that the route is being hit as I see the response when I change it, but I am not getting the slug, instead I am getting Region object back.
If I do this:
public function getView($region, $slug)
{
return $slug;
}
Then I get the slug back. But I have no idea how is this possible, and how could I do it (I came as another dev on the existing project).
I tried commenting out all the middleware and it is still the same. How can I even make something fill the method if I didn't explicitly say it?
EDIT
I noticed there is binding going on in routes file:
Route::bind('region', function ($value) {
...
});
Now if I dd($value) I get the variable back. How is this value filled? From where could it be forwarded?
Looking quickly it should work, but maybe you was verifying other url.
Make sure you put:
Route::get('{slug}', 'EventController#getView')->name('event.show');
Route::get('{slug}/edit', 'EventController#getEdit')->name('event.edit');
routes at the end of routes you showed.
EDIT
If you think that's not the case and you don't have your routes cached you should run:
php artisan route:list
to verify your routes.
EDIT2
After explaining by OPs in comment, domain used for accessing site is:
{region}.example.com
So having $region in controller as 1st parameter is correct behaviour because of route model binding and other route parameters will be 2nd, 3rd and so on.
Instead of
Route::prefix('events')->namespace('Content\Controller')->group(function () {
Route::get('/', 'EventController#getIndex')->name('event.index');
Route::get('{slug}', 'EventController#getView')->name('event.show');
Route::get('{slug}/edit', 'EventController#getEdit')->name('event.edit');
Route::post('load-more-ajax/{region?}', 'EventController#postLoadMoreAjax');
Route::any('sorted-ajax/{region?}', 'EventController#anySortedAjax');
Route::get('category/{category_slug}/{subcategory_slug?}', 'EventController#getCategory');
});
try
Route::prefix('events')->namespace('Content\Controller')->group(function () {
Route::get('/', 'EventController#getIndex')->name('event.index');
Route::post('load-more-ajax/{region?}', 'EventController#postLoadMoreAjax');
Route::any('sorted-ajax/{region?}', 'EventController#anySortedAjax');
Route::get('category/{category_slug}/{subcategory_slug?}', 'EventController#getCategory');
Route::get('{slug}', 'EventController#getView')->name('event.show');
Route::get('{slug}/edit', 'EventController#getEdit')->name('event.edit');
});

Detect if action is show or edit in Laravel 5.2

I have a middleware that detects if a user owns a tournament.
So, if user want to edit a tournament he doesn't own, he will get a 403.
Thing is I can't make difference between laravel.dev/tournament/1/edit, and laravel.devl/tournament/1
Off course, I could check the "edit" word in URL, but I would prefer other better param...
I tried method param in Request Object, but it is giving me GET for both, so I can't make difference...
Any Idea???
In your case, you can do like this:
$request->route()->getName();
Now you can do your logic based on this.
What about using a different HTTP method for edit, e.g PATCH or PUT and declaring two different routes, something like:
Route::get('laravel.devl/tournament/1', 'TournamentController#showTournament');
Route::put('laravel.dev/tournament/1/edit', 'TournamentController#editTournament');
Then in the TournamentController you can check if the user has rights to edit.
It sounds like you should just use route specific middleware instead of global middleware. See https://laravel.com/docs/master/middleware#assigning-middleware-to-routes. Then you can just do:
Route::get('/tournament/{id}/edit', ['middleware' => ['tournamentOwner'], function () {
//
}]);
Route::get('/tournament/{id}', ['middleware' => [], function () {
//
}]);
If it's a RESTful route, you can just do:
public function __construct()
{
$this->middleware('tournamentOwner', ['only' => ['edit']]);
}

How can I check whether the route "URL" exists?

In Laravel 5.2, is there a particular way (handler) to check whether a route is existing or not? Let's say, for a basic URL like:
http://www.example.com/laravel
I then want to handle the non-existing URLs (like: /laravel) from my Main Page Router, which is:
Route::get('/{page}', funtion(){
//check if $page is a valid route URL? Or 404?
});
How do I purposely check whether this route is a valid one or not?
I use the following as my last route:
Route::any('{catchall}', function($page) {
abort(404);
} )->where('catchall', '(.*)');
If you are not aware yet, abort(404) will return the view 404.blade.php from resources/views/errors.
Simply put your Route::get('/{page}','MainController#getPage'); last. That way if it finds another route before it will use it but if it doesn't then it will get caught by this. For example:
Route::get('/welcome','WelcomeController#getWelcome');
Route::get('/test','TestController#getTest');
Route::get('/{page}','MainController#getPage');
If you were to hit /welcome or /test it should route them to the correct controller. If you where to hit /hello it should go to the MainController and hit function getPage($page) with $page being the page you hit.
If it hits MainController#getPage you know it was basically a 404.
If you need to know before you hit the route for some reason you could create something like this:
Route::get('/checkurl/{page}',function($page) {
$exists = Route::has('/' . $page);
return (new Response(json_encode(['exists'=>$exists]),200);
});
Adding last route with any catch doesn't works anymore with laravel 5.5.1+

Change target controller/action from middleware

I have two resources /test and /blabla.
For the /test I have registered middleware. In the middleware, based on certain condition, I would like to redirect current call to the controller/action which serve /blabla resource, transparently for user (no any extra client request, no 302 status response code etc..). How can I achieve it ?
It seems like your solution might be better suited in the routes file. You are suggesting serving a different route given a certain condition.
So in your routes.php file:
Route::get('test', function(){
if($condition){
return App::make('App\Http\Controllers\TestController')->index();
} else {
return App::make('App\Http\Controllers\BlaBlaController')->index();
}
});
If you still want to handle it in the middleware you should be able to do the same thing as above:
return App::make($controller)->index(); // or whatever controller method you want to call.
If you need both sets of middlewares to be called, then inside the constructor (after calling your middlewares) check your condition and call the other controller like above.
If you want to change the users url, I don't think there's any way other than returning a redirect. Most users don't notice the redirect so it will probably seem "transparent."
In that case, your middleware function looks like:
public function handle($request, Closure $next)
{
if (something == thingy) {
return redirect('/blabla');
}
return $next($request);
}

Zend 2 equivalent of Laravel 4 Route Filter

I'm new to Zend 2, I started first with laravel and I need something to do that I know Laravel's Route Filter can solve but I'm using Zend 2.
Laravel Route Filter
I checked the documentation of Zend 2 and I can't seem to find it.
I need to do some logging and stuffs only on selected routes and I don't want to add that code on every actions of every routes because I have over 50 different routes here, but in laravel I could make use of route filter so that in selected routes, it will go first in the filter before going to that route.
In laravel's route:
Route::get('route1',array('before'=>'generic','uses'=>'GenericController#getIndex'));
Route::get('route2',array('before'=>'generic','uses'=>'GenericController#getIndex'));
Route::filter('generic', 'RouteFilter');
I have not used Laravel before, but I followed to the link and I am very afraid to say that,
No, it does not exist
You will have use the controller:
public function somethingAction()
{
if (!condition true) {
return $this->notFoundAction();
// or return $this->redirect()->toRoute('MyRoute');
}
// Route is filtered
}
You can also attach a callback to the MvcEvent::EVENT_ROUTE event:
public function(MvcEvent $e)
{
$e->getApplication()->getEventManager()->attach(MvcEvent::EVENT_ROUTE, function(EventInterface $e) {
// check the route and do whatever you like
$matchedRouteName = $event->getRouteMatch()->getMatchedRouteName();
if ($matchedRouteName = 'admin') {// or whatever you want to check
// check if user is admin
}
});
}
Not only MvcEvent::EVENT_ROUTE, there are a lot of events triggered such as MvcEvent::EVENT_DISPATCH. You just need to attach a callback function!
For, full list of all the Mvc Events, view this link!

Categories