Monday 22 October 2007, 13:39
How I use the Zend Framework
By Geoffrey - Coding - Permalink
Having started a few applications using the Zend Framework, I came out with a few practices that I tend to use over and over. In this post I'll quickly expose some of them and explain why I do things the way I do them. As you'll notice, most of them are already widely known and used over the ZF developer's community. Please remember that these practices are just what I do, and come with no garanty at all to be best practices.
Directory structure
First thing to work out when starting a new Zend Framework powered application, at least if you decide to use the ZF's MVC component, is the application's directory structure. Here is the one I used, which is a slightly modified version of the official recommended structure. This is essentially a standard modular structure with all directories needed to store various additional data from your application.
application/ cache/ config/ application.ini routes.ini data/ layouts/scripts/ library/App/ logs/ modules/ default/ user/ document_root/ css/ images/ index.php js/
As you can see, I have many directories, each dedicated to a specific file type. This has many advantages, such as always knowing where to find what you're looking for or easily process files of a certain type (think grep foo logs/*). Also, I name my directories explicitly. I used to call the config directory etc, which is the directory holding most configurations files under UNIX systems, but it may not appear that clear to non-UNIX user, while config is clear enough for everyone.
Another point you might notice is the that all applications files and data are placed outside the document_root. This is done to avoid unwanted access to such resources. While this is the best way, in my opinion, to do, it may not always be possible (like when you have no control on your actual DocumentRoot. In this case, you may consider having the following structure:
application/ cache/ config/ application.ini routes.ini data/ layouts/scripts/ library/App/ logs/ modules/ default/ user/ tasks/ css/ images/ index.php js/
Then you can deny any web access to the application/ directory with the following htaccess rules:
<Directory application>
Order allow,deny
Deny from all
</Directory>
Did you say modular ?
Yeah, I said it actually. Modules in Zend Framework are groups of controllers (along with their corresponding views and models) which sits in their own namespace. One could argue that module's primary goal is to ease code re-use, but I personnaly dunno, as I personnally still have not seen such a use of modules. The drawbacks of re-usable code is that it needs to be abstract enough to fit ant particular situation or so. In this context, I only have a single separate module alongside the default one: the user module. It has Index and Auth controllers, respectively used to perform CRUD and login/logout operations.
Having re-usable modules implies that all modules containes its own models, or at least, knows where (ie, in which other module) to find its required models. There comes Xend's model loader. This is an action helper which ease the load of models inside controllers, like:
$this->_helper->modelLoader(array('MyCoolModel', 'MyOtherModel'));
Easy heh ? The bad point with this helper is that it is restricted to, or at best tricky to use outside, action controllers. That is why I developped my own library loader which I shall present in another blogpost soon.
Models naming convention
Using the Xend's model loader trained me to adopt what I consider a good model naming convention, basically, it just follows the controller's conventions, that is, prefix the model name with the module's name, so that for example my user model is named like User_Users (the first User is the module name, the second Users is the ucfirst'ed tablename). whenever I need to have row specific model I just postfix the whole model name with _Row. It gives the following directory architecture:
modules/user/models/ Users/Row.php Users.php
I'll eventually load User_Users_Row from User/Users.php with a simple require:
require_once dirname(__FILE__).'/Users/Row.php';
Personal library namespace
A recurring question from ZF beginners is to know where they should put their own library classes. The answer is pretty simple actually. You just create your own library namespace alongside Zend's. Let's say you wish to extend Zend_Db_Table_Abstract to add your own logic. The first thing to do is to choose the name of your namespace, we will use Foobar as an example, because this is a cool name. Your class will be named like Foobar_Db_Table_Abstract, and located in Foobar/Db/Table/Abstract.php, which in turn should be located anywhere in your include_path. So you could have the following directory structure:
application/library/ Zend/ Foobar/ Riskle/
Just remember ZF's naming convention: from the filename, strip the .php, replace slashes (/) with underscores (_), and you've got the class name. Simple heh ?
App_ library namespace (App_Controller_Action, etc)
Additionnaly to my personal library namespace, I also have a special App namespace, which I always locate into application/library/App. This namespace principally provides two classes, App_Controller_Action and App_Db_Table_Abstract, which basically extend respectively Zend_Controller_Action and Zend_Db_Table_Abstract. All my controllers and models then use the App_ namespace as a reference, so that I can easily change the base class for all my controllers / models as easily as changing the parent of the corresponding App class.
Using third party components
Using ZF compatible components is just easy as dropping them in your include path. By ZF compatible, I mean following the ZF class naming convention. Just make source it's in your include_path, and you can start using them right away. Components library I use includes:
- Xend's layout component
- Some components from Naneau's library
- My own library, Riskle (you'll need an assembla account)
I put them in a particular path (~/share/php/) which I add to my include path.
note: Some dikdiks tend to store third-party in application/library/ instead of a completely separate place. This problem looks a lot like dynamically linked vs static binaries. With static binaries (in our case, storing all in application/library/), you don't have to care about dependencies, as every single needed line of code is shipped with your application. This ease redistribution and installation a lot, but makes your download larger. You also have to manage yourself dependencies upgrade (which in turn save this hassle from the end-user). With dynamically linked applications, you avoid duplicated code by forcing the use of a global, site wide, code repository (generally /usr/share/php on unix systems). You also transfer dependencies handling to the end-user (and/or the packaging system). Really, this is a choice to make yourself I think.
Things get a little bit more complicated when the components does not follow the naming convention. What I do in this case is just puting them into a separate directory tree called vendor/, which I don't forget to add to my include path of course, then I just manually includes need files. We could have done a one-to-one match between the component's public classes and custom well-named classes, but it's much of a hassle for the benefit I think.
That's all folks !
Well that's all for today. I'll try to write some more in the future about application building with the Zend Framework, there are still a lot of things to be said, invented, and discovered :-)
2 comments
Very nice introduction. Thanks alot.
Hi! great tutorial.
But i i'am facing a problem with the first Directory Structure.
I want to use Zend_Layout for templating. The layout file just containt HTML, but some modules need to access some pictures in it owns directories. How can i reference these picture so they can be displayed from the Action Controllers?
thanks
This post's comments feed