Skip to content

Bug: can't change and override valid locales #4297

Closed
@davislasis

Description

@davislasis

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 from protected to public
  • 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugVerified issues on the current code behavior or pull requests that will fix them

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions