CodeIgniter Forums
problem with custom controller constructor - Printable Version

+- CodeIgniter Forums (https://forum.codeigniter.com)
+-- Forum: CodeIgniter 4 (https://forum.codeigniter.com/forumdisplay.php?fid=28)
+--- Forum: CodeIgniter 4 Support (https://forum.codeigniter.com/forumdisplay.php?fid=30)
+--- Thread: problem with custom controller constructor (/showthread.php?tid=79333)

Pages: 1 2


problem with custom controller constructor - tino - 05-29-2021

i have a SignupController with some methods in it.
these methods use the $session object, which is declared in BaseController::initController(), and everything works fine.

BaseController, i only declared the protected $session property and initialized in initController():
PHP Code:
<?php

namespace App\Controllers;

use 
CodeIgniter\Controller;
use 
CodeIgniter\HTTP\CLIRequest;
use 
CodeIgniter\HTTP\IncomingRequest;
use 
CodeIgniter\HTTP\RequestInterface;
use 
CodeIgniter\HTTP\ResponseInterface;
use 
Psr\Log\LoggerInterface;

/**
 * Class BaseController
 *
 * BaseController provides a convenient place for loading components
 * and performing functions that are needed by all your controllers.
 * Extend this class in any new controllers:
 *    class Home extends BaseController
 *
 * For security be sure to declare any new methods as protected or private.
 */

class BaseController extends Controller
{
 
/**
 * Instance of the main Request object.
 *
 * @var IncomingRequest|CLIRequest
 */
 
protected $request;

 
/**
 * An array of helpers to be loaded automatically upon
 * class instantiation. These helpers will be available
 * to all other controllers that extend BaseController.
 *
 * @var array
 */
 
protected $helpers = [];

 protected 
$session;

 
/**
 * Constructor.
 *
 * @param RequestInterface  $request
 * @param ResponseInterface $response
 * @param LoggerInterface  $logger
 */
 
public function initController(RequestInterface $requestResponseInterface $responseLoggerInterface $logger)
 {
 
// Do Not Edit This Line
 
parent::initController($request$response$logger);

 
//--------------------------------------------------------------------
 // Preload any models, libraries, etc, here.
 //--------------------------------------------------------------------
 // E.g.: $this->session = \Config\Services::session();
 
$this->session session();
 }


i want the SignupController to be accessible only if the session isn't set, so i used to to an if like this in the multiple methods of the SignupController
PHP Code:
if ($this->session->is_logged_id) {
    return redirect()->to("/")


the fact is that i'm trying to refactor everything for better readability and i decided to create a constructor in the SignupController and move the above if in it, so the code looks like this:

PHP Code:
<?php

namespace App\Controllers\Signup;

use 
App\Controllers\BaseController;
use 
CodeIgniter\HTTP\RedirectResponse;

class 
SignupController extends BaseController {

    /**
    * when an instance of this class is created
    * redirect if the user is already logged in
    */
    public function __construct() {
        if ($this->session->is_logged_in) {
            return redirect()->to("/");
        }
    }

    /**
    * shows the signup page
    */
    public function index() {
        // do stuff...
        echo view("signup");
    }

    public function signup() {
        // do stuff...
    }


the problem is that it's like BaseController::initController() is called after my own constructor, so the $session property is set only after the execution of my SignupController::__constructor()

i say this because i tried to do a var_dump() of the $session property inside of SignupController::__constructor() and the output is null, but if i try to do the same thing in the other SignupController methods i can actually see that $session is an object with its properties and methods...


RE: problem with custom controller constructor - includebeer - 05-29-2021

Don't use a constructor. Override initController(), don't forget to call parent::initController(), and then do what you need to do.
But, a better approach, would be to create a filter and do your redirect in it.


RE: problem with custom controller constructor - paulkd - 05-29-2021

(05-29-2021, 12:25 PM)includebeer Wrote: Don't use a constructor. Override initController(), don't forget to call parent::initController(), and then do what you need to do.
But, a better approach, would be to create a filter and do your redirect in it.

So I've been struggling with the "purpose" of initController and have resorted to using a standard constructor for all controllers extended off baseController (I'm migrating from CI3 you see).

Using a constructor is working for me, but my preference is to follow the "correct/recommended/designed" pattern. The problem I have is that you can't just call parent::initController() you have to provide the request, response and logger params.

I've not been able to find any code examples where parent::initController() is used.


RE: problem with custom controller constructor - InsiteFX - 05-30-2021

Myth/Auth AuthController uses the __construct() and passes service objects. for sessions etc.


RE: problem with custom controller constructor - paliz - 05-30-2021

math auth has filter use it


RE: problem with custom controller constructor - includebeer - 05-30-2021

(05-29-2021, 11:39 PM)paulkd Wrote: I've not been able to find any code examples where parent::initController() is used.

There's an example right in the BaseController that calls the parent initController from the Controller class :
PHP Code:
parent::initController($request$response$logger); 



RE: problem with custom controller constructor - groovebird - 06-22-2022

(05-29-2021, 12:25 PM)includebeer Wrote: Don't use a constructor. Override initController(), don't forget to call parent::initController(), and then do what you need to do.
But, a better approach, would be to create a filter and do your redirect in it.

Is this the CI4 Way to use a constructor? I had the problem to access the request object in the constructor and got another solution here in the forum. You can call the request class with a service in the __construct method. I don't know if there are problems if the request class is called again in the initController method.


RE: problem with custom controller constructor - includebeer - 06-22-2022

(06-22-2022, 12:54 PM)groovebird Wrote:
(05-29-2021, 12:25 PM)includebeer Wrote: Don't use a constructor. Override initController(), don't forget to call parent::initController(), and then do what you need to do.
But, a better approach, would be to create a filter and do your redirect in it.

Is this the CI4 Way to use a constructor? I had the problem to access the request object in the constructor and got another solution here in the forum. You can call the request class with a service in the __construct method. I don't know if there are problems if the request class is called again in the initController method.

No, it's not the CI4 way to use a constructor. The problem is you're trying to access objects that are not yet initialized. The request object is available after initController() has run. The constructor is too early in the cycle. Look at the code in the BaseController for an example. You need to override the initController method, call its parent, then do what you want after that.
PHP Code:
    /**
    * Constructor.
    */
    public function initController(RequestInterface $requestResponseInterface $responseLoggerInterface $logger)
    {
        // Do Not Edit This Line
        parent::initController($request$response$logger);

        // Preload any models, libraries, etc, here.

        // E.g.: $this->session = \Config\Services::session();
    



RE: problem with custom controller constructor - groovebird - 06-22-2022

Using a __construct seems to me a bit more normal but in CI4 i think there is no other way.


RE: problem with custom controller constructor - kenjis - 06-22-2022

Why do you want to use __construct() in Controllers?

Don't use __construct() in Controllers.
It is generally bad practice and you will have more problems like this.

See https://codeigniter4.github.io/CodeIgniter4/extending/basecontroller.html#preloading-components