Description
Problem
System does not change incoming request locale with overriding it from outer source (not App config, like database) using filter approach
Describe the bug
- all my routes has {locale} in front as first url segment 'en/dashboard', 'lv/dashboard' etc
- supported locales are stored in local mysql database and managed through admin area
- my project will populate / manage languages only through database and admin area, no need of App config $supportedLocales as client will not change and re-commit files
- to avoid caching locale change in frontend, i have setup mainFilter which caches potential locale change at any point (route) within the system
- IncomingRequest class is initialised before filters, so if my filter override supportedLocales - it does not change in further system loding
CodeIgniter 4 version
4.1.1
Solution 1:
- IncomingRequest class - variable
$validLocales
change fromprotected
topublic
- this way it is possible to override values if needed
Affected module(s)
/system/HTTP/IncomingRequest.php
https://github.com/codeigniter4/CodeIgniter4/blob/develop/system/HTTP/IncomingRequest.php#L99
Solution 2:
- as App config does not have
$validLocales
variable - as IncomingRequest class - variable
$validLocales
is not heavily used elsewhere - as IncomingRequest class controller mandatory requests App config as first method param
- remove variable
$validLocales
from IncomingRequest class - as IncomingRequest class method setLocale() uses
$validLocales
, replace it with already loaded$this->config->supportedLocales
Affected module(s)
/system/HTTP/IncomingRequest.php
remove: https://github.com/codeigniter4/CodeIgniter4/blob/develop/system/HTTP/IncomingRequest.php#L99
remove: https://github.com/codeigniter4/CodeIgniter4/blob/develop/system/HTTP/IncomingRequest.php#L162
update: https://github.com/codeigniter4/CodeIgniter4/blob/develop/system/HTTP/IncomingRequest.php#L225
/**
* Sets the locale string for this request.
*
* @param string $locale
*
* @return IncomingRequest
*/
public function setLocale(string $locale)
{
// If it's not a valid locale, set it
// to the default locale for the site.
if (! in_array($locale, $this->config->supportedLocales))
{
$locale = $this->defaultLocale;
}
$this->locale = $locale;
// If the intl extension is loaded, make sure
// that we set the locale for it... if not, though,
// don't worry about it.
// this should not block code coverage thru unit testing
// @codeCoverageIgnoreStart
try
{
if (class_exists('\Locale', false))
{
\Locale::setDefault($locale);
}
}
catch (\Exception $e)
{
}
// @codeCoverageIgnoreEnd
return $this;
}
For reference my MainFilter class
<?php namespace Modules\Core\Base\Filters;
use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;
use CodeIgniter\Filters\FilterInterface;
use Config\App;
use Config\Database;
class MainFilter implements FilterInterface
{
/**
* Do whatever processing this filter needs to do.
* By default it should not return anything during
* normal execution. However, when an abnormal state
* is found, it should return an instance of
* CodeIgniter\HTTP\Response. If it does, script
* execution will end and that Response will be
* sent back to the client, allowing for error pages,
* redirects, etc.
*
* @param \CodeIgniter\HTTP\RequestInterface $request
*
* @param null $arguments
* @return mixed
*/
public function before(RequestInterface $request, $arguments = null)
{
$locales = [];
// get all languages from database
$db = Database::connect();
$results = $db->table('core_languages')
->select('language')
->where('published', 1)
->get()
->getResultArray();
if (!empty($results)) {
foreach ($results as $result) {
$locales[] = $result['language'];
}
}
if (!empty($locales)) {
/** @var App $config */
$config = Config('App');
$config->supportedLocales = $locales;
$request->config = $config;
$locale = $request->uri->getSegment(1);
if (in_array($locale, $locales)) {
$request->setLocale($locale);
} else {
$request->setLocale($config->defaultLocale);
}
}
}
//--------------------------------------------------------------------
/**
* Allows After filters to inspect and modify the response
* object as needed. This method does not allow any way
* to stop execution of other after filters, short of
* throwing an Exception or Error.
*
* @param \CodeIgniter\HTTP\RequestInterface $request
* @param \CodeIgniter\HTTP\ResponseInterface $response
*
* @param null $arguments
* @return mixed
*/
public function after(RequestInterface $request, ResponseInterface $response, $arguments = null)
{
}
//--------------------------------------------------------------------
}
Context
- OS: Ubuntu 20.04 LTS
- Web server: Apache 2.4.41
- PHP version 7.4 and 8.0
My suggestion
I vote for solution 2 my-self and i can create a PR if needed after discussion and decision