Learn how to upgrade a Symfony 1.4 application to be compatible with PHP 8.2

Porting a fully functional legacy Symfony 1.4 application to PHP 8.2

Don't even try to run a Symfony 1.4 project on PHP 8 on your server, if you do, you will find plenty of deprecations and for sure a Fatal error that will stop the project from working, even if the project is empty:

Symfony 1.4 on PHP 8.2

And it's quite important to mention, that this is only the code related to the framework itself! Your own code might be incompatible with PHP 8.2 as well. PHP has gone through a thorough optimization since that version, new features were included such as a significant performance boost, improvements in error handling, and other important features such as match expressions, named arguments, union types, etc.

Upgrading a project from a very old version of PHP is certainly not an easy task, it will take time, having a codebase with unit testing will definitely help you out with that, but in case you don't have such a tool to your disposition, don't be afraid and take just a step at a time. Just like the thing we are going to teach you today, which is basically the upgrade of the Symfony framework itself to be compatible with PHP 8.2. This will not guarantee that your project will work out of the box with just the upgrade of the framework because as I mentioned before, this is going to depend on your project codebase. But it's definitely an important step when trying to make your old Symfony 1.4-based application compatible with PHP 8.2.

Important note before upgrading to 8.2

It's recommended to upgrade sequentially from PHP 5.6 to PHP 7.2 and finally to PHP 8.2 as it will be easier for you to debug the project later and make your own code compatible with PHP 8.2 (but this is merely a personal recommendation, for the Symfony framework code is easily interchangeable, yet your apps/ code won't be, so please keep that in mind when doing the upgrade). We wrote a year ago about how to upgrade a Symfony 1.4-based project to work with PHP 7.2 here, so be sure to check it out before following this tutorial.

Having said that, let's get started with the upgrade.

1. Prepare original project files

As shown in the following Treeview, our original project of Symfony 1.4, which works in PHP 7.2 looks like this:

project/
├── Check.php
├── apps/
├── cache/
├── check_configuration.php
├── composer.json
├── composer.lock
├── config/
├── data/
├── lib/
├── log/
├── nbproject
├── package.xml
├── plugins/
├── readme.textile
├── sandbox.py
├── symfony-1.4.27
├── test/
├── trunk/
└── web/

The project works properly in PHP 5.6 with the original structure. To make it fully compatible with PHP 8.2, we need to tweak some stuff.

2. Create a composer.json file

The project should work with composer from now on, proceed to create a new composer file using the following command in the root directory of your project:

composer init

Or alternatively, create it manually with at least the following structure:

{
    "name": "ourcodeworld/projectname",
    "type": "project",
    "authors": [
        {
            "name": "Your Name",
            "email": "[email protected]"
        }
    ],
    "require": {
        
    }
}

Note that till this point there is no autoloader file that you can include in your project or composer.lock file. To create the autoloader, you will need to install the first library that you need (Symfony itself).

3. Install Symfony 1.4 with support for PHP 8.2

The new version of Symfony that supports PHP 8.2 will be Symfony 1.5 which is unofficially maintained by the guys at FriendsOfSymfony1, can be installed with the following command:

composer require friendsofsymfony1/symfony1 "1.5.*"

After installing Symfony 1.4 you will now have the following project structure:

project/
├── Check.php
├── apps/
├── cache/
├── check_configuration.php
├── composer.json
├── composer.lock
├── config/
├── data/
├── lib/
├── log/
├── nbproject
├── package.xml
├── plugins/
├── readme.textile
├── sandbox.py
├── symfony-1.4.27
├── test/
├── trunk/
├── vendor/
└── web/

4. Install the ORM

In Symfony 1.4 you were able to use Doctrine or Propel as ORM, so in case your project uses Doctrine 1, you can install it with the following command:

composer require friendsofsymfony1/doctrine1

It's compatible with PHP 8.2 so you shouldn't have any problem with this package.

5. Configuring your project to use the new Symfony

Now, in the old Symfony project, on the ProjectConfiguration.class.php file, specifically located at the project/config directory, you will find the line that imports the autoload of Symfony 1.4 (sfCoreAutoload.class.php):

<?php

require_once dirname(__FILE__) . '/../symfony-1.4.27/lib/autoload/sfCoreAutoload.class.php';

You need to update it, so instead of loading the old Symfony autoload, it will load the autoload file of composer:

<?php

// File: myproject/config/ProjectConfiguration.class.php

// 1. Use the autoload file of Composer
require_once dirname(__FILE__) . '/../vendor/autoload.php';

sfCoreAutoload::register();

class ProjectConfiguration extends sfProjectConfiguration 
{
    // .... 
    // Your code 
}

After saving the changes in the file, your application should be able to run on a PHP 8.2 environment:

Symfony 1.4 running on PHP 8.2

6. Running commands

Finally, in case you want to know how to run commands in Symfony 1.4, stuff like cleaning the cache, doing reverse engineering, building the models from the schema, or generating the schema itself, you need to know that the binary path has changed. It is located now in the vendor directory, inside the data/bin directory of Symfony 1.4. For example, to clean the cache of your project you can simply run the following command:

php vendor/friendsofsymfony1/symfony1/data/bin/symfony cc

Which is going to generate an output similar to the following one:

>> cache     Clearing cache type "all" for "frontend" app and "prod" env
>> file+     /var/www/html/data/frontend_prod-cli.lck
>> chmod 777 /var/www/html/data/frontend_prod-cli.lck
>> file-     /var/www/html/cache/frontend/prod/config/config_factories.yml.php
>> file-     /var/www/html/cache/frontend/prod/config/modules_myapp_config_module.yml.php
>> file-     /var/www/html/cache/frontend/prod/config/modules_myapp_config_module.yml.php
>> file-     /var/www/html/cache/frontend/prod/config/config_autoload.yml.php
>> file-     /var/www/html/cache/frontend/prod/config/modules_global_components_config_security.yml.php
>> file-     /var/www/html/cache/frontend/prod/config/modules_myapp_config_module.yml.php
>> file-     /var/www/html/cache/frontend/prod/config/modules_myapp_config_security.yml.php
>> file-     /var/www/html/cache/frontend/prod/config/config_core_compile.yml.php
>> file-     /var/www/html/cache/frontend/prod/config/config_services.yml.php
>> file-     /var/www/html/cache/frontend/prod/config/config_databases.yml.php
>> file-     /var/www/html/cache/frontend/prod/config/modules_myapp_config_filters.yml.php
>> file-     /var/www/html/cache/frontend/prod/config/config_settings.yml.php
>> file-     /var/www/html/cache/frontend/prod/config/modules_myapp_config_view.yml.php
>> file-     /var/www/html/cache/frontend/prod/config/modules_myapp_config_security.yml.php
>> file-     /var/www/html/cache/frontend/prod/config/modules_myapp_config_view.yml.php
>> file-     /var/www/html/cache/frontend/prod/config/modules_myapp_config_security.yml.php

Common must-fixes

After implementing the basic upgrade, there will be some things that you need to fix as well.

1. Use Doctrine_Core instead of Doctrine

There are some cases where an old naming convention may lead to exceptions like the following one:

Fatal error: Uncaught Error: Class 'Doctrine' not found in \plugins\sfDoctrineGuardPlugin\lib\validator\sfGuardValidatorUser.class.php:67 
Stack trace: #0 \plugins\sfDoctrineGuardPlugin\lib\validator\sfGuardValidatorUser.class.php(44): sfGuardValidatorUser->getTable() 
#1 \vendor\friendsofsymfony\symfony1\lib\validator\sfValidatorBase.class.php(327): sfGuardValidatorUser->doClean(Array) 
#2 \vendor\friendsofsymfony\symfony1\lib\validator\sfValidatorSchema.class.php(254): sfValidatorBase->clean(Array) 
#3 \vendor\friendsofsymfony\symfony1\lib\validator\sfValidatorSchema.class.php(192): sfValidatorSchema->postClean(Array) 
#4 \vendor\friendsofsymfony\symfony1\lib\validator\sfValidatorSchema.class.php(90): sfValidatorSchema->doClean(Array) 
#5 \vendor\friendsofsymfony\symfony1\lib\form\sfForm.class.php(259): sfValidatorSchema->clean(Array) 
#6 \vendor\friendsofsymfony\symfony1\lib\form\addon\sfFormSymfony.class.php in \plugins\sfDoctrineGuardPlugin\lib\validator\sfGuardValidatorUser.class.php on line 67

2. Increase session.gc_maxlifetime

There are other regular exceptions, for example when trying to increase the session timeout on the factories.yml of your project:

# You can find more information about this file on the symfony website:
# https://symfony.com/legacy/doc/reference/1_4/en/05-Factories

# ...

all:
  # ...

  # ...

  user:
    class: myUser
    param:
      timeout: 21600

3. Your own code

Of course, you will need to upgrade your deprecated code, the one that doesn't belong to the Symfony 1.4 core but to your controllers, templates, and tasks.

Happy coding ❤️!


Senior Software Engineer at Software Medico. Interested in programming since he was 14 years old, Carlos is a self-taught programmer and founder and author of most of the articles at Our Code World.

Sponsors