Laravel5 assign Middleware to route patterns - php

Assume i have 1 application and two external packages.
Package 1 defines routes like api/v1/package1/foo
Package 2 defines routes like api/v1/package2/bar
In my main application i want to apply some Middleware for each api/v1/* route.
How to do this?

Use Route Groups to accomplish this. You can set prefix or domain groups, namespace groups, and middleware groups this way.
For example:
Route::group(['prefix' => 'api/v1'], function(){
Route::group(['prefix'=>'package1', 'middleware' => 'package1.middleware']), function({
Route::get('foo', 'FooController#foo');
});
Route::group(['prefix' => 'package2', 'middleware' => 'package2.middleware']), function({
Route::get('bar', 'BarController#bar');
});
});

Related

Load backend and frontend routes separately without interfering

I have two kind of routes, admin routes and frontend routes.
The frontend routes
Route::get('{locale?}/', ['uses' => '\App\Http\Controllers\loadViewController#home']);
Route::get('{locale?}/{page}', ['uses' => '\App\Http\Controllers\loadViewController#index']);
Route::get('{locale?}/{template?}/{page}', ['uses' => '\App\Http\Controllers\loadViewController#detail']);
The backend routes
Route::prefix('admin/dashboard')->group(function () {
Route::get('/', 'DashboardController#index')->name('dashboard');
});
Now when i type admin/dashboard or api/admin, laravel uses the frontend routes to load the views, while i want the backend views to be loaded.
So to filter out the backend routes i tried this
Route::group(['where' => ['page' => '^(?!admin|api)$', 'template' => '^(?!admin|api)$']], function ({
Route::get('{locale?}/', ['uses' => '\App\Http\Controllers\loadViewController#home']);
Route::get('{locale?}/{page}', ['uses' => '\App\Http\Controllers\loadViewController#index']);
Route::get('{locale?}/{template?}/{page}', ['uses' => '\App\Http\Controllers\loadViewController#detail']);
});
which obviously did not work
Also the frontend routes should not have something like /website, they should all start with /
My question is: How can i load the backend and frontend routes separately without interfering when called, even if they have the same url length in terms of parameters, keep in mind that the admin routes always start with /admin or /api.
Note: i can't put the backend routes before the frontend routes
Thanks in advance!
If you want to you could put a constraint on the locale route parameter:
Route::pattern('locale', '^(?!(api|admin)$)(\w*)');
You can put this in the boot method of you RouteServiceProvider and it will now not allow the locale route parameter to match for 'api' or 'admin'.
You can register seperate routes in RouteServiceProvider. Following is how you can do it.
Inside RouteServiceProvider.php do:
public function map()
{
$this->mapFrontendRoutes();
$this->mapAdminRoutes();
}
Definition of mapFrontendRoutes():
protected function mapFrontendRoutes()
{
Route::prefix('{locales?}')
->middleware('frontend')
->namespace($this->namespace.'\Frontend')
->group(base_path('routes/frontend.php'));
}
Definition of mapAdminRoutes():
protected function mapAdminRoutes()
{
Route::prefix('admin')
->middleware('admin')
->namespace($this->namespace.'\Admin')
->group(base_path('routes/admin.php'));
}
I personally find this very useful, helps to declare interference free and logical routes. Open to feedback.
The simple way is to group both url's as separate groups. Example as follows :
Route::group(['prefix' => 'admin', 'as' => 'admin'], function () {
Route::post('/dashboard', 'AdminController#dashboard');
});
Route::group(['prefix' => 'home', 'as' => 'home'], function () {
Route::get('/record/{id}', 'HomeController#getRecord');
});

Laravel 7 - Use Middleware and except in route file

I use Laravel 7 for an API project, I have created a JWT Middleware, and I want to apply it to all my routes, except 2 of them.
For now I have in my routes/api.php :
Route::prefix('v1')->group(function () {
Route::get('ping', 'Api\Ping\PingController#ping');
// auth routes
Route::group(['prefix' => 'login/'], function () {
Route::post('login', 'Api\Auth\AuthController#login');
Route::group(['middleware' => 'jwt:api'], function() {
Route::get('me', 'Api\Auth\AuthController#me');
Route::post('refreshToken', 'Api\Auth\AuthController#refresh');
Route::post('logout', 'Api\Auth\AuthController#logout');
});
});
Route::group(['middleware' => 'jwt:api'], function() {
Route::resource('users', 'Api\User\UserController');
// my other routes protected .....
I don't like this approach because I need to copy the middleware.
I tried this approach :
Route::group(
[
'middleware' => ['jwt:api', ['except' => 'login/login']],
'prefix' => 'v1/',
], function() {
But I have this error :
Illegal offset type in isset or empty
Is it possible ? I want to group everything in my route file.
Possible solutions:
You can pass additional parameters to middleware via dots and check in middleware to do not use passed routes
Also, you can overwrite middleware and add some property\constant with array of excepts, like in csrf middleware
Implement ability in Laravel core to pass except array as in your exmaple and make a PR to framework github
Left it as you have done

How to set name in route group in laravel 5.5?

I'm using this package in my project and there have default package routes.
Like this:
I want use this route in my controller. I'm trying to use with name but it did not work this way.
Route::group(['prefix' => 'admin', 'as' => 'admin.'], function () {
Voyager::routes();
});
And
Route::group(['prefix' => 'admin'], function () {
Voyager::routes();
})->name('admin');
I'm trying to use like this:
I want to give access like this, as if I'm trying to access 'admin' route then I could access all routes under these route group. I don't know how I will do that?
Please help me.
You cannot redirect to route with name admin. because such route doesn't exist.
When you use:
Route::group(['prefix' => 'admin', 'as' => 'admin.'], function () {
Voyager::routes();
});
it means all routes created by Voager::routes() will have name starting with admin. but it doesn't mean admin. route exist.
So I assume you should instead use rather admin.voyager.dashboard instead, so you should rather use:
return redirect()->route('admin.voyager.dashboard');
instead of:
return redirect()->route('admin.');

Difference between middleware route group and namespaces route group in laravel 5.1?

I was reading laravel 5.1 documentation. I didn't understand how laravel route group working and what's the difference between following route groups.
Route Groups & Named Routes
If you are using route groups, you may specify an as keyword in the route group attribute array, allowing you to set a common route name prefix for all routes within the group:
Route::group(['as' => 'admin::'], function () {
Route::get('dashboard', ['as' => 'dashboard', function () {
// Route named "admin::dashboard"
}]);
});
Middleware
To assign middleware to all routes within a group, you may use the middleware key in the group attribute array. Middleware will be executed in the order you define this array:
Route::group(['middleware' => 'auth'], function () {
Route::get('/', function () {
// Uses Auth Middleware
});
Route::get('user/profile', function () {
// Uses Auth Middleware
});
});
Namespaces
Another common use-case for route groups is assigning the same PHP namespace to a group of controllers. You may use the namespace parameter in your group attribute array to specify the namespace for all controllers within the group:
Route::group(['namespace' => 'Admin'], function()
{
// Controllers Within The "App\Http\Controllers\Admin" Namespace
Route::group(['namespace' => 'User'], function()
{
// Controllers Within The "App\Http\Controllers\Admin\User" Namespace
});
});
Sub-Domain Routing
Route groups may also be used to route wildcard sub-domains. Sub-domains may be assigned route parameters just like route URIs, allowing you to capture a portion of the sub-domain for usage in your route or controller. The sub-domain may be specified using the domain key on the group attribute array:
Route::group(['domain' => '{account}.myapp.com'], function () {
Route::get('user/{id}', function ($account, $id) {
//
});
});
Route Prefixes
The prefix group array attribute may be used to prefix each route in the group with a given URI. For example, you may want to prefix all route URIs within the group with admin:
Route::group(['prefix' => 'admin'], function () {
Route::get('users', function () {
// Matches The "/admin/users" URL
});
});
You may also use the prefix parameter to specify common parameters for your grouped routes:
Route::group(['prefix' => 'accounts/{account_id}'], function () {
Route::get('detail', function ($account_id) {
// Matches The accounts/{account_id}/detail URL
});
});
Ref: http://laravel.com/docs/5.1/routing
Route groups allow you to group together routes that share common attributes without having to redefine said attributes for each route.
Example
As an example lets use the namespace array attribute.
Say we have a controller called NewsController that contains all the Admin logic for your apps news section. You may place this file within the 'App/Http/Controllers/Admin` directory.
Laravel 5 follows PSR-4 autoloading conventions, so the application expcets the namespace to be identical to the path of the file, so our class might look something like this:
<?php
namespace App\Http\Controllers\Admin;
class NewsController
{
}
We could write a route to this class like so:
Route::get('admin/news', [
'uses' => 'Admin\NewsController#index'
]);
Note: Laravel automatically assumes all your controllers will be in the App/Http/Controllers directory so we can leave this out of any controller declarations in the routes file.
The above should work fine, but maybe you also have a dozen or so other class files that deal with Admin logic all within the same namespace. We can use the namespace option to group these together.
Route::group(['namespace' => 'Admin'], function()
{
Route::get('admin/news', [
'uses' => 'NewsController#index'
]);
Route::get('admin/users', [
'uses' => 'UserController#index'
]);
...
});
Notice how I no longer define the Admin namespace for the controller for each route.
The same process can be applied to middleware, subdomains, and url prefixes.
Further Example
Lets take the first example and build on it. As you can see from the above route declarations all our admin routes share a common url prefix.
http://example.com/admin/news
http://example.com/admin/users
We can use the prefix array attribute to define the common url for our routes. In our case this is admin.
Our updated Route declarations would look like so.
Route::group(['namespace' => 'Admin', 'prefix' => 'admin'], function()
{
Route::get('news', [
'uses' => 'NewsController#index'
]);
Route::get('users', [
'uses' => 'UserController#index'
]);
...
});
Your probably wondering why would this be useful? Well imagine you have developed a large application with tens if not hundreds of routes. Then one day your boss comes to you and says "Hey Mr. tester, we need to change the admin url from /admin to /cms, how long will this take?".
If you've declared all your routes using groups with the prefix array attribute like above, this is going to be an easy and painless process for you.

laravel middleware. Most efficient way

At the moment I'm working with laravel 5 project, which contains ~100 post and get routes. I'm trying to add middlewares here but logics behind this project is really complicated. Middlewares will do really important role here. Before I was using groups, for example:
Route::group(['middleware' => 'auth'], function(){
//routes
});
But everything became really messy since I had to create groups in group, for example:
Route::group(['middleware' => 'auth'], function(){
Route::group(['middleware' => 'status'], function(){
//routes
});
});
At the moment I have 20 controllers, so each of them contains about 5 routes. Could you suggest me more efficent way to use middlewares in big projects. What way do you use? Thanks in advance!
It all depends on which middlewares you need to have applied to different routes.
If you have groups of routes that share the same middleware set, then the easiest way to do is what you do in the first example:
Route::group(['middleware' => 'auth'], function(){
//routes
});
If you have some roots that share common middlewares, but each of them might have some specific middleware applied, then nesting routes and route groups withing existing group like you do in the second example is a way to go:
Route::group(['middleware' => 'auth'], function(){
Route::group(['middleware' => 'status'], function(){
//routes
});
Route::get('/uri/', ['middleware' => 'some_other_middleware']);
});
Finally, when different routes have different middleware sets and you are not able to group them in any way, you'll need to apply a set of middlewares to each of them:
Route::get('/uri1/', ['middleware' => 'some_middleware']);
Route::get('/uri2/', ['middleware' => 'some_other_middleware']);
Long story short - if you have complex rules on what middleware to apply to what routes, then setting it up in the routes.php file will reflect the complexity.
It might be also true that some of the things you do in the middleware should belong to some other layer in the application and moving the logic there could simplify routes.php, but it all depends on what routes and middlewares you have.

Categories