Integrating ZF into a legacy app

Why doing that ?

No matter how neat or good looking code you write at some point, inevitably there’s a time when new coding technologies or frameworks will emerge. This moment can occur after one or two or even more years the project was initially started. Along this time, business logic was added to your product/application, bugs were fixed which brought the application at a more stable and mature level.

Redo everything vs. bring in that “something”

At this point you will face a decision: drop everything you did and redo it on the new framework or technology or find a way to bring that technology into the current set-up. The first options seems very attractive (when it comes to engineers) as it gives you the chance to start from scratch, on a new technology (much better and faster in terms of development) and you finally have the opportunity to avoid the mistakes you did in the prior implementation. And you start working for several weeks or months and you suddenly realize that low or no progress was made. You spent all that time for making the very basics setup of the app (login, registration, listings, access control,etc) while very little business logic was added. Before choosing that option, you might want to take a look at the things you should never do when designing software.

That is why one should carefully consider the second option:  bring that “something new” into the current code base. Our something was Zend Framework. The project in discussion is over 6 years old and it was initially started on PHP 4.x and eventually ported to 5.3.x. It contains a mix of procedural and object oriented code with different programming techniques and with the usual functionality redundancy (multiple functions doing the same thing) often associated with old and large projects.

We wanted ZF to boost the development process, to leverage the numerous components and integrations the framework provides, but to also increase the developers motivation (which is a very important thing). The most important aspect we took care of, was to be as less intrusive as we could, so the old code to remain un-touched while allowing the new structure to be deployed as smooth as possible.

ZF integration considerations

The main integration points that needed our attention were: request routing, user authentication and access control (ACLs). Each one has its own story so I will briefly describe them below.

Request routing

This is the part where we actually injected ZF into the old code. Our application worked on plain URLs like some-page.html or some-module–page.html and, very important, we had a single entry point for all the requests. What we did was to add an identifier in URL signature so we can know when to load the ZF based environment. The URL from above became something like /zf/some-module/some-page.html, where “zf’ is the magic word that triggers the framework.

The code behind the scenes is very simple and it actually loads Zend_Application just like you would do in /public/index.php file of a regular ZF app.

if(strpos($_SERVER['REQUEST_URI'], 'zf') !== false) {
    $config = new Zend_Config_Ini('\path\to\application.ini', APPLICATION_ENV, true);
    Zend_Registry::set('application.config', $config);

    $application = new Zend_Application(APPLICATION_ENV, $config);
    $application->bootstrap()->run();
    exit();
}

User authentication

Once the framework loading problem was addressed, we’ve moved on to the next issue: integrating old user authentication system into ZF. This means that the ZF code to “understand” where the user got authenticated in the old app, because the authentication remained (and it will still remain) under the old code structure.

We did this by creating a custom Zend_Auth_Storage_Session class that could simply read key/values pairs straight from the $_SESSION array ($_SESSION[‘session-key’]). Like you know, ZF stores session based data in namespaces ($_SESSION[‘name-space-name’][‘session-key’]) so, with the defalut session storage you have no way of reading the old application session data.

The new storage class we created is attached here and below you will see how the new storage was used, in Bootsrap.php:

public function _initCustomSessionStorage() {
        Zend_Auth::getInstance()->setStorage(
	    new ZFWeb_Auth_Storage_CustomSession('session_key_name'));
}

ACL

The control list implementation is straight forward as the role access per pages are stored in a database table. Hence we’ve created a custom ACL class to extend Zend_Acl which overwrites the isAllowed method. Here we simply delegate to a model the user check.

class ZFWeb_Acl_CustomAcl extends Zend_Acl {
	public function isAllowed($_role, $_resource) {
            $page_access_check = new PageAccessCheck();
            return $page_access_check->isAllowed($_role, $_resource);
	}
}

Closing it up

Beside the above integration points, we still had a few things to deal with. They were more like application specific rather than ZF related. For instance we had to redo the main layout to be compatible with ZF view system, as the old app uses a template engine rather than PHP to render the HTML. Another thing we did was to create a custom component to render the application menus in both implementations (legacy code and ZF).

So, no matter how overwhelming it looks to combine the old (the code you have) with the new (the framework you dream at), you should go ahead and do it. Start by making a higher level plan, then isolate the functionalities and try to see how they impact the current application and start working 🙂

Leave a Reply

Your email address will not be published. Required fields are marked *