Welcome Guest, Not a member yet? Register   Sign In
problem with custom controller constructor
#1

(This post was last modified: 05-29-2021, 10:59 AM by tino.)

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...
Reply
#2

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.
CodeIgniter 4 tutorials (EN/FR) - https://includebeer.com
/*** NO support in private message - Use the forum! ***/
Reply
#3

(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.
Reply
#4

Myth/Auth AuthController uses the __construct() and passes service objects. for sessions etc.
What did you Try? What did you Get? What did you Expect?

Joined CodeIgniter Community 2009.  ( Skype: insitfx )
Reply
#5

math auth has filter use it
Enlightenment  Is  Freedom
Reply
#6

(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); 
CodeIgniter 4 tutorials (EN/FR) - https://includebeer.com
/*** NO support in private message - Use the forum! ***/
Reply
#7

(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.
Reply
#8

(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();
    
CodeIgniter 4 tutorials (EN/FR) - https://includebeer.com
/*** NO support in private message - Use the forum! ***/
Reply
#9

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

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/CodeIgnit...components
Reply




Theme © iAndrew 2016 - Forum software by © MyBB