I have a multi language site and I’d like to inject the language list from the language middleware to the form request. As far as I can tell there is a service container which could be used for this purpose, but it is based on the class of the value, while here I just want to inject an array of Language models or stdClass if it comes from cache. Is there a way to inject an array from the middleware to a controller or form request?
namespace AppHttpMiddleware;
use AppModelsLanguage;
use Closure;
use IlluminateHttpRequest;
use IlluminateSupportFacadesApp;
use IlluminateSupportFacadesCache;
use IlluminateSupportFacadesRequest as FacadesRequest;
use IlluminateSupportFacadesURL;
use IlluminateSupportFacadesView;
use SymfonyComponentHttpFoundationResponse;
class SetUrlLanguage
{
public function handle(Request $request, Closure $next): Response
{
if (Cache::has('locales'))
$locales = collect(json_decode(Cache::get('locales')));
else {
$locales = Language::all();
Cache::add('locales', $locales->toJson());
}
$locales = $locales->keyBy('code');
$codes = $locales->keys()->toArray();
$code = FacadesRequest::segment(1);
if (!in_array($code, $codes))
abort(404);
URL::defaults([
'locale' => $code
]);
View::share('locales', $locales);
View::share('selectedLocale', $locales->get($code));
if (App::getLocale() !== $code)
App::setLocale($code);
return $next($request);
}
}
edit:
Solved it with the Config
facade for now, but I am curious what is the best way to do this.
3
There are so many way through which you can do this. But 1st I want draw your attention to
Why using Config::set(...)
is not the best approach ?
- When you use
Config::set('locales', $locales);
&Config::set('selectedLocale', $locales->get($code))
, It only temporarily sets a configuration value in memory for thecurrent request lifecycle
.So basically during eachrequest-lifecycle
you set a configuration value, that may involve additionaloverhead
. - Laravel
caches
configuration files for performance in production environments using thephp artisan config:cache
command. Changes made to configuration values at runtime (e.g., usingConfig::set()
) might not be reflected in the cached configuration. - When you use this approach it is not
well-scoped
to therequest
passing through theSetUrlLanguage
middleware though you have set the value of theConfig
in the middleware if other parts of the application are also trying to set or get configuration values, this can make your application harder to debug.
So I think to implement the best approach and as well as to get rid of all the issue I mentioned above you need to use request-object
to do the same like this.
In your middleware
do this..
public function handle(Request $request, Closure $next): Response
{
....//Do your other works//....
// Injecting array into the request
$languages = ['locales' => $locales, 'selectedLocale' => $locales->get($code)];
$request->merge(['data' => $languages]);
return $next($request);
}
You can access the injected array in the controller using the Request
object.
public function index(Request $request)
{
$data = $request->input('data');
//$data is now the array injected by the middleware
}
If you’re using a form request
, you can access the array the same way.
class CustomFormRequest extends FormRequest
{
public function rules()
{
//Accessing the array in form request
$data = $this->input('data');
}
}
N:B :-
- Injecting the array into the Request object using
$request->merge()
in the middleware is clean, and scoped to a single request. - Other approches includes using
session
& Laravel’sService Container Binding
that you have also mentioned in your question. But in this particular scenario I think the above procedure is best suited as per the condition you mentioned. - Please also add
laravel
tag to your question since this particular question focuses on laravel and it’s core feature as a whole rather than it’s specific version. Even before the release oflaravel-11
all the features discussed here in the Q&A already existed in the other versions.