Welcome Guest, Not a member yet? Register   Sign In
redirect() does not redirects
#1

"redirect()" does not make redirect - it is only returns prepared response for redirecting. For redirecting you need to "return" this response from executing method of the Controller. Yes it is described in the documentation. But it makes some inconvenience.
In CI3 "redirect()" was physically doing the redirect. And it was possible to run it from anywhere - Controller, Model, Library.
In CI4 need to run it only from Controller and return it's response.

Here is my case:

I want to use route localization like said here. Every URLs should contain locale segment. And if someone goes to "mydomain.com/User" I want to redirect him to "mydomain.com/en/User" (default locale).
So as every Controller extends "BaseController" I've decided to add checking in its constructor:
PHP Code:
class BaseController extends Controller
{

    /**
     * Constructor.
     */
    public function initController(\CodeIgniter\HTTP\RequestInterface $request, \CodeIgniter\HTTP\ResponseInterface $response, \Psr\Log\LoggerInterface $logger)
    {
        // Do Not Edit This Line
        parent::initController($request$response$logger);

        // check locale segment
        $uri = \Config\Services::uri();
        $locale $uri->getSegment(1);
        if (!in_array($locale, ['en''ua''de'])) {
            return redirect()->to('/en/' $uri->getPath());
        }
    }


But It was no effect. Then I tried to make separate method and call it in constructor, make Library and Event listener - nothing helped.

The only thing that helped me was - to make separate method in "BaseController" and call it from executing method of my Controller. But there is a nuance - if this method returns a response for a redirect, you need to return it from the controller method.

Method in "BaseController":
PHP Code:
    /**
     * Check locale
     * @return bool|\CodeIgniter\HTTP\RedirectResponse
     */
    public function checkLocale()
    {
        // check locale segment
        $uri = \Config\Services::uri();
        $locale $uri->getSegment(1);
        if (!in_array($locale, ['en''ua''de'])) {
            return redirect()->to('/en/' $uri->getPath());
        }

        return true;
    

My Controller:
PHP Code:
<?php namespace App\Controllers;

class 
User extends BaseController
{
    public function index()
    {
        $check $this->checkLocale();
        if (!is_bool($check)) {
            return $check;
        }

        // other code of the method
    }


Based on this, I need to insert this check into every executable method of every controller. And this is not very good.

Maybe someone knows a more convenient way to perform such check in one place (as I wanted to do it in the constructor)?
Reply
#2

Haha, I just answered a question from you on StackOverflow and here we meet again (I promise I'm not following you).

Have you tried using Filters? https://codeigniter4.github.io/userguide...lters.html

The idea behind filters is precisely what you want to achieve: call a given method before (or after) every call to a controller. It is called "filters" because it can be used to prevent the user from accessing data without authentication, for example.

Take a look and tell me if it doesn't fit your needs.
Reply
#3

(09-06-2020, 11:09 AM)T.O.M. Wrote: "redirect()" does not make redirect - it is only returns prepared response for redirecting. For redirecting you need to "return" this response from executing method of the Controller. Yes it is described in the documentation. But it makes some inconvenience.
In CI3 "redirect()" was physically doing the redirect. And it was possible to run it from anywhere - Controller, Model, Library.
In CI4 need to run it only from Controller and return it's response.

Here is my case:

I want to use route localization like said here. Every URLs should contain locale segment. And if someone goes to "mydomain.com/User" I want to redirect him to "mydomain.com/en/User" (default locale).
So as every Controller extends "BaseController" I've decided to add checking in its constructor:
PHP Code:
class BaseController extends Controller
{

    /**
     * Constructor.
     */
    public function initController(\CodeIgniter\HTTP\RequestInterface $request, \CodeIgniter\HTTP\ResponseInterface $response, \Psr\Log\LoggerInterface $logger)
    {
        // Do Not Edit This Line
        parent::initController($request$response$logger);

        // check locale segment
        $uri = \Config\Services::uri();
        $locale $uri->getSegment(1);
        if (!in_array($locale, ['en''ua''de'])) {
            return redirect()->to('/en/' $uri->getPath());
        }
    }


But It was no effect. Then I tried to make separate method and call it in constructor, make Library and Event listener - nothing helped.

The only thing that helped me was - to make separate method in "BaseController" and call it from executing method of my Controller. But there is a nuance - if this method returns a response for a redirect, you need to return it from the controller method.

Method in "BaseController":
PHP Code:
    /**
     * Check locale
     * @return bool|\CodeIgniter\HTTP\RedirectResponse
     */
    public function checkLocale()
    {
        // check locale segment
        $uri = \Config\Services::uri();
        $locale $uri->getSegment(1);
        if (!in_array($locale, ['en''ua''de'])) {
            return redirect()->to('/en/' $uri->getPath());
        }

        return true;
    

My Controller:
PHP Code:
<?php namespace App\Controllers;

class 
User extends BaseController
{
    public function index()
    {
        $check $this->checkLocale();
        if (!is_bool($check)) {
            return $check;
        }

        // other code of the method
    }


Based on this, I need to insert this check into every executable method of every controller. And this is not very good.

Maybe someone knows a more convenient way to perform such check in one place (as I wanted to do it in the constructor)?

You can improve the approach to your design, and completely avoid "en/home" etc. First ensure all text on your pages are actually from language blocks, then have translations for the languages you wish to support. Then automatically retrieve a users locale like this..https://codeigniter.com/user_guide/outgoing/localization.html?highlight=locale#retrieving-the-current-locale and automatically serve the user in his/her language or default if not available.

For the redirect, you can create a helper function like this, and use it as you were using redirect in CI3.

if
(!function_exists('go')){
    function go($route){
        $str = base_url().'/'.$route;
      header("Location: $str");
      exit();
    }
}

Hope it helps
Reply
#4

(09-06-2020, 09:48 PM)SteeveDroz Wrote: Have you tried using Filters? https://codeigniter4.github.io/userguide...lters.html

Yes, filters are really what I've needed! Thanks for your help Smile
Reply
#5

(09-06-2020, 11:42 PM)chenzen Wrote: You can improve the approach to your design, and completely avoid "en/home" etc. First ensure all text on your pages are actually from language blocks, then have translations for the languages you wish to support. Then automatically retrieve a users locale like this https://codeigniter.com/user_guide/outgo...ent-locale and automatically serve the user in his/her language or default if not available.
Interesting solution - to use different locales in the same URL depending on user. Maybe I've missed it when read the docs Confused 
And even "setLocale()" may call in filter, as said before, when user is authorized Cool

(09-06-2020, 11:42 PM)chenzen Wrote: For the redirect, you can create a helper function like this, and use it as you were using redirect in CI3.

if
(!function_exists('go')){
    function go($route){
        $str = base_url().'/'.$route;
      header("Location: $str");
      exit();
    }
}
Alternatively, it may be. Thanks!
Reply




Theme © iAndrew 2016 - Forum software by © MyBB