5

Why is it that whenever I redirect something through the constructor of my Codeigniter 4 controller is not working?

<?php namespace App\Controllers\Web\Auth;

class Register extends \App\Controllers\BaseController
{
    function __construct()
    {
        if(session('username')){
            return redirect()->to('/dashboard');
        }
    }
    public function index()
    {
        // return view('welcome_message');
    }
}

But if I put it inside index it's working as expected.

public function index()
{
        if(session('username')){
            return redirect()->to('/dashboard');
        }
}

The thing is, I do not want to use it directly inside index because I it need on the other method of the same file.

user3569641
  • 892
  • 1
  • 17
  • 50
  • Can you elaborate on _ I do not want to use it directly inside index because I it need on the other method of the same file_ ? Also, are you sure `session()` when the controller is getting instantiated? – nice_dev Mar 01 '20 at 16:18
  • 1
    If I'm not wrong he meant that he wants to check the session in the constructor instead of writing it in every other method. May be for code reusability and security.. – BEingprabhU Mar 01 '20 at 16:46
  • 1
    That's correct @beingprabhu. That's what I meant. – user3569641 Mar 01 '20 at 17:41
  • 1
    The proper way to achieve what you're trying to do is by using filters and not using the construct in the controller. – marcogmonteiro Sep 23 '20 at 08:17

5 Answers5

5

As per the Codeigniter forum, you can no longer use the redirect method in the constructor to redirect to any of the controllers.

Please refer the below link for more information

https://forum.codeigniter.com/thread-74537.html

It clearly states that redirect() will return a class instance instead of setting a header and you cannot return an instance of another class while instantiating a different class in PHP.

So that's why you can't use redirect method in constructor.

Instead, what I can suggest to you is that use the header method and redirect to your desired controller.

<?php namespace App\Controllers\Web\Auth;

class Register extends \App\Controllers\BaseController
{
    function __construct()
    {
        if(session('username')){
            header('Location: /dashboard');
        }
    }
}

If that's not feasible or difficult to achieve you can follow the below code

<?php namespace App\Controllers\Web\Auth;

class Register extends \App\Controllers\BaseController
{
    function __construct()
    {
        //call to session exists method
        $this->is_session_available();
    }

    private function is_session_available(){
        if(session('username')){
            return redirect()->to('/dashboard');
        }else{
            return redirect()->to('/login');
        }
    }
}

The 2nd solution will be more interactive than the first one. And make sure the method is private. So that it should not be called from other class instances.

The community team has also given a solution to look into the controller filter.

https://codeigniter4.github.io/CodeIgniter4/incoming/filters.html

Please refer to the thread. I hope it may help you in finding a better solution.

BEingprabhU
  • 1,618
  • 2
  • 21
  • 28
  • 2
    Now I know why, thanks! I actually use filter to achieve what I wanted. Since I really don't know why it's not working when in fact it's working on the previous version (3.*) – user3569641 Mar 01 '20 at 17:40
  • 1
    Glad my answer helped you. Codeigniter 4 is complete rewrite of Codeigniter 3. So many of the methods and functionalities that are available in CI 3 is not available in CI 4. – BEingprabhU Mar 01 '20 at 17:43
  • Yup, I just started today. Been waiting since December so I can start my new project and rewrite the old ones. I noticed that my app (which I am currently rewriting) is much faster compared to the old one. Still with learning curve though but not as much as Laravel. My head would explode with Laravel that's why I waited for Codeigniter 4. – user3569641 Mar 01 '20 at 17:47
  • To be frank I've not yet started working in CI 4. I have been following it for a few months now and unfortunately didn't get much time to look into it. Thanks to you as your question enlightened me and it made me do a quick research on it. That's why I gave you an upvote. – BEingprabhU Mar 01 '20 at 17:52
  • 1
    The proper way to achieve what OP is trying to do is by using filters and not using the construct in the controller. – marcogmonteiro Sep 23 '20 at 08:17
  • May be you are right. I gave him all the options available to achieve a solution for the problem. Everyone has their own way of accomplishing it. If you think my answer doesn't serve its purpose I'm happy to remove it. – BEingprabhU Sep 24 '20 at 18:07
0

In this case you shouldn't even be doing this kind of logic in your controllers. This should be done in a filter and not your controllers.

So you have your controller Register.

You should create a filter in your app/filters folder something like checkLogin.php

That filter should have the following structure:

<?php

namespace App\Filters;

use CodeIgniter\Filters\FilterInterface;
use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;

class CheckLogin implements FilterInterface
{

    /**
     * Check loggedIn to redirect page
     */
    public function before(RequestInterface $request, $arguments = null)
    {
        $session = \Config\Services::session();
        if (session('username')) {
            return redirect()->to('/dashboard');
        }
    }

    public function after(RequestInterface $request, ResponseInterface $response, $arguments = null)
    {
        // Do something here
    }
}

Then in your app/config/Filters.php your should add the filter to the desired controller.

public $aliases = [
    'csrf' => \CodeIgniter\Filters\CSRF::class,
    'toolbar' => \CodeIgniter\Filters\DebugToolbar::class,
    'honeypot' => \CodeIgniter\Filters\Honeypot::class,
    'checkLogin' => \App\Filters\CheckLogin::class,
];

// List filter aliases and any before/after uri patterns
public $filters = [
    'checkLogin' => ['before' => ['Register']],
];

For more information on filters and how to use then please check the documentation.

https://codeigniter.com/user_guide/incoming/filters.html?highlight=filters

You can then even create filters to your other controllers that would redirect to this one in case the user is not logged in.

marcogmonteiro
  • 2,061
  • 1
  • 17
  • 26
0

Codeigniter 4 using initController() to create constructor.

You can't use redirect() inside __construct() or initController() function.

But you can use $response parameter or $this->response to call redirect in initController() before call another function in controller;

<?php namespace App\Controllers\Web\Auth;

class Register extends \App\Controllers\BaseController
{
    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);
        
        
        if(session('username')){
            $response->redirect(base_url('dashboard')); // or use $this->response->redirect(base_url('dashboard'));
        }
    }
    
    public function index()
    {
        // return view('welcome_message');
    }
}
0

I just got into CI 4 and i had the same issue as you did, since i've been approaching the login system as with CI 3.

So here is the proper way of doing it right. Enjoy.

Ivo Ivanov
  • 173
  • 9
-1

Codeigniter 4 do not has any return on Constructor, but you can use like this

public function __construct()
{
    if (!session()->has('user_id')) {
        header('location:/home');
        exit();
    }
}

Don't forget to use exit()

But, you better use Filters

Rahma TV
  • 49
  • 4