Welcome Guest, Not a member yet? Register   Sign In
Codeigniter 4 extend core class process clarification
#1

(This post was last modified: 04-08-2024, 12:10 PM by Semsion.)

An attempt has been made to extend the Codeigniter framework Session class and override function get, instead of replacing the whole Session class /  library. This was by following the guide at https://www.codeigniter.com/user_guide/e...re-classes



Steps taken:



- A new class has been created at `app/Libraries/Session.php`

  - Points of note in this file

    - Added a new namespace: `namespace App\Libraries;`.

    - Pulled in the Codeigniter framework Session class: `use CodeIgniter\Session\Session as BaseSession;`.

    - Extended this class in the function head `class Session extends BaseSession`.

    - Called the parent constructor (not sure if this is required):

      - ```public function __construct()  { parent::__construct($this->driver, $this->config);}```

    - Created a function with the same name `public function get` to override the framework version.

    - As suggested via https://www.codeigniter.com/user_guide/e...re-classes went to the previous section on the same page https://www.codeigniter.com/user_guide/e...re-classes and performed the steps as below:

      - Ensured the Autoload.php could find the namespace App\Libraries (confirmed via `php spark namespaces`).

      - An assumption has been made the interface will be implemented by extending the parent class, that implements the interface.

      - It’s not clear what is meant by `and modify the appropriate Service to load your class in place of the core class.`

        - As adding the below to `app/Config/Services.php` didn’t appear to do anything, another assuption was made that a new Services.php file might need to be created at `app/Libraries/Config/Services.php` (see below also) - as per https://www.codeigniter.com/user_guide/e...re-classes;  however it’s not clear if the content of the class(es) is correct.



PHP Code:
<?php

// app/Config/Services.php

namespace Config;

use 
CodeIgniter\Config\BaseService;

class 
Services extends BaseService
{
    public static function get($getShared true)
    {
        if ($getShared) {
            return static::getSharedInstance('get');
        }
        return new \App\Libraries\Session();
    }


PHP Code:
<?php

// app/Libraries/Config/Services.php

namespace Libraries\Config;

use 
CodeIgniter\Config\BaseService;

class 
Services extends BaseService
{
    public static function get($getShared true)
    {
        if ($getShared) {
            return static::getSharedInstance('get');
        }
        return new \App\Libraries\Session();
    }


- The file located at vendor/codeigniter4/framework/system/Config/Services.php has not been modified.


- `var_dump('Session_get');die;` has been added to  `app/Libraries/Session.php` but is not being hit.


Can anyone possibly assist here please?!
Reply
#2

(This post was last modified: 04-08-2024, 03:16 PM by kenjis.)

You are confusing.

The following code defines a new service named "get".
It does not extend Session::get().

PHP Code:
// app/Config/Services.php

namespace Config;

use 
CodeIgniter\Config\BaseService;

class 
Services extends BaseService
{
    public static function get($getShared true)
    {
        if ($getShared) {
            return static::getSharedInstance('get');
        }
        return new \App\Libraries\Session();
    }


See https://www.codeigniter.com/user_guide/e...he-service
Reply
#3

(This post was last modified: 04-09-2024, 09:37 AM by Semsion.)

Thank you for your response, but the new session file / function still isn't being hit. Please see the changes made below and advise if you meant another way.

app/Libraries/Session.php is now just a clone of vendor/codeigniter4/framework/system/Session/Session.php - but with the namespace App\Libraries, and some debug added for testing (a var_dump in the get function, triggered by running vendor/bin/phpunit in the terminal, which calls get() via a unit test).

app/Config/Services.php now looks like the below (the forum code formatter appears broken on responses):

PHP Code:
namespace Config;

 use 
CodeIgniter\Config\BaseService;
 
// use App\Libraries\Session;
 
use Config\Session as SessionConfig;
 use 
Config\Services as AppServices;
 use 
CodeIgniter\Session\Handlers\DatabaseHandler;
 use 
CodeIgniter\Session\Handlers\Database\MySQLiHandler;
 use 
CodeIgniter\Session\Handlers\Database\PostgreHandler;

 class 
Services extends BaseService
 
{
 public static function 
get($getShared true)
 {
 if (
$getShared) {
 return static::
getSharedInstance('get');
 }

 
$config ??= config(SessionConfig::class);

 
$logger AppServices::logger();

 
$driverName $config->driver;

 if (
$driverName === DatabaseHandler::class) {
 
$DBGroup $config->DBGroup ?? config(Database::class)->defaultGroup;
 
$db Database::connect($DBGroup);

 
$driver $db->getPlatform();

 if (
$driver === 'MySQLi') {
 
$driverName MySQLiHandler::class;
 } elseif (
$driver === 'Postgre') {
 
$driverName PostgreHandler::class;
 }
 }

 
$driver = new $driverName($configAppServices::request()->getIPAddress());
 
$driver->setLogger($logger);

 return new \
App\Libraries\Session($driver, new SessionConfig());
 } 
Reply
#4

It seems you don't get what a method name is in Services class.

If you want to replace `session` service, you need to add the session() method in Config\Services.
But you added the get() method. It means you added `get` service.
Reply
#5

(This post was last modified: 04-11-2024, 05:09 AM by Semsion.)

Ok thank you yes; the function name needed changing.

After forcing the function parameter to false for $getShared, for testing purposes, an error is returning as:

Code:
1) ExampleSessionTest::testSessionSimple
ErrorException: ini_set(): Session ini settings cannot be changed after headers have already been sent

/home/andyf/Git-Sandbox/codeigniter4Test/vendor/codeigniter4/framework/system/Session/Handlers/FileHandler.php:72
/home/andyf/Git-Sandbox/codeigniter4Test/app/Config/Services.php:70
/home/andyf/Git-Sandbox/codeigniter4Test/tests/session/ExampleSessionTest.php:13

This appears to be because of the method call `ini_set('session.save_path', $this->savePath);` in FileHandler.php:72

Do we have any idea how this can be resolved?!
Reply
#6

Testing Session is difficult. Because Session does not work in CLI.
So if you are not an expert, I recommend you test via web.

CI4 provides MockSession for PHPUnit testing.
So if you replace Session, you need to create your MockSession,
and a feature to use your MockSession in your test case.
See https://github.com/codeigniter4/CodeIgni...#L332-L343
Reply
#7

(This post was last modified: 04-15-2024, 09:39 AM by Semsion.)

Ok, thank you - will continue to test via the web. This is fine as the main route also creates a session.

The current issue is that with the new replacement app/Config/Services.php, which eventually hits `$this->logger->info("Session: Class initialized using '" . $this->config->driver . "' driver.");` inside of vendor/codeigniter4/framework/system/Session/Session.php or it's new replacement (clone) app/Libraries/Session.php - if either of these Session.php files are used (from the new app/Config/Services.php file) (see below) The web page is throwing an error as null: `Call to a member function info() on null`.

PHP Code:
<?php

// app/Config/Services.php

namespace Config;

use 
CodeIgniter\Config\BaseService;
use 
CodeIgniter\Session\Session;
use 
Config\Session as SessionConfig;
use 
Config\Services as AppServices;
use 
CodeIgniter\Session\Handlers\DatabaseHandler;
use 
CodeIgniter\Session\Handlers\Database\MySQLiHandler;
use 
CodeIgniter\Session\Handlers\Database\PostgreHandler;

/**
 * Services Configuration file.
 *
 * Services are simply other classes/libraries that the system uses
 * to do its job. This is used by CodeIgniter to allow the core of the
 * framework to be swapped out easily without affecting the usage within
 * the rest of your application.
 *
 * This file holds any application-specific services, or service overrides
 * that you might need. An example has been included with the general
 * method format you should use for your service methods. For more examples,
 * see the core Services file at system/Config/Services.php.
 */
class Services extends BaseService
{
 public static function 
session($getShared true)
 {
 if (
$getShared) {
 return static::
getSharedInstance('session');
 }

 
$config ??= config(SessionConfig::class);

 
$logger AppServices::logger();

 
// var_dump($logger);die;

 
$driverName $config->driver;

 if (
$driverName === DatabaseHandler::class) {
 
var_dump('DatabaseHandler');die;
 
$DBGroup $config->DBGroup ?? config(Database::class)->defaultGroup;
 
$db      Database::connect($DBGroup);

 
$driver $db->getPlatform();

 if (
$driver === 'MySQLi') {
 
$driverName MySQLiHandler::class;
 } elseif (
$driver === 'Postgre') {
 
$driverName PostgreHandler::class;
 }
 }

 
$driver = new $driverName($configAppServices::request()->getIPAddress());
 
$driver->setLogger($logger);

 
//$session = new \App\Libraries\Session($driver, new SessionConfig());
 
$session = new Session($driver$config);

 if (
session_status() === PHP_SESSION_NONE) {
 
$session->start();
 }

 return 
$session;
 }
 
 } 
Reply
#8

The error message tells that $this->logger is null.
But if you set Logger, it should not be null.
I don't know why you get the error.
Reply
#9

(This post was last modified: 04-17-2024, 05:29 AM by Semsion.)

Thanks for coming back; the error was because the logger hadn't been set for the session. The error has been resolved now.

It's coming across that the session class / method may not be able to be extended / replaced, at least in any reasonable / simple manner.

The next error is from vendor/codeigniter4/framework/system/Security/Security.php:

TypeError

Cannot assign App\Libraries\Session to property CodeIgniter\Security\Security::$session of type ?CodeIgniter\Session\Session

PHP Code:
SYSTEMPATH/Security/Security.php at line 223

216    
private function isCSRFCookie(): bool
217    
{
218        return $this->config->csrfProtection === self::CSRF_PROTECTION_COOKIE;
219    }
220 
221    
private function configureSession(): void
222    
{
223        $this->session Services::session();
224    }
225 
226    
private function configureCookie(CookieConfig $cookie): void
227    
{
228        $cookiePrefix    $cookie->prefix;
229        $this->cookieName $cookiePrefix $this->rawCookieName;
230        Cookie::setDefaults($cookie); 



UPDATE: Ok, looks like we're finally there! Have extended app/Libraries/Session.php with CodeIgniterSession, but pulling in at the top of this file `use CodeIgniter\Session\Session as CodeIgniterSession`.

This has resolved the previous issue, and we're now able to access this new Session class.
Reply




Theme © iAndrew 2016 - Forum software by © MyBB