Hi Vincent and others,
We have built an app development framework based on Zend+Doctrine+Smarty+other stuff that may be of interest to you, and I'll share our structure here. I'll say upfront that this is a fairly heavy-weight approach which is useful for development shops that implement similar technology over and over, and is not suited to a one-off site implementations.
We use modules, but we also go much further. Unlike most implementations I've seen, we have separated out our framework libraries from the application, so we can build multiple applications which reference the one shared library. This makes bulk deployment and bulk upgrades faster and easier.
We build lots of sites with similar characteristics and we favour heavy shared library code and light per-application code. We don't like embedding the framework libs into each project, nor do we like code re-use via copy/paste.
So, in our framework we have added modules into both our framework library, and into each application, so commonly-deployed modules are shared, not copied.
An example server set-up.
At the server level, you a sample deployment might be something like this:
/app1.example.com/app2.example.com/common
Against Zend conventions, our docroot is each /app* directory. We found that it was too restrictive using a /public folder, as we could not store the module's assets (style sheets, images, etc) in the module's directory. Instead, we have a modified .htaccess file that provides protection against source file access, and allows each module to access its assets via HTTP.
I'd be interested in hearing from any other people that have solved this in other ways.
Applications
Each app is its own virtual server in apache, and as explained above the app root is also the doc root for us. Each application looks like:
/config/library/modules/tests/themes/tmp
/library
Our library has our model classes (named as a singular because the entire set of classes is considered as the model). This uses Doctrine for ORM, but can also contain other hand-written classes for factories, etc. We also have the ability for per-application view and controller helpers (although in practice we tend to put these into our framework library for re-use across all our applications).
/model/helper/controller/view
/modules
Each module directory looks like this:
/module1/controllersFooController.phpBarController.php/libraryFoo.php/publicfoo.jpg/helpers/filters/views/fooindex.tpl/barindex.tplbleh.tpl/tests
Of special note with our module implementation:
- we've changed Zend's /views directory structure to be flatter (removed the /scripts dir)
- we have a /public directory in each module where we can place public assets. We then use rewrite rules to allow HTTP access to that dir while restricting access to others. This allows modules to have images, stylesheets, etc in each module.
- we have per-module tests
/tests
We have per-app tests here, using PHP_Unit.
/themes
We have extended Zend_Layout to accommodate the idea of multiple "themes", with each theme containing multiple layouts. So, inside /themes you may find:
/theme1/controllersDefaultController.phpHomeController.php/lib/helpers/filters/publicfoo.jpg/views/defaultlayout.tpl/homelayout.tpl
We have heavily extended Zend_Layout to do the following:
- our layouts run a full dispatch against a layoutAction() so we can build a controller and assign things into the layout's view.
- each theme can have its own /lib, /helpers, /filters, etc so they are logically separate from each other. To understand why, the broadband theme may need lots more helpers to do stuff in their sidebar, whereas a wap theme won't have a sidebar but it might need a helper to look up GPS coords from the client. This approach allows for contextualised themes or subsite themes, and a layout within a theme can have its own logic to apply to its view, rather than making those decisions in the module's controller.
- There's lots more I could explain here - it's pretty cool stuff - but it's out of scope for a discussion on directory structures.
/tmp
Our tmp dir has subdirectories for /logs, /cache and /smarty.
The common library
Our library has its own set of modules and themes. This allows us to provide a central CMS via a set of modules which is delivered over each application's URL namespace (for example, app1.example.com/cms loads the 'cms' module which is stored in our library, not in the application).
The library directory looks like this:
/library/ZendFramework/Smarty/Doctrine/Bravo.../modules/cms.../publicfoo.jpg/scripts/tests/themes
This approach is certainly not for everyone. It has these advantages:
- separate libraries for all applications, each application, each module to store models, helpers, etc.
- allows for extensive code sharing across multiple similar applications (such as a CMS) while maintaining access to the app's model classes
- CVS/SVN checkins per application are lighter as we do not include shared libs
- quick to deploy solutions to shared server environments once they are configured.
We've also modified much of Zend's MVC with different routes, layouts, views, helpers, etc. We chose Zend because it was not a full app development environment like Symfony or Code Igniter, but was instead much more flexible, allowing us to create our own customised development environment that perfectly suits our company.
Hope this helps...
Cheers, Scott