Porting a fully functional legacy Symfony 1.4 application to PHP 7.2

Porting a fully functional legacy Symfony 1.4 application to PHP 7.2

Yeah i know, why the hell would i work with such an old framework like Symfony 1.4 when we are right now in the Symfony 5 version. The reason is simple, money. However only someone that works in a company with a very important and complex project understand how deep this conjecture is, not every company would be able to pay for a new port of an old project to a new one that uses the latest technologies.

However, as a programmer that loves to work with the latest stuff, i keep looking for a better way to do things. In some old post, we wrote how to provide support for PHP 5.5+ in your Symfony 1.4 project (considering that symfony 1.4 was meant to run on PHP 5.3, it was a huge advance till then btw). However, the mentioned support broke with the introduction of PHP 7, if you decided to run a Symfony 1.4 project in the mentioned version of PHP, you would only see a big disaster.

Fortunately, there's still a bunch of people like you and me that needs to support this kind of project. The guys at FriendsOfSymfony1 decided to expand the Symfony 1 lifespan through some enhancements (all of them are listed in the WHATS_NEW file) that are:

The project is quite understandable and according to the way you work, the installation may be different, however in this article we will explain you what we did to get one of our old Symfony 1.4 projects working with PHP 7.

1. Prepare original project files

As shown in the following treeview, our original project of Symfony 1.4, that works in PHP 5.6 looks like this:

original_project/
├── apps/
├── cache/
├── Check.php
├── check_configuration.php
├── config/
├── data/
├── lib/
├── log/
├── nbproject/
├── package.xml
├── plugins/
├── symfony
├── symfony-1.4.27/
├── test/
├── trunk/
└── web/

The project works quite well, if we serve the project through a web server for PHP 5.6 pointing to the web directory, it will run without any issue:

Symfony 1.4 project running

Now that we know that the project works, create a security copy of everything and remove the symfony-1.4.27 directory from your project as we won't use this version anymore.

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 project directory:

composer init

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

{
    "name": "ourcodeworld/projectname",
    "type": "project",
    "authors": [
        {
            "name": "Your Name",
            "email": "youremail@youremail.com"
        }
    ],
    "require": {
        
    }
}

Note that till this point there is no autoloader file that you can include in your project nor 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 7.2

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

composer require lexpress/symfony1 "1.5.*"

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

new_project/
├── apps/
├── cache/
├── Check.php
├── check_configuration.php
├── config/
├── data/
├── lib/
├── log/
├── nbproject/
├── package.xml
├── plugins/
├── symfony
├── test/
├── trunk/
├── vendor/
└── web/

As you can see, we have something special now which is the vendor directory that exists because we provided manually composer support for Symfony 1.4 (we wrote about how to provide support for composer in Symfony 1.4 in this article) and that's what we did on the first steps.

4. Install the ORM

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

composer require lexpress/doctrine1

If you used Propel instead, then you can install propel with the following one:

composer require propel/sf-propel-o-r-m-plugin

After installing the ORM, most of the stuff in your project may work now, however we still need to configure your old project to use the new version of Symfony.

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):

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

You need to change that, instead you will only need to use the composer autoload from the vendor directory like this:

<?php

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

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

sfCoreAutoload::register();

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

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

Symfony 1.5

6. Running commands

Finally, in case that you want to know how to run commands in Symfony 1.4, we used to run the commands like this (which should work btw):

php symfony cc

As the symfony binary was usually in the root directory of the project, however if that binary isn't working, you can use the symfony binary from the vendor directory like this:

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

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 and 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\lexpress\symfony1\lib\validator\sfValidatorBase.class.php(327): sfGuardValidatorUser->doClean(Array) 
#2 \vendor\lexpress\symfony1\lib\validator\sfValidatorSchema.class.php(254): sfValidatorBase->clean(Array) 
#3 \vendor\lexpress\symfony1\lib\validator\sfValidatorSchema.class.php(192): sfValidatorSchema->postClean(Array) 
#4 \vendor\lexpress\symfony1\lib\validator\sfValidatorSchema.class.php(90): sfValidatorSchema->doClean(Array) 
#5 \vendor\lexpress\symfony1\lib\form\sfForm.class.php(259): sfValidatorSchema->clean(Array) 
#6 \vendor\lexpress\symfony1\lib\form\addon\sfFormSymfony.class.php in \plugins\sfDoctrineGuardPlugin\lib\validator\sfGuardValidatorUser.class.php on line 67

The solution is quite simple, as the exception shows, the Doctrine class doesn't exists even though the doctrine package has been installed using composer, this happens because the class should be Doctrine_Core, so replacing all the Doctrine instances should fix the issue.

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

The following warning will appear globally on your project:

Warning: ini_set(): A session is active. You cannot change the session module's ini settings at this time in project\vendor\lexpress\symfony1\lib\user\sfBasicSecurityUser.class.php on line 257

This can be solved by simply increasing the session.gc_maxlifetime property in your php.ini file to at least 3600, you may increase it according to your needs:

; After this number of seconds, stored data will be seen as 'garbage' and
; cleaned up by the garbage collection process.
; http://php.net/session.gc-maxlifetime
session.gc_maxlifetime=3600

3. Your own code

Of course you will need as well 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 ❤️!

References and external resources

This could interest you

Become a more social person