laravel terminable middleware, pass parameters from controller - laravel

I want to use a terminable middleware for request logging:
<?php
namespace Illuminate\Session\Middleware;
use Closure;
use App\Helpers\Logger;
class LogRequest
{
public function handle($request, Closure $next)
{
return $next($request);
}
public function terminate($request, $response)
{
Logger::log($request, $response, $additionalInfo)
}
}
How can I pass the $additionalInfo from the controller to the middleware?
EDIT:
Unfortunately the additional info is generated in the controller. I therefore cannot hard code it in the route middleware function

Have you try to add to kernel.php:
protected $routeMiddleware = [
......
'LogRequest'=> \App\Http\Middleware\LogRequest::class
];
in the LogRequestMiddleware:
public function handle($request, Closure $next, $additionalInfo)
{
//here you have $additionalInfo
$request->attributes->add(["info" => $additionalInfo]);
return $next($request);
}
public function terminate($request, $response)
{
dd( $request->attributes);
}
And in controller:
public function __construct()
{
$additionalInfo = "test"
$this->middleware("LogRequest:$additionalInfo");
}

I think you can set some attribute to the request object in your controller while handling it, and the request object itself will be passed to terminate($request, $response) as the first parameter. Then you can extract whatever you set in your controller and use it.

Edited: You might be able to do this
Controller
$request->attributes->add(['additionalInfo' => 'additionalInfoValue']);
Middleware
public function terminate($request, $response)
{
$additionalInfo = $request->attributes('additionalInfo' => $additionalInfo);
Logger::log($request, $response, $additionalInfo)
}

Related

debug adding header in middleware laravel

i added header in middleware and i want to check in my controller that header that i set exists or not . the problem i cant watch headers in controller debugging? how can i do that? anyway use case for this is cors problem
this is my middleware:
public function handle(Request $request, Closure $next)
{
return $next($request)
->header('Access-Control-Allow-Origin', '*');
}
and this is my controller:
public function action()
{
dd(request()->headers->get("Access-Control-Allow-Origin")); //always null
}
You need to call the set method:
public function handle(Request $request, Closure $next)
{
$request->headers->set('Access-Control-Allow-Origin', '*');
return $next($request);
}
Then you can retrieve the header:
public function action()
{
dd(request()->headers->get("Access-Control-Allow-Origin")); // *
}

How to get current user id in constructor in laravel?

I am using laravel 5.7, but i can't get current user id in __construct().
I also tried Auth:id(), but it also not working.
How to get current user id in constructor?
use Illuminate\Support\Facades\Auth;
class TestController extends Controller
{
public $id;
public function __construct()
{
$this->middleware('auth');
$this->middleware(function ($request, $next) {
$this->id = Auth::user()->id;
return $next($request);
});
dd($this->id);
}
}
Current output is null.
You can only access the session in the closure. Just refactor your code to this:
public function __construct()
{
$this->middleware('auth');
$this->middleware(function ($request, $next) {
$this->id = Auth::user()->id;
dd($this->id);
return $next($request);
});
}
You can now use the value $this->id in your controller methods.
In the example in your question, after you've set the value $this->id, you continue with the request. Since you try to access $this->id outside of the scope of the closure, it still is null in the datadump.
After return you will not go to next statement that's why it is not print.
If you want to use this in view then no need to pass in view you can simply access logged user id like this
{{Auth->user->id}}
if you wan to use this in controller make sure you are logged in.
Sometime session expired then you will not get user id
use Illuminate\Support\Facades\Auth;
class TestController extends Controller
{
public $id;
public function __construct()
{
$this->middleware('auth');
$this->middleware(function ($request, $next) {
$this->id = Auth::user()->id;
dd($this->id);
return $next($request);
});
}
}
The easiest solution is to create a middleware and call it later in the constructor.
php artisan make:middleware FoobarMiddleware
I recommend putting an alias in Kernel.php
protected $routeMiddleware = [
...
'foobar' => \App\Http\Middleware\FoobarMiddleware::class,
]
Constructor:
public function __construct()
{
$this->middleware('auth');
$this->middleware('foobar');
}
I recommend changing the focus of how you are creating everything

Send variable to terminate in middleware

I am trying to send a variable to terminate of middleware from route:
Route::group(['middleware' => 'checkUserLevel'], function () {
// my routes
});
I can get checkUserLevel in handle of middleware but I need to access in terminate method too, what should I do?
public function handle($request, Closure $next, $key)
{
dd($key); // it returns variable
}
public function terminate($request, $response)
{
//I need that variable here
}
As mentioned in documentation, if you would like to use the same instance of middleware (because by default it is using the fresh instance of middleware) you need to register the middleware as singleton.
You can register it as singleton by adding to your ServiceProvider's register method
public function register()
{
$this->app->singleton(\App\Http\Middleware\YourMiddleware::class);
}
Then you can use the class' property like the first example of lorent's answer
protected $foo;
public function handle($request, Closure $next)
{
$this->foo = 'bar';
return $next($request);
}
public function terminate($request, $response)
{
// because we cannot use `dd` here, so the example is using `logger`
logger($this->foo);
}
You can do:
protected $key;
public function handle($request, Closure $next, $key)
{
$this->key = $key;
}
public function terminate($request, $response)
{
$this->key; //access property key
}
even though this should be passed via request global. Like:
public function handle($request, Closure $next)
{
$request->input('key');
}
public function terminate($request, $response)
{
$request->input('key');
}
Edited:
Route::group(['middleware' => 'checkUserLevel'], function () {
Route::get('/test/{testparam}', function () {
});
});
public function handle($request, Closure $next)
{
$request->route('testparam');
}
public function terminate($request, $response)
{
$request->route('testparam');
}
I know this is ages old, but you could also use a static property. That saves you from having to register a singleton:
<?php
namespace App\Http\Middleware;
class MyMiddleware {
private static $key;
public function handle($request, Closure $next, $key)
{
self::$key = ($key); // it returns variable
}
public function terminate($request, $response)
{
$key = self::$key;
}
}
This works in my Laravel 5.8 application, don't see why it wouldnt' work anywhere else. Cannot say if there's any reason NOT to do this, but I don't know of one.
I'm using this myself to generate a Cache key in my handle function, and reuse the same key in my terminate function.

Laravel domain group without having to pass domain parameter to controllers

I have all my routes in a domain group but I would like to avoid having the domain as a parameter in each controller method.
So I would like to avoid having this everywhere:
public function show($domain, $id) {}
and would like to just keep it as
public function show($id) {}
I was able to partially make it work with $request->route()->forgetParameter('subdomain') placed in a middleware but it doesn't work in the case of calling redirect()->action('SomeController#show') from a controller method.
Here are some more details:
First, all routes are in a domain group.
Route::middleware(['some_middleware'])->domain('{subdomain}' .website.com)->group(function () {
// .. All routes
} );
Then, in some_middleware I have
public function handle($request, Closure $next) {
// ..
$request->route()->forgetParameter('subdomain');
return $next($request);
}
Then where it doesn't work:
class SomeController {
public function process()
{
// ...
redirect()->action('SimpleController#show', ['simple' => $id]);
}
}
The error I'm getting is:
Missing required parameters for [Route: ] [URI: simples/{simple}].
This only works if I explicitly pass in the subdomain variable.
class SomeController {
public function process()
{
// ...
redirect()->action('SimpleController#show', ['subdomain'=>'some_subdomain', 'simple' => $id]);
}
}
Can anyone suggest a "fix" for this? Thanks in advance :)
With Laravel 5.5+, you can use URL::defaults to set request-wide values for things like the route helper.
https://laravel.com/docs/5.6/urls#default-values
public function handle($request, Closure $next) {
// ..
$subdomain = $request->route('subdomain');
URL::defaults(['subdomain' => $subdomain]);
$request->route()->forgetParameter('subdomain');
return $next($request);
}
You could create a wrapper helper for the action() helper:
if (! function_exists('actionSub')) {
function actionSub($name, $parameters)
{
return action($name, $parameters + ['subdomain' => request()->route('subdomain')]);
}
}
Then use it:
redirect(actionSub('SimpleController#show', ['simple' => $id]));
If someone has a more elegant solution for this, it will be great to see it.

Laravel Middleware changing header before passing to controller

I'm trying to change the header of my request before passing it to the controller using a middleware but it seems $next($request) executes the code in my controller. Is there a way to change the header then send the updated request to my controller?
My middleware:
class JWTAuthenticator
{
public function handle($request, Closure $next)
{
$token =JWTAuth::getToken();
$my_new_token = JWTAuth::refresh($token);
//it runs here
$response = $next($request);
//it runs this part after executing the controller
$response->header('Authorization','Bearer '.$my_new_token);
return $response;
}
This is how the middleware is assigned to my route:
Route::get('/{user}', 'v1\UserController#find')->middleware('jwt_auth');
That way you are excecuting the $response->header('Authorization','Bearer '.$my_new_token); sentence after the request was attended.
Change your code as follows:
class JWTAuthenticator
{
public function handle($request, Closure $next)
{
$token =JWTAuth::getToken();
$my_new_token = JWTAuth::refresh($token);
$request->headers->set('Authorization','Bearer '.$my_new_token);
return $next($request);
}

Resources