PHP Framework / Directory Structure

PHP Directory Structure (my take)

On the PHPWM mailing list, we've been having occassional discussions about directory structure(s) - see Akabat's take and Darren's take for alternative views.

At Pale Purple, we tend to create separate php scripts for each 'page', with Smarty being used for templating. Within each individual script, we may make use of Objects, and only use PHP5 (exceptions, interfaces, abstract classes etc), so much so that many pages contain only 4-6 lines of PHP logic (create object, run, retrieve results and put them in template).

So, things were going quite well, then unfortunately we started using our common code in multiple projects, and naturally each instance started to diverge as bugs were fixed (and created) or files were changed to suit individual needs. Last Saturday, I found my self in the process of doing this once again, while creating a simple web interface to an email archive I'd just installed for a customer, and realised it had gone on for too long - when I thought "Which project has the best .... ?"

So, we've finally pulled our finger out and knocked our collection of PHP scripts into a sort of framework. I'm not sure it can be described as elegant, and doesn't yet have a name (no, not Monty!). So far, we're using it on one project (and it took most of a day to undertake a changeover and make the framework work). However, on the bright side of things, we've eliminated code duplication, and now stuff should be easier for people to find.

The directory structure is similar to that of RubyOnRails, and seems to make a reasonable amount of sense - so much so, Sam (our newest employee) seems to have taken to it naturally.

So, what about :

# app - the unique stuff for a particular project.
    * api - PHPDoc generated stuff
    * controller - main php files for application
    * view - smarty templates; directory structure should match that of controller
    * lib - shared code specific to this project, or extensions of real lib stuff
    * export - report specific tempates (e.g. RTFs)
          o rtf_template
          o other_format_template 
    * exception - app specific exceptions 
# db
    * propel (schema.xml + build directory, etc)
    * native - Any non-propel code (e.g. aggregate stuff that has to be written by hand) 
# lib - checked out from common repository 
    * public - same structure as /public dir, but cross project stuff
    * smarty - actual smarty code (plus our own smarty objects)
    * propel - actual propel code
    * controller - common controllers (the PP* classes)
    * report - common report stuff (e.g. PPRtfReport)
    * exception - generic exceptions 
    * Other.PHP.Libraries
# config
    * common.php - contains all initialisation routines etc.
# public things that will be accessible to the world (static .html files etc)
    * dispatch.php 
    * .htaccess  (forwards anything not found in public into dispatch.php)
    * images - plus subdirs
    * javascript - plus subdirs
    * styles - plus subdirs 
# var - transient things
    * log.txt - debug/error log
    * sessions - PHP session files
    * templates_c - smarty compiled templates

One thing I like about this configuration is that there is an effective union of various directories, so we can have some files we always use (.js, .css etc) in the lib/public folder, and they'll 'appear' as if they're in the /public folder (remember /lib is from a separate, common subversion repository). The magic is possible, thanks to the power of mod_rewrite and a simple dispatching PHP class.

A couple of things still suck however, the first is that subversion doesn't really handle the '/lib' directory all that well - in that you need to explicity go into it to perform an update (which sucks). The second, is that I need to install so much stuff in the '/lib' directory (currently I already have Propel, Creole, Smarty, PEAR::Log) - this is good from some points of view - in that I can now patch Propel/Smarty and not have to worry about someone doing a 'pear upgrade-all' or 'apt-get dist-upgrade' and suddenly everything stops working, but bad from others (i.e. I need to keep an eye out wrt security announcements etc). We were having problems with maintaining a patchset on Propel and installing the applications on various machines, so hopefully they should now all be removed.

I suspect the '/config' directory is in the wrong place, and should perhaps be in 'app', but it's perhaps too early to say for certain - none of us have used RubyOnRails, we just saw a nice looking diagram detailing it's directory structure, and thought "that looks good, we need something, lets base ours of theirs". Hopefully we'll soon move other projects over to this structure, and then we'll realise what's not quite right with it.

Technorati Tags:

Comments

SVN

Isn't there an Subversion thingy for getting it to automatically checkout another repository when you checkout your main one?

*pause whilst I google!*

Aha! I was thinking of "externals" (http://svnbook.red-bean.com/en/1.2/svn.advanced.externals.html)

Might help a bit, you never know.

It's interesting that you separate out the rtf templates from the view. There's a school of thought that would suggest that the RTF output is just a different kind of view, not a special export. I dunno. We put our email templates in the same folder as the web templates. We haven't done an RTF export, so I'm not sure where I'd put it!

Also, is the db/ stuff generic or specific? If it's generic, why isn't it in lib/? If it's specific to this app, why isn't it in app/? Or to rephrase the question a bit: what's different enough about db/ to warrant a top level directory?

At the end of the day, the best thing about a common directory structure is that you can find things again having not touched a project for 6 months. It doesn't really matter about the details :)

Regards,

Rob...

Thank you!

I had an idea there must be some way of doing what externals does, but hadn't looked.

To answer your questions:

1) I wanted the app/view and app/controller directories to mirror one another; export templates (rtf, or email or whatever) somehow felt like they should be in a seperate directory (hence export).

2) The db stuff is application specific, for some reason we put it in the db folder, and not 'app'... I think this was perhaps us blindly following the Rails convention, without having used Rails to know any different.

Hopefully, I'll start documenting some of the framework soon, and at which point we may have two projects both using the 'framework', so then hopefully it will be time to sit down and quickly discuss what's right/wrong and make changes.

David.
(Glad you found the externals stuff!)

Multiple Projects

There's nothing like multiple projects to help you realise that you've put app-specific stuff in the wrong place :)

Regards,

Rob...

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <img>
  • Lines and paragraphs break automatically.

More information about formatting options

CAPTCHA
We don't take kindly to automated nonsensible adverts around here.