I'm using "laravel/lumen-framework": "5.7.*"
I have two middlewares, first one AuthTokenAuthenticate that should be applied to all the routes, so its defined in bootstrap/app.php like
$app->middleware([
App\Http\Middleware\AuthTokenAuthenticate::class
]);
Another middleware is defined like
$app->routeMiddleware([
'auth.token' => Vendor\Utilities\Middleware\AuthToken::class
]);
and will only be applied to some specific routes.
I need auth.token to be executed first, then AuthTokenAuthenticate but I can't find the way to do it because Lumen executes $app->middleware routes first.
Laravel has $middlewarePriority which is exactly what I need, but how can I handle it in Lumen?
I don't think this is possible in Lumen in the way you want to. What I suggest is using the middleware alongside the router group middleware options.
Remove the global middleware registration
/bootstrap/app.php
$app->middleware([
//App\Http\Middleware\AuthTokenAuthenticate::class
]);
Add both middlewares to the route middleware
/bootstrap/app.php
$app->routeMiddleware([
'auth.token' => Vendor\Utilities\Middleware\AuthToken::class,
'auth.token.authenticate' => App\Http\Middleware\AuthTokenAuthenticate::class
]);
Create two route groups: one with just auth.token.authenticate and one group with both auth.token and auth.token.authenticate.
/routes/web/php
$router->get('/', ['middleware' => 'auth.token.authenticate', function () use ($router) {
// these routes will just have auth.token.authenticate applied
}]);
$router->get('/authenticate', ['middleware' => 'auth.token|auth.token.authenticate', function () use ($router) {
// these routes will have both auth.token and auth.token.authenticate applied, with auth.token being the first one
}]);
I think this is the cleanest way to get the desired effect.
As of now with Lumen v6 (and possibly earlier), you can specify the middleware as an array field when defining your route. In the routes file web.php, I have something like the following:
$router->get('/api/path/to/thing', [
'uses' => 'FooController#index',
'middleware' => ['etag', 'caching', 'bar']
]);
Note how the the middleware field is an array with three elements. When this route is called, the middleware etag will execute first, then caching, then bar, in that order. When you only have a single middleware class, you can either specify it as a plain string or an array with just one element. This can of course be extended to route groups so that you have an entire class of routes that all use this middleware in this order.
Related
I have a program that uses $router->resource([]). I use laravel-admin.
here my routes.php
$router->resources([
'programs' => ProgramController::class,
'programs/categories' => ProgramCategoryController::class,
]);
on my programs its work well with all the crud operation.
but on my programs/categories its not working, said not found. did route controller must use different url?...
i mean my category can't be child from my programs with different controller?...
Try changing "programs/categories" to "programs.categories"
You want to add "programs" prefix to categories resource routes. You can do it by changing you code as follows:
$router->resources([
'programs' => ProgramController::class,
]);
// to add programs prefix to categories routes
Route::group(['prefix' => 'programs'], function () use ($router) {
$router->resource('categories', ProgramCategoryController::class);
// here you can add more routes and all those routes will have
// "programs" prefix in there url
});
refer to https://laravel.com/docs/5.5/controllers#resource-controllers
Supplementing Resource Controllers
If you need to add additional routes to a resource controller beyond the default set of resource routes, you should define those routes before your call to Route::resource; otherwise, the routes defined by the resource method may unintentionally take precedence over your supplemental routes:
Route::get('photos/popular', 'PhotoController#method');
Route::resource('photos', 'PhotoController');
So on my case above, just simply change this:
$router->resources([
'programs' => ProgramController::class,
'programs/categories' => ProgramCategoryController::class,
]);
to this :
$router->resources([
'programs/categories' => ProgramCategoryController::class,
'programs' => ProgramController::class,
]);
and it's working well now, also both crud operations.
it's not an optimal solution but its working for me.
I want to pretty-up my routes, ie, I have such entries:
// DataTable
Route::get('dt/reservations/{room_id]', 'DataTablesController#reservations')->where(['room_id', '[0-9]+']);
Route::get('dt/rooms/{area_id]', 'DataTablesController#rooms')->where(['area_id', '[0-9]+']);
Route::get('dt/departments', 'DataTablesController#departments');
Route::get('dt/addresses', 'DataTablesController#areas');
Route::get('dt/areas', 'DataTablesController#areas');
I would like to make it more understandable. I can add prefix what would give me:
// DataTable
Route::group(['prefix' => 'dt'], function () {
Route::get('reservations/{room_id]', 'DataTablesController#reservations')->where(['room_id', '[0-9]+']);
Route::get('rooms/{area_id]', 'DataTablesController#rooms')->where(['area_id', '[0-9]+']);
Route::get('departments', 'DataTablesController#departments');
Route::get('addresses', 'DataTablesController#areas');
Route::get('areas', 'DataTablesController#areas');
});
But can I somehow make the rest too? The route name and method name will always be the same.
Is it possible to make something like:
// DataTable
Route::group(['prefix' => 'dt'], function () {
Controller => DataTablesController,
Methods => [
'reservations',
'rooms',
'departments',
'addresses',
'areas'
];
});
Although a very good feature. But it can't be done in Laravel
All your routes must be explicit, Laravel won't/can't assume that you
are using same controller for all the routes.
So you will have to define all the routes explicitly.
Only Resource Controllers can have implicit routing in Laravel
Take a look here....
Route use the same controller
I have routes for my project and I'm using Route::when('*', 'auth') to protect my routes by implement auth filter on every Route like given below:
// All the following routes must be filtered by the 'auth' filter.
Route::when('*', 'auth');
Route::resource('route_1', 'Controller_1);
Route::controller('route_2', 'Controller_2');
Route::get('route_3', 'Controller_3#method_1');
It's clear that the user can not access the routes as a guest or in other words without log into.
Now I'v to use a couple of routes which could be accessed without login. I'm using the following code but it's not working and also implement auth filter on route_0:
// Following two routes must not be filtered by the 'auth' filter.
Route::get('route_0', 'Controller_0#getMethod');
Route::post('route_0', 'Controller_0#postMethod');
// All the following routes must be filtered by the 'auth' filter.
Route::when('*', 'auth');
Route::resource('route_1', 'Controller_1);
Route::controller('route_2', 'Controller_2');
Route::get('route_3', 'Controller_3#method_1');
How can I remove auth filter from route_0? I also don't want to use auth filter separately on each route or controller. Any solution please?
You can use Route group like following
Route::get('/', array('as' => 'home','uses' => 'HomeController#index'));
Route::group(array('before' =>'auth'), function()
{
Route::get('about', array('as' => 'about','uses' => 'HomeController#about'));
}
);
Put the routes those required to be filtered in the group and other outside. You can use multiple group too.
You can read about it here https://laravel.com/docs/4.2/routing#route-filters
You can use a route group that uses a given route filter.
Route::group(['before' => ['auth']], function() {
Route::resource('route_1', 'Controller_1');
Route::controller('route_2', 'Controller_2');
Route::get('route_3', 'Controller_3#method_1');
});
// Other non filtered routes.
Documentation: https://laravel.com/docs/4.2/routing#route-filters
Note: In Laravel 5.*, we don't use filters anymore, instead, we use middlewares: https://laravel.com/docs/master/middleware.
You can use whenRegex instead of when and exclude the route path from matching when applying the filter:
Route::whenRegex('/^((?!route_0).)*$/', 'auth');
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.
In Laravel it's quite handy to quickly generate a load of routes by using a route resource:
Route::resource('things'ThingsController');
This will produce all the necessary RESTful routes for CRUD operations. One of these is the PUT/PATCH route which might be defined as follows:
PUT/PATCH things/{id} ThingsController#update things.update
I've read around that it's better to explicitly define each of your routes rather than use a route resource but how would I define the PUT/PATCH route above. I understand that I can do
Route::put('thing/{id}', ['as' => 'things.update']);
or
Route::patch('thing/{id}', ['as' => 'things.update']);
But the second would overwrite or conflict with the first allowing the things.update route name to only refer to either a PUT or PATCH request. How can I explicitly create the combined PUT/PATCH route as created by the resource route?
After tedious searching, try the following;
Route::match(array('PUT', 'PATCH'), "/things/{id}", array(
'uses' => 'ThingsController#update',
'as' => 'things.update'
));
This allows you to restrict request via an array of Verbs.
Or you can limit the resource as so;
Route::resource('things', 'ThingsController',
array(
'only' => array('update'),
'names' => array('update' => 'things.update')
));
Both should provide the same result, but please note they are not tested.
This work for me
Route::match(['put', 'patch'],'thing/{id}', 'ThingsController#update');