Zend Framework Automatic Dependency Tracking

When you develop or deploy an application, dependency tracking is one of the problems you must solve. Keeping track of dependencies for every application you develop is not an easy task. To solve this problem I’ve created Zend_Debug_Include, a Zend Framework component that supports automatic dependency tracking.

We all agree that dependencies cannot be maintained by hand, it’s almost impossible, specially if you are using packages from Zend, Solar, Maintainable and/or Zym (if you don’t know any of these frameworks, check them out, they are pretty cool). Every time you add an include/require statement or create an instance of an object, you introduce a new dependency. And that’s why tracking internal project dependencies can become complex when using a framework.

The concept behind Zend_Debug_Include is that the dependencies for each source file are stored in a separate file. If the source file is modified, the file containing that source file’s dependencies is rebuilt. This concept enables you to determine run-time dependencies of files using arbitrary components. This solution is also useful if you are deploying your application using Linux packages. But, dependency tracking isn’t just useful for deploying applications, it can also be used to evaluate packages. Sometimes packages create unnecessary dependencies and this is something that we need to monitor.

Zend_Debug_Include comes with 3 built-in adapters: File, Package and Url.

Tracking File Dependencies

To track file dependencies you need to create an instance of Zend_Debug_Include_Manager and set the Zend_Debug_Include_Adapter_File adapter. This needs to happen inside your bootstrapper file, before the Front Controller dispatches the request.

$included = new Zend_Debug_Include_Manager();
$included->setAdapter(new Zend_Debug_Include_Adapter_File());
$included->setOutputDir('/var/www/my-app/dependencies');

/* Dispatch request */
$frontController->dispatch();

This creates a zf-files.txt in your output directory containing all the files included or required on that request. Every time the Front Controller dispatches a request, Zend_Debug_Include checks for new dependencies and adds them to the zf-files.txt file:

/var/www/my-app/public/index.php
/var/www/my-app/application/bootstrap.php
/var/www/my-app/library/Zend/Loader.php
/var/www/my-app/library/Zend/Controller/Front.php
/var/www/my-app/library/Zend/Controller/Action/HelperBroker.php
/var/www/my-app/library/Zend/Controller/Action/HelperBroker/PriorityStack.php
/var/www/my-app/library/Zend/Controller/Exception.php
/var/www/my-app/library/Zend/Exception.php
/var/www/my-app/library/Zend/Controller/Plugin/Broker.php
/var/www/my-app/library/Zend/Controller/Plugin/Abstract.php
/var/www/my-app/library/Zend/Controller/Dispatcher/Standard.php
/var/www/my-app/library/Zend/Controller/Dispatcher/Abstract.php
/var/www/my-app/library/Zend/Controller/Dispatcher/Interface.php
/var/www/my-app/library/Zend/Controller/Request/Abstract.php
/var/www/my-app/library/Zend/Controller/Response/Abstract.php
/var/www/my-app/library/Zend/Controller/Router/Route.php
/var/www/my-app/library/Zend/Controller/Router/Route/Abstract.php
/var/www/my-app/library/Zend/Controller/Router/Route/Interface.php
/var/www/my-app/library/Zend/Config.php
... (63 files in total) ...

To change the name of the file:

$included = new Zend_Debug_Include_Manager();
$included->setOutputDir('/var/www/my-app/dependencies');
$included->setFilename('files.dep');
...

Tracking Package Dependencies

Similar to Zend_Debug_Include_Adapter_File, but groups all the files into packages.

$included = new Zend_Debug_Include_Manager();
$included->setAdapter(new Zend_Debug_Include_Adapter_Package());
$included->setOutputDir('/var/www/my-app/dependencies');

The code above creates a zf-packages.txt file and adds the following data:

Zend/Loader.php
Zend/Controller
Zend/Exception.php
Zend/Config.php
Zend/Debug
Zend/View.php
Zend/View
Zend/Loader
Zend/Uri.php
Zend/Filter
Zend/Filter.php

Now, if you introduce a new dependency, for example, Zend_Mail:

class IndexController extends Zend_Controller_Action
{
    public function indexAction()
    {
        $mail = new Zend_Mail();
        $this->view->message  = 'test';
    }
}

The next time the Front Controller dispatches the request and calls the index action, Zend_Debug_Include will automatically add the Zend_Mail package and all its dependencies to the zf-packages.txt file:

Zend/Loader.php
Zend/Controller
Zend/Exception.php
Zend/Config.php
Zend/Debug
Zend/View.php
Zend/View
Zend/Loader
Zend/Uri.php
Zend/Filter
Zend/Filter.php
Zend/Mail.php
Zend/Mail
Zend/Mime.php
Zend/Mime

You can then use this information to keep track of dependencies and tell your build tool the name of the files and directories you need to copy and package.

External Dependencies

Here is where everything starts to make sense. Zend_Debug_Include allows you to search for external dependencies as well, you just need to tell the Adapter the libraries you are using. For example:

$libraries = array('Zend', 'Solar');
$adapter = new Zend_Debug_Include_Adapter_Package($libraries);

$included = new Zend_Debug_Include_Manager();
$included->setAdapter($adapter);
$included->setOutputDir('/var/www/my-app/dependencies');

The Solar packages will also be added to the zf-packages.txt file:

Zend/Loader.php
Zend/Controller
Zend/Exception.php
Zend/Config.php
Zend/Debug
Zend/View.php
Zend/View
Zend/Loader
Zend/Uri.php
Zend/Filter
Zend/Filter.php
Zend/Mail.php
Zend/Mail
Zend/Mime.php
Zend/Mime
Solar/Base.php
Solar/File.php
Solar/Factory.php
Solar/Sql.php
Solar/Sql
Solar/Cache.php
Solar/Cache

URL Adapter

If you want to create a different file for each request, use the URL adapter instead:

$included = new Zend_Debug_Include_Manager();
$included->setAdapter(new Zend_Debug_Include_Adapter_Url());
$included->setOutputDir('/var/www/my-app/dependencies');

The URL adapter maps the URL path to a filename. So, if you request the following URI:

http://my-app/blog/2009/02/01

It creates the file blog_2009_02_01.txt.

SVN

$ cd libraries/Zend
$ svn co http://svn.fedecarg.com/repo/Zend/Debug
About these ads

11 thoughts on “Zend Framework Automatic Dependency Tracking

  1. I’m not sure a lot of people are going to be interested in this component. Solar and Zend have in total 2365 files, without counting your own files My_*. For what I know, a lot of people find it easier to drop everything inside the libraries/ folder and forget about it. The downside of this is that you end up deploying 2000 library files and 20 application files, and if you are deploying an open source application, or handing over some code to a client or colleague, it might not be the best option. It would be interesting to find out how other developers are deploying their applications and libraries.

  2. I needed a similar solution at some point in the past. Your solution is nicer , I especially like the url adapter. What I did back then is to extend Zend_Loader that basically did something similar. In that way , I could enable it or disable it at will. I am sure a lot of people need this type of functionality , and it would be an alternative to generating all sort of graphs using external tools , so a proposal will be nice. Perhaps the tool would just list packages instead of files , and you woun’t have those 2365 files , instead x packages.

  3. This is indeed a cool extension of the debug library. I was in need of something like this because I only want to ship parts of Zend and other libraries that are actually used in my code without having to worry about what depends on what.

    With this, my code coverage tests can also tell me the libraries that are all used so I only need to upgrade and track what is used.

    Thanks a lot for this Federico!

  4. Hey Federico!

    This is actually a pretty interesting article. I would like to take the code for a spin. When you think about concepts like “freezing” (in rails & others) of system library code to an applications library directory, this kind of analyzer would indeed be great to minify the project.

    Also, I think it would prove to be more beneficial if you had a more personal prefix on this.. like FC_xxx or PHPImpact_xxx, this way these classes can reside next to ZF on someones system.

    Cheers!
    Ralph

  5. Yes, I was using the prefix Trex_* in 2006, I’ll stick to that one next time.

    In case someone wants to change the prefix:
    $ find . -type f -print0 | xargs -0 sed -i ’s/Zend_Debug_Include/My_Debug_Include/’

    Thanks

  6. Pingback: Reading List: 6Feb09 » Karl Katzke | PHP, Puppies, and other Geekery

  7. Pingback: Tims Blog

  8. Pingback: Implementing your own Front Controller in Zend Framework « fede.carg ( blog )

  9. Pingback: Federico Cargnelutti (fedecarg) 's status on Monday, 19-Oct-09 20:05:04 UTC - Identi.ca

  10. This looks very nice indeed! I found your post accidentially, but this is really something I was thinking about myself. Zend library is huge and very often it is hard to deploy as the size of the installation package becomes really huge. Good to know there’s a nice and elegant solution availabe to solve this.

    I think if this is combined with good covered unit testing, it might be able to detect all dependecies for the application in one shot (I would rather use “Package Dependencies”).

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s