If I have middleware like:
<?php namespace App\Http\Middleware;
class SomeMiddleware
{
public function handle($request, Closure $next, $id = null)
{
//
}
}
In kernel.php:
'someMiddleware' => \App\Http\Middleware\SomeMiddleware::class,
In routes.php :
Route::put('post/{id}', ['middleware' => 'someMiddleware']);
How I can pass id captured in {id} to my middleware?
I know that I can pass some custom parameter like this:
Route::put('post/{id}', ['middleware' => 'someMiddleware:16']);
But in laravel documentation there is no described how to pass argument captured in route pattern.
I think that you can get the parameter from inside the middleware like this:
//your middleware's method
public function handle($request, Closure $next)
{
//get the ID
$id = $request->id
}
Related
I created a custom middleware to redirect short urls to other urls, I have a Url model that has this information:
{
"id":1,
"original_url":"http://www.google.com",
"short_url":"http://127.0.0.1:8000/wGjxw",
"updated_at":"2023-02-08T21:05:39.000000Z",
"created_at":"2023-02-08T21:05:39.000000Z"
}
so I have created a middleware:
<?php
namespace App\Http\Middleware;
use App\Models\Url;
use Closure;
use Illuminate\Http\Request;
class RedirectMiddleware
{
public function handle(Request $request, Closure $next)
{
//dd('here'); // is not reaching this code
$url = Url::where('short_url', $request->fullUrl())->first();
if ($url) {
return response()->redirectTo($url->original_url);
}
return $next($request);
}
}
app/Http/Kernel.php
....
....
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\RedirectMiddleware::class,
...
...
But, when I hit the url http://127.0.0.1:8000/wGjxw I get a 404 error,
This is the web.php
Route::get('/', function () {
return view('main');
});
Route::post('/urls', [UrlsController::class, 'store'] );
These routes are for showing the page with the form, and for creating the short url and those are working properly, the problem is that it looks like the middleware is not registered or I don't know what is happening, what I want is the short_url gets redirected to the original_url, what can I do? thanks
If the middleware approach isn't working, you could make a route specifically for it using route model binding with short_url as the key.
https://laravel.com/docs/9.x/routing#customizing-the-key
Route::get('/{url:short_url}', fn (Url $url) => redirect()->away($url->original_url));
My error was that the middleware was in the $middlewareGroups property, and it should be in the $middleware property, now it is working properly
Couldn't find anything that specifically matches my situation. I have a route group defined as:
Route::group(['prefix' => 'api/v1/{access_token}'], function(){
...
}
The above group has several resource routes inside. I am trying to create a custom middleware that will validate the access_token parameter and return a 400 response if the parameter is not valid. I would like to be able to so something like this in my controllers:
class ProductController extends Controller {
/**
* Instantiate a new ProductController
*/
public function __construct()
{
$this->middleware('verifyAccessToken');
}
...
}
My question is not "how do I define custom middleware", but rather, how can I gain access to the access_token parameter from within the handle function of my custom middleware?
EDIT: While the question suggested as a duplicate is similar and has an answer, that answer seems to be outdated and/or unsatisfactory for what I am trying to accomplish.
You can just access it from your $request object using the magic __get method like this:
public function handle($request, Closure $next)
{
$token = $request->access_token;
// Do something with $token
}
http://laravel.com/docs/master/middleware#middleware-parameters
For simple
public function yourmethod($access_token){
$this->middleware('verifyAccessToken', $access_token);
}
I think you can't do it in __construct() method.
Just stick the middleware on the Route::group
Route::group(['prefix' => 'api/v1/{access_token}', 'middleware' => 'verifyAccessToken'], function(){
});
Then in your middleware, as Thomas Kim pointed out, you can use the $request object to gain access to the token that was passed to the route.
public function handle($request, Closure $next)
{
$token = $request->access_token;
// Do something with $token
}
I would like the route argument to be passed as a middleware argument, something like this
Route::get('foo/{id}', ['middleware' => 'bar:{id}', function(){
});
How to do this?
You can get it from the request variable:
Route::get('foo/{id}', ['middleware' => 'bar', function(){
});
public function handle($request, Closure $next) {
$id = $request->id;
}
https://laracasts.com/discuss/channels/general-discussion/how-to-get-url-parameters-at-middleware?page=1
The
bar:id
is used when you want to pass the string id to the middleware.
If you set the middleware up in the controller's constructor, it's possible to pass dynamic middleware variables.
public function __construct()
{
$this->middleware('bar:'.request()->id);
}
I have two Middlewares: beforeCache & afterCache, boths registered on Kernel.
I want to call them into routes in this order:
1. beforeCache
2. myController
3. afterCache
If I define a route like this:
Route::get('especies/{id}', [
'middleware' => 'beforeCache',
'uses' => 'MyController#myMethod',
'middleware' => 'afterCache',
]);
beforeCache don't executes because afterCache is redefining the same array key middleware.
How should I do that? Thanks!
I'll assume you're using 5.1 in this, but what you're doing is essentially trying to define an array of attributes on the route. The brackets [] are just a shorthand version of saying array(...).
From the documentation (http://laravel.com/docs/5.1/middleware#defining-middleware) specifically the Before / After Middleware you simply just need to return a certain way.
For Before middlewares you do your code and return the next request after your code executes.
public function handle($request, Closure $next)
{
// Perform action
return $next($request);
}
For After middleware you handle the rest of the request and then your code executes and finally return the response.
public function handle($request, Closure $next)
{
$response = $next($request);
// Perform action
return $response;
}
The route would end up looking like this,
Route::get('especies/{id}',[
'middleware' => [
'beforeCache',
'afterCache'
],
'uses' => 'MyController#myMethod'
]);
class BeforeMiddleware implements Middleware {
public function handle($request, Closure $next)
{
// Do Stuff
return $next($request);
}
}
class AfterMiddleware implements Middleware {
public function handle($request, Closure $next)
{
$response = $next($request);
// Do stuff
return $response;
}
}
1-The before middleware operates and then passes on the request.
2-The after middleware allows the request to be processed, and then operates on it
So I have a route that looks like this:
Route::any('some/page', ['as' => 'some-page', 'uses' => 'SomePageController#index']);
However, I also have ajax calls at the same URL (using a request parameter called ajax like: some/page/?ajax=my_action) that I want to hit methods on my controller:
index already routes: 'SomePageController#index'
ajax = my_action needs to route: 'SomePageController#ajaxMyAction'
ajax = my_other_action needs to route: 'SomePageController#ajaxMyOtherAction'
ajax = blah_blah needs to route: 'SomePageController#ajaxBlahBlah
...
What's the elegant solution to setting this up in my routes.php file?
After inspection of Laravel's Http Request and Route classes, I found the route() and setAction() methods could be useful.
So I created a middleware to handle this:
<?php namespace App\Http\Middleware;
class Ajax {
public function handle($request, Closure $next)
{
// Looks for the value of request parameter called "ajax"
// to determine controller's method call
if ($request->ajax()) {
$routeAction = $request->route()->getAction();
$ajaxValue = studly_case($request->input("ajax"));
$routeAction['uses'] = str_replace("#index", "#ajax".$ajaxValue, $routeAction['uses']);
$routeAction['controller'] = str_replace("#index", "#ajax".$ajaxValue, $routeAction['controller']);
$request->route()->setAction($routeAction);
}
return $next($request);
}
}
Now my route looks like:
Route::any('some/page/', ['as' => 'some-page', 'middleware'=>'ajax', 'uses' => 'SomePageController#index']);
And correctly hits my controller methods (without disturbing Laravel's normal flow):
<?php namespace App\Http\Controllers;
class SomePageController extends Controller {
public function index()
{
return view('some.page.index');
}
public function ajaxMyAction(Requests\SomeFormRequest $request){
die('Do my action here!');
}
public function ajaxMyOtherAction(Requests\SomeFormRequest $request){
die('Do my other action here!');
}
...
I think this is a fairly clean solution.
You can't make this dispatch in the routing layer if you keep the same URL. You have two options :
Use different routes for your AJAX calls. For example, you can prefix all your ajax calls by /api. This is a common way :
Route::group(['prefix' => 'api'], function()
{
Route::get('items', function()
{
//
});
});
If the only different thing is your response format. You can use a condition in your controller. Laravel provides methods for that, for example :
public function index()
{
$items = ...;
if (Request::ajax()) {
return Response::json($items);
} else {
return View::make('items.index');
}
}
You can read this http://laravel.com/api/5.0/Illuminate/Http/Request.html#method_ajax and this http://laravel.com/docs/5.0/routing#route-groups if you want more details.