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
11 responses to “Zend Framework Automatic Dependency Tracking”
Will you make a zf-proposal for this really nice idea ?
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.
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.
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!
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
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
[…] the “Yes, Mom, I’m still a PHP Coder” department, Php:Impact has Automatic Dependency Tracking in Zend Framework. I use this along with firebug to see exactly what kind of spiderweb I […]
[…] zend framework automatic dependency tracking […]
[…] Zend Framework Automatic Dependency Tracking […]
[…] https://blog.fedecarg.com/2009/02/01/zend-framework-automatic-dependency-tracking/ a few seconds ago from web […]
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”).