Laravel optional prefix routes with regexp - laravel

Is there a way to create routes with prefixes so I can have routes like this
/articles.html -> goes to listing Controller in default language
/en/articles.html -> goes to the same controller
/fr/articles.html -> goes to the same controller
My current problem is that by doing:
Route::group(['prefix=>'/{$lang?}/',function(){});
a route like this: /authors/author-100.html will match a prefix 'authors` , and for sure there is no language called "authors".
I use laravel 5.5

There doesn't seem to be any good way to have optional prefixes as the group prefix approach with an "optional" regex marker doesn't work. However it is possible to declare a Closure with all your routes and add that once with the prefix and once without:
$optionalLanguageRoutes = function() {
// add routes here
}
// Add routes with lang-prefix
Route::group(
['prefix' => '/{lang}/', 'where' => ['lang' => 'fr|en']],
$optionalLanguageRoutes
);
// Add routes without prefix
$optionalLanguageRoutes();

This should be sufficient using the where Regex match on the optional route parameter:
Route::get('/{lang?}, 'SameController#doMagic')->where('lang', 'en|fr');
You can do the same on Route Group as well, else having all the options as in this answer evidently works.
An update to show the use of prefix:
Route::group(['prefix' => '{lang?}', 'where' => ['lang' => 'en|fr']],function (){
Route::get('', 'SameController#doNinja');
});
As far as I am concerned this should be sufficient even when there is no lang as well as when there is one, just maybe this group could come before other routes.

You can use a table to define the accepted languages and then:
Route::group([
'prefix' => '/{lang?}',
'where' => ['lang' => 'exists:languages,short_name'],
], function() {
// Define Routes Here
});

Another working solution would be to create an array of langs and loop over it:
$langs = ['en', 'fr', ''];
foreach($langs as $lang) {
Route::get($lang . "/articles", "SomeController#someMethod");
}
For sure this makes your route file less readable, however you may use php artisan route:list to clearly list your routes.

Related

How to use multiple method in single route in laravel

I want to use more than one method in a single route using laravel. I'm try this way but when i dd() it's show the plan string.
Route::get('/user',[
'uses' => 'AppController#user',
'as' => 'useraccess',
'roles'=> 'HomeController#useroles',
]);
When i dd() 'roles' option it's show the plan string like this.
"roles" => "HomeController#useroles"
my middleware check the role this way.
$actions=$request->route()->getAction();
$roles=isset($actions['roles'])? $actions['roles'] : null;
The simplest way to accept multiple HTTP methods in a single route is to use the match method, like so:
Route::match(['get', 'post'], '/user', [
'uses' => 'AppController#user',
'as' => 'useraccess',
'roles'=> 'HomeController#useroles',
]);
As for your middleware, to check the HTTP request type, a tidier way would be:
$method = request()->method();
And if you need to check for a specific method:
if (request()->isMethod('post')) {
// do stuff for post methods
}
Here's how you can do multiple methods on a single route:
Route::get('/route', 'RouteController#index');
Route::post('/route', 'RouteController#create');
Route::put('/route', 'RouteController#update');
/* Would be easier to use
* Route::put('/route/{route}', 'RouteController#update');
* Since Laravel gives you the Model of the primary key you've passed
* in to the route.
*/
Route::delete('/route', 'RouteController#destroy');
If you've written your own middleware, you can wrap the routes in a Route::group and apply your middleware to those routes, or individual routes respectively.
Route::middleware(['myMiddleware'])->group(function () {
Route::get('/route', 'RouteController#index');
Route::post('/route', 'RouteController#create');
Route::put('/route', 'RouteController#update');
});
Or
Route::group(['middleware' => 'myMiddleware'], function() {
Route::get('/route', 'RouteController#index');
Route::post('/route', 'RouteController#create');
Route::put('/route', 'RouteController#update');
});
Whichever is easier for you to read.
https://laravel.com/docs/5.6/routing#route-groups

Identify Route's Group in Middleware

My ultimate objective is to limit accesses to the group of routes by validating permissions provided to the user.
These target 'group of routes' have ONE COMMON PARENT GROUP and may have zero or more sub-groups, such that, if access to these target 'group of routes' is permitted/accessible to the user then, all its sub-route groups are also accessible to the user.
To achieve this, I believe I need to differentiate these target group of routes by any uniqueString/parameter in middleware, which is indeed answered here.
But, I want to generalize this further, by applying middleware to common SINGLE PARENT GROUP of all these target group of routes and identify these target group of routes by any means in the middleware.
So, my question is how do I identify/differentiate these target group of routes in the middleware? Is there any way to do so?
Sample Code of what I am trying to describe:
Route::group(['prefix' => 'singleParent','middleware' => 'permissionMiddleware'], function (){
Route::group(['prefix' => 'target-group-1', 'groupUniqueString' => 'tsg1'], function (){
Route::group(['prefix' => 'sub-group-1.1'], function (){
});
Route::group(['prefix' => 'sub-group-1.2'], function (){
});
});
Route::group(['prefix' => 'target-group-2', 'groupUniqueString' => 'tsg2'], function (){
Route::get('route-1','Controller#method-of-Route1');
});
});
So, to specify a route group in your middleware to handle some actions, you can do it in this way :
Route::group(['prefix' => 'singleParent','middleware' => 'permissionMiddleware'], function (){
Route::group(['prefix' => 'target-group-1', 'as' => 'tsg1.'], function (){
//...
});
});
This will generate route names with the prefix : tsg1
Now in your middleware you can do like this to get the route group :
function getCurrentRouteGroup() {
$routeName = Illuminate\Support\Facades\Route::current()->getName();
return explode('.',$routeName)[0];
}
Updated
and to check :
if ($request->route()->named('name')) {
//
}
return $next($request);
Or in another approach you can achieve :
To get the prefix of a route group you can do something like this :
$uri = $request->path();
// this will give you the url path like -> if this is the url :
// http://localhost:8000/foo/bar you will get foo/bar
And then :
$prefix = explode('/',$uri)[0];
// and you will get 'foo'
Let me know if this works for you.

Unused parameters in routes Laravel 5.1

I write api for mobile, since I have more than one version, I don't want to copy-paste the same routes, hence I decided to do something like this:
Route::model('callRequestNote', CallRequestNote::class);
Route::group([
'prefix' => 'api/v{version}/mobile',
'where' => ['version' => '[1|2]'],
], function () {
Route::delete('/notes/{callRequestNote}', MobileNotesController::class . '#destroy');
// other duplicated routes
});
public function destroy($version, CallRequestNote $callRequestNote)
{
//
}
I use version parameter only in BeforeMiddleware, hence I don't need it in controller. My question is how to replace those parameters and make CallRequestNote as a first argument and get rid of $version?

How to add dynamically prefix to routes?

In session i set default language code for example de. And now i want that in link i have something like this: www.something.com/de/something.
Problem is that i cant access session in routes. Any suggestion how can i do this?
$langs = Languages::getLangCode();
if (in_array($lang, $langs)) {
Session::put('locale', $lang);
return redirect::back();
}
return;
Route::get('blog/articles', 'StandardUser\UserBlogController#AllArticles');
So i need to pass to route as prefix this locale session.
If you want to generate a link to your routes with the code of the current language, then you need to create routes group with a dynamic prefix like this:
Example in Laravel 5.7:
Route::prefix(app()->getLocale())->group(function () {
Route::get('/', function () {
return route('index');
})->name('index');
Route::get('/post/{id}', function ($id) {
return route('post', ['id' => $id]);
})->name('post');
});
When you use named routes, URLs to route with current language code will be automatically generated.
Example links:
http://website.com/en/
http://website.com/en/post/16
Note: Instead of laravel app()->getLocale() method you can use your own Languages::getLangCode() method.
If you have more questions about this topic then let me know about it.
Maybe
Route::group([
'prefix' => Languages::getLangCode()
], function () {
Route::get('/', ['as' => 'main', 'uses' => 'IndexController#index']);
});

Laravel, Routing Wildcards to filter and then controller

I am trying to capture a wildcard from URL and then first pass it to a filter then route to controller. I am not sure how to plot the question exactly but here is what I've tried so far.
Route::get('test/(:any?)', array('as' => 'testroute', 'uses' => 'test#result', 'before' => "test_filter:$1"));
Route::filter('test_filter', function($id = NULL)
{
if($id)
echo "This id is " . $id; // Prints "This id is $1"
});
and
Route::get('test/(:any?)', array('as' => 'testroute', function($id = NULL)
{
if($id)
echo "this id is " . $id; // Does not do anything
}, 'uses' => 'test#result'));
Basically, I want to check if there is an id appended to the URL and set a cookie if there is one. But regardless of the case, I want this route to be handled by a controller no matter if there is any id appended or not.
I have to do the same thing with so many routes so I'd prefer something like a filter rather than modifying the controller's codes.
I know that I can directly pass the wildcard element to a closure, or I can feed this as a parameter to any controller but in that case I'll have to modify the controller codes, which I can't at the moment.
Can I do it through filters ? or any other way in which i wont have to modify the controller codes ?
Try passing an anonymous right after the before
Route::get('test/(:any?)',
array(
'as' => 'testroute',
'uses' => 'test#result',
'before' => "test_filter",
function($my_cookie_value)
{
// Set cookie here
}
)
);
Taken from here
I'd use a middleware http://laravel.com/docs/5.1/middleware (or filter for older Laravel versions) and add the route/s into a group which has the middleware as you can see in here http://laravel.com/docs/5.1/routing#route-group-middleware.
The middleware will be executed before the route code, where you can add a logic to manage your cookie.

Resources