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 App\Http\Middleware;
use App\Models\Language;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Request as FacadesRequest;
use Illuminate\Support\Facades\URL;
use Illuminate\Support\Facades\View;
use Symfony\Component\HttpFoundation\Response;
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.
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 ?
Config::set('locales', $locales);
& Config::set('selectedLocale', $locales->get($code))
, It only temporarily sets a configuration value in memory for the current request lifecycle
.So basically during each request-lifecycle
you set a configuration value, that may involve additional overhead
.caches
configuration files for performance in production environments using the php artisan config:cache
command. Changes made to configuration values at runtime (e.g., using Config::set()
) might not be reflected in the cached configuration.well-scoped
to the request
passing through the SetUrlLanguage
middleware though you have set the value of the Config
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 :-
$request->merge()
in the middleware is clean, and scoped to a single request.session
& Laravel’s Service 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.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 of laravel-11
all the features discussed here in the Q&A already existed in the other versions.