Upgrading legacy CodeIgniter 3 application directory structures to CodeIgniter 4 PSR-4 autoloading on Debian 12
Prerequisites and Environment Setup
This guide assumes a Debian 12 (Bookworm) server with a functional LAMP or LEMP stack. Specifically, you’ll need PHP 8.1 or later, Composer installed globally, and root or sudo privileges. We’ll be working within a hypothetical application directory, /var/www/legacy_app. Ensure your existing CodeIgniter 3 application is functional before proceeding with the upgrade.
First, let’s verify our PHP and Composer versions:
sudo apt update && sudo apt upgrade -y php -v composer --version
If Composer is not installed, you can install it via:
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php composer-setup.php
sudo mv composer.phar /usr/local/bin/composer
php -r "unlink('composer-setup.php');"
composer --version
Analyzing the Legacy CodeIgniter 3 Directory Structure
A typical CodeIgniter 3 application has a flat structure within the application/ directory. Key subdirectories include config/, controllers/, models/, views/, and libraries/. CodeIgniter 3 relies on its own autoloader, which is file-based and often requires manual inclusion or the use of APPPATH constants.
Consider a simplified legacy structure:
/var/www/legacy_app/ ├── application/ │ ├── config/ │ │ ├── config.php │ │ └── database.php │ ├── controllers/ │ │ └── Welcome.php │ ├── models/ │ │ └── User_model.php │ ├── views/ │ │ └── welcome_message.php │ └── libraries/ │ └── My_library.php ├── system/ │ └── (CodeIgniter 3 core files) └── index.php
Introducing CodeIgniter 4 and PSR-4 Autoloading
CodeIgniter 4 embraces modern PHP standards, most notably PSR-4 autoloading. This means your application’s classes will be organized into namespaces, and Composer will handle their loading automatically based on directory structure. The typical CI4 structure is flatter and more organized, with a dedicated app/ directory for your application code and a public/ directory for web-accessible files.
The goal is to migrate the contents of application/ into a new app/ directory, adopting namespaces and leveraging Composer’s autoloader. The public/ directory will contain the entry point (index.php) and front-controller related assets.
Step-by-Step Migration Strategy
We will perform this migration in stages, ensuring minimal downtime and allowing for iterative testing.
1. Initializing CodeIgniter 4 Project
Navigate to your application’s root directory and create a new CodeIgniter 4 project using Composer. It’s crucial to do this in a separate directory initially to avoid overwriting your existing application. We’ll then selectively copy over files.
cd /var/www/ composer create-project codeigniter4/appstarter legacy_app_ci4 cd legacy_app_ci4
This command downloads the latest CodeIgniter 4 skeleton into a new directory named legacy_app_ci4. The core structure will look something like this:
/var/www/legacy_app_ci4/ ├── app/ │ ├── Config/ │ ├── Controllers/ │ ├── Database/ │ ├── Filters/ │ ├── Helpers/ │ ├── Language/ │ ├── Libraries/ │ ├── Models/ │ ├── ThirdParty/ │ └── Views/ ├── public/ │ ├── index.php │ ├── robots.txt │ └── .htaccess (or nginx equivalent) ├── writable/ ├── tests/ ├── vendor/ ├── composer.json └── spark
2. Migrating Configuration Files
CodeIgniter 4 uses a dedicated app/Config/ directory. Configuration files are now classes extending CodeIgniter\Config\BaseConfig. We need to adapt our legacy application/config/ files to this new format.
Copy your legacy configuration files (e.g., config.php, database.php) into the new app/Config/ directory. Then, refactor them into CI4 configuration classes. For example, application/config/config.php might become app/Config/App.php.
Example: Migrating application/config/config.php to app/Config/App.php
Legacy application/config/config.php (simplified):
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
$config['base_url'] = 'http://localhost/legacy_app/';
$config['index_page'] = '';
$config['uri_protocol'] = 'REQUEST_URI';
// ... other configurations
?>
New app/Config/App.php:
<?php
namespace Config;
use CodeIgniter\Config\BaseConfig;
class App extends BaseConfig
{
/**
* @var string
*/
public $baseURL = 'http://localhost/legacy_app/'; // Note: This will be overridden by environment variables or public/.htaccess
/**
* @var string
*/
public $indexPage = '';
/**
* @var string
*/
public $uriProtocol = 'REQUEST_URI';
/**
* @var string
*/
public $defaultLocale = 'en';
/**
* @var bool
*/
public $negotiateLocale = false;
/**
* @var array
*/
public $supportedLocales = ['en'];
// ... other configurations mapped to public properties
}
?>
Similarly, refactor application/config/database.php into app/Config/Database.php. Pay close attention to the structure of the $default and $backup arrays in CI4’s Database.php.
Example: Migrating application/config/database.php to app/Config/Database.php
Legacy application/config/database.php (simplified):
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
$db['default'] = array(
'dsn' => '',
'hostname' => 'localhost',
'username' => 'root',
'password' => '',
'database' => 'legacy_db',
'dbdriver' => 'mysqli',
'dbprefix' => '',
'pconnect' => FALSE,
'db_debug' => (ENVIRONMENT !== 'production'),
'cache_on' => FALSE,
'cachedir' => '',
'char_set' => 'utf8',
'dbcollat' => 'utf8_general_ci',
'swap_pre' => '',
'encrypt' => FALSE,
'compress' => FALSE,
'stricton' => FALSE,
'failover' => array(),
'save_queries' => TRUE
);
?>
New app/Config/Database.php:
<?php
namespace Config;
use CodeIgniter\Database\Config\BaseConfig;
class Database extends BaseConfig
{
/**
* @var string
*/
public $defaultGroup = 'default';
/**
* @var array
*/
public $default = [
'DSN' => '',
'hostname' => 'localhost',
'port' => '',
'database' => 'legacy_db',
'username' => 'root',
'password' => '',
'DBDriver' => 'MySQLi', // Note: Case sensitivity and driver name
'dbprefix' => '',
'pConnect' => false,
'DBDebug' => (ENVIRONMENT !== 'production'),
'cacheOn' => false,
'cacheDir' => '',
'charset' => 'utf8',
'DBCollat' => 'utf8_general_ci',
'swapPre' => '',
'encrypt' => false,
'compress' => false,
'strictOn' => false,
'failover' => [],
'modes' => [],
' குற்றச்சாட்டுகள்' => [], // Example of a potential typo in legacy, corrected here
'saveQueries' => true,
];
// ... other database groups if any
}
?>
3. Migrating Controllers, Models, and Libraries
This is the core of the migration. CodeIgniter 4 uses namespaces extensively. Your controllers, models, and libraries need to be placed in their respective directories within app/ and assigned appropriate namespaces.
Controllers:
Legacy application/controllers/Welcome.php:
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
class Welcome extends CI_Controller {
public function index()
{
$this->load->view('welcome_message');
}
}
?>
Migrated app/Controllers/Home.php (CI4 convention uses Home for the default controller):
<?php
namespace App\Controllers;
class Home extends BaseController
{
public function index()
{
return view('welcome_message'); // CI4 uses view() helper or $this->render()
}
}
?>
Models:
Legacy application/models/User_model.php:
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
class User_model extends CI_Model {
public function get_user($id)
{
$this->db->where('id', $id);
$query = $this->db->get('users');
return $query->row();
}
}
?>
Migrated app/Models/UserModel.php:
<?php
namespace App\Models;
use CodeIgniter\Model;
class UserModel extends Model
{
protected $table = 'users';
protected $primaryKey = 'id';
protected $allowedFields = ['name', 'email']; // Example
// CI4 uses a different API for querying
public function getUser($id)
{
return $this->where('id', $id)->first();
}
}
?>
Libraries:
Legacy application/libraries/My_library.php:
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
class My_library {
public function do_something() {
return "Hello from legacy library!";
}
}
?>
Migrated app/Libraries/MyLibrary.php:
<?php
namespace App\Libraries;
class MyLibrary
{
public function doSomething() {
return "Hello from CI4 library!";
}
}
?>
Important Notes on Migration:
- Namespaces: Ensure all your migrated classes have the correct namespace (e.g.,
App\Controllers,App\Models,App\Libraries). - Base Classes: Controllers should extend
\App\Controllers\BaseController, and Models should extend\CodeIgniter\Model. - Autoloading: Composer will handle autoloading for classes within the
app/directory based on theAppnamespace. - File Naming: CI4 conventions often use CamelCase for class names (e.g.,
User_model.phpbecomesUserModel.php). - API Changes: Many CI3 methods have changed. For example,
$this->load->model('User_model')becomes$userModel = new \App\Models\UserModel();or using the model factory. Database queries use a fluent builder API.
4. Updating the Entry Point and Web Server Configuration
The public/ directory in CI4 is the new web root. The index.php file here is the front controller.
Copy your legacy index.php and .htaccess (if Apache) or configure your Nginx server block to point the document root to the new public/ directory.
New public/index.php (from CI4 starter):
<?php
//--------------------------------------------------------------------
// App Initialization
//--------------------------------------------------------------------
// The path to the application directory.
$appPath = __DIR__ . '/../app';
// The path to the front controller (this file).
define('FCPATH', __DIR__ . DIRECTORY_SEPARATOR);
// The path to the system directory.
define('SYSTEMPATH', __DIR__ . '/../system'); // Note: CI4 system is in vendor/codeigniter4/framework/system
// The path to the writable directory.
define('WRITEPATH', __DIR__ . '/../writable');
// The path to the public directory.
define('PUBLICPATH', __DIR__ . DIRECTORY_SEPARATOR);
/*
*---------------------------------------------------------------
* BOOTSTRAP THE APPLICATION
*---------------------------------------------------------------
* This process sets up the path constants, loads the
* application's drivers, and sets the true root path.
*/
$bootstrap = require rtrim($appPath, '/ ') . '/bootstrap.php';
/*
*---------------------------------------------------------------
* LAUNCH THE APPLICATION
*---------------------------------------------------------------
*/
$app = \Config\Services::app();
// Activate filters
$app->run();
?>
Apache Configuration (/etc/apache2/sites-available/legacy_app.conf):
<VirtualHost *:80>
ServerAdmin webmaster@localhost
DocumentRoot /var/www/legacy_app_ci4/public
<Directory /var/www/legacy_app_ci4/public>
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/$1 [L]
</Directory>
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
Enable the site and rewrite module:
sudo a2ensite legacy_app.conf sudo a2enmod rewrite sudo systemctl reload apache2
Nginx Configuration (/etc/nginx/sites-available/legacy_app):
server {
listen 80;
server_name your_domain.com; # Or localhost
root /var/www/legacy_app_ci4/public;
index index.php index.html index.htm;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php8.1-fpm.sock; # Adjust PHP version if necessary
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
location ~ /\.ht {
deny all;
}
}
Enable the site and test Nginx configuration:
sudo ln -s /etc/nginx/sites-available/legacy_app /etc/nginx/sites-enabled/ sudo nginx -t sudo systemctl reload nginx
5. Composer Autoloading and Environment Variables
After migrating files and updating configurations, run Composer’s dump-autoload command to ensure the autoloader is up-to-date.
cd /var/www/legacy_app_ci4 composer dump-autoload
CodeIgniter 4 heavily relies on environment variables for configuration, especially for sensitive data like database credentials. The .env file in the project root is used for this. Copy your legacy database credentials and other environment-specific settings into .env.
Example .env file:
[app] baseURL = 'http://localhost/legacy_app_ci4/' # ... other app settings [database] default.database = 'legacy_db' default.username = 'root' default.password = '' default.DBDriver = 'MySQLi' # ... other database settings [mail] # ... mail settings
Ensure the .env file is correctly referenced in public/index.php and app/bootstrap.php. The starter project usually handles this.
6. Testing and Debugging
With the basic structure in place, it’s time for thorough testing. Enable detailed error reporting in your development environment by setting CI_ENVIRONMENT = 'development' in your .env file.
Common Issues and Debugging Steps:
- 404 Errors: Verify your web server’s document root points to the
public/directory and that rewrite rules are correctly configured. Checkapp/Config/App.phpforbaseURLandindexPage. - Class Not Found Errors: Double-check namespaces and file paths. Ensure
composer dump-autoloadhas been run. Verify the PSR-4 mapping invendor/composer/autoload_psr4.json. - Database Connection Errors: Confirm credentials in
.envandapp/Config/Database.phpare correct. Check theDBDrivername (e.g., ‘MySQLi’ vs ‘mysqli’). - View Rendering Issues: Ensure views are in
app/Views/and are being called correctly using theview()helper or$this->render(). - Helper Function Not Found: CI4 has a different set of built-in helpers. You may need to load them explicitly in your controller’s constructor or in
app/Config/Autoload.php. - Session Issues: CI4 has a new session library. Ensure it’s configured in
app/Config/Session.phpand loaded correctly.
Use the CodeIgniter 4 Debug Toolbar for invaluable insights into requests, database queries, and errors during development.
Post-Migration Considerations
Once the application is running on CodeIgniter 4, consider these points:
- Security: Review CI4’s security features, such as CSRF protection, input filtering, and escaping output.
- Performance: Optimize database queries, leverage caching, and profile your application.
- Testing: Implement unit, feature, and integration tests using PHPUnit, which is integrated with CodeIgniter 4.
- Deployment: Adapt your deployment scripts to handle Composer dependencies and the new directory structure.
- Code Refactoring: Gradually refactor legacy code to take full advantage of CI4’s features and modern PHP practices.
This comprehensive approach to migrating from CodeIgniter 3’s directory structure to CodeIgniter 4’s PSR-4 autoloading on Debian 12 provides a robust foundation for modernizing your legacy application.
Leave a Reply
You must be logged in to post a comment.