Maintaining an Application-independant Code Library

By Eduardo Del Balso aka "Sake"
As a developper for my web company, I often write cake components/helpers/etc that I reuse often throughout my various client projects. For a while now I've been looking for a way to use and manage this code with CVS in a way that avoids duplication. I finally found the solution.
In trying to find a way to manage all my code snippets, I finally settled on a solution that I think merits everyone's attention since it's so simple, so maintainable and so useful.

This idea is as follows, I set up a code library on my filesystem (I use windows, but this will work anywhere) with the following file structure:

Download code
D:/codelib/cake/
D:/codelib/cake/app/
D:/codelib/cake/app/controllers/
D:/codelib/cake/app/controllers/components/
D:/codelib/cake/app/models/
D:/codelib/cake/app/models/behaviors/
D:/codelib/cake/app/views/
D:/codelib/cake/app/views/helpers/
D:/codelib/cake/app/plugins/
D:/codelib/cake/app/vendors/


The idea here is that I have a copy of my cake app/ file structure where I can put code that I will reuse in all my applications. This method now will allow any files I put in this code library to be available in any cake application I make in the future.

The simplicity in this approach is outlined by this example; Suppose I made a "FileHandlerComponent", the use of this component would simply go as follows:

  • Save my file_handler.php component file in D:/codelib/cake/app/controllers/components/file_handler.php
  • In any of my cake applications, I would simply put the line "var $components = array('FileHandler');" in a controller and the FileHandler component will be loaded properly.


That's all!

To do this, first create the above code library file structure. Now create a file D:/codelib/cake/codelib.inc with the following contents (adjust directories appropriately):

Download code
<?php

$PATH_TO_CODE_LIBRARY 
dirname(__FILE__) . DS;

$modelPaths = array($PATH_TO_CODE_LIBRARY.'app'.DS.'models'.DS);
$behaviorPaths = array($PATH_TO_CODE_LIBRARY.'app'.DS.'models'.DS.'behaviours'.DS);
$controllerPaths = array($PATH_TO_CODE_LIBRARY.'app'.DS.'controllers'.DS);
$componentPaths = array($PATH_TO_CODE_LIBRARY.'app'.DS.'controllers'.DS.'components'.DS);
$viewPaths = array($PATH_TO_CODE_LIBRARY.'app'.DS.'views'.DS);
$helperPaths = array($PATH_TO_CODE_LIBRARY.'app'.DS.'views'.DS.'helpers'.DS);
$pluginPaths = array($PATH_TO_CODE_LIBRARY.'app'.DS.'plugins'.DS);
$vendorPaths = array($PATH_TO_CODE_LIBRARY.'app'.DS.'vendors'.DS);

?>


Once that is complete, all you have to do to make this code library available to your cake app is open your /app/config/bootstrap.php and put the following line in there:

Download code
include('D:'.DS.'codelib'.DS.'cake'.DS.'codelib.inc');


Now, when you enter the following code in your controller:

Download code
var components = array('FileHandler');


It will first check your application's /app/controller/components/ folder for a file_handler.php file. If it's there, it will use the local one, otherwise it will check in your code library to see if the file exists there.

The advantage of this is that now you can develop a library of application-wide software functionality using cake, and this library can be maintained via CVS or SVN, and no more copy-paste related synchronization issues!

Comments 648

CakePHP team comments Author comments

Comment

1 Question on File Structure

I like your thinking here, but I'm wondering if there's a reason for the extended nesting of the file structure. The app dir in particular seems superfluous. Any reason for not using something simpler like:

D:/codelib/cake/
D:/codelib/cake/controllers/
D:/codelib/cake/codelib.inc

Or even:

D:/cakelib/
D:/cakelib/controllers/
D:/cakelib/codelib.inc
posted Sat, Apr 12th 2008, 12:37 by Tom Klenwell

Comment

2 path setting in codelib inc file

A change that occurred to me in setting this up for myself:

$PATH_TO_CODE_LIBRARY = dirname(__FILE__) . DS;

(Makes it a little more portable.)
posted Sat, Apr 12th 2008, 13:02 by Tom Klenwell

Comment

3 Reply about File Structure

@Tom

Any file structure will work, so long as you adjust the .inc file. You can really set it up the way you like, I just preferred to have a cake/app directory because I have other code in my codelib/ and codelib/cake folders that I don't want to easily include within my cake apps.

Thanks for the feedback, I have updated the .inc file in the article with your suggestion.
posted Wed, Apr 16th 2008, 11:09 by Eduardo Del Balso

Comment

4 A better way

Playing with Paths to point to your reusable stuff is definitely not the best way. I figured out that, when I had issues with many of my client apps. Here's what I would suggest you:

1. Try to have most of your reusable stuff as plugin, so everything remains in the folder.

2. When needed, copy paste the folders etc.

I have several reusable plugins like Comments, Star Rating, and many more..

Earlier, I was using a very similar trick like yours.
posted Tue, May 6th 2008, 18:00 by Abhimanyu Grover

Comment

5 Nice

Thank you, this is exactly what I've been looking for.
posted Wed, May 7th 2008, 21:14 by Steve Oliveira

Comment

6 Not quite a better way

@Abhimanyu I was doing exactly what you recommended and then found myself committing changes to 5 different versions of my plugins, components, etc and not having a reliable way to keep track and merge all these changes. It's the copy/paste step that makes things unreliable since you're duplicating data.
I like to use this method and then copy/paste my plugins only if I release to an environment that can't have my library installed, or an environment where I don't want the client to have my full library.
posted Wed, May 7th 2008, 22:48 by Eduardo Del Balso

Comment

7 Use vendor branching

Sharing a single set of shared files is dangerous - any newer change could break your old applications - and are you going to test all your old apps for every library update? Having completely separate copies can make applying changes to all versions tedious - and which is the latest version anyway?

The best solution is just to use vendor branching. Keep your libraries in their own repository, with local versions in each of your applications. The newest library files can be merged into each application as you need.

  • Old applications can keep the correct library files in perpetuity, in their own repository.
  • If any application does need minor changes to their library files, this can be done.
  • You can easily merge new library files into any application - when you are ready to test there are no new errors due to this.


Felix has a handy screencast of setting this up. His method is slightly over-complex, but it achieves the job well.

http://www.debuggable.com/posts/screencast-using-vendor-branching-and-cakephp:480f4dd6-6cac-44cb-b685-4d6bcbdd56cb
posted Thu, May 8th 2008, 02:04 by Grant Cox.

Comment

8 Interesting Alternative to Vendor Branching

The best solution is just to use vendor branching. Keep your libraries in their own repository, with local versions in each of your applications. The newest library files can be merged into each application as you need.

Felix has a handy screencast of setting this up. His method is slightly over-complex, but it achieves the job well.


So you're saying that a version of the library should be checked out for each project? I guess that makes sense, but the above method is still applicable so you don't have to have a second repository existing in your app/ directory.

The whole point is that if my app/ directory is in CVS/SVN, then I can't manage my PaypalComponent across 9 different applications via CVS/SVN unless it's taken out of the app/ folder.

An alternative also is to include versioning parameters in all your function calls. Don't know if that would be overkill or not.
posted Fri, May 9th 2008, 13:24 by Eduardo Del Balso

Comment

9 Use vendor branching

Dammit, the bakery swallowed my long, detailed reply because my session timed out :( So, a summarised version:

- I have a similar situation - components/helpers that are used in every project for the last couple of years.

- The version used in a site from 18 months ago is nothing like the up-to-date version. That old site needs to remain in a completely working and tested state in case updates need to be made.

- Having a shared library of code, which could change at any time independently of a project using that library, is a minefield. You will have to go back and test EVERY past application with every library change - completely impractical.

- With your suggested method, in 2 years after you've made 25 more projects and your library has evolved substantially, is this old project going to be in exactly the same (working) state as you left it?

- Vendor branching lets each application have, in their own repository, the exact version of the library that is known to work.

- Vendor branching lets each application have some unique modifications to these libraries, if necessary.

- Vendor branching allows you to merge in the updated library, with all the good stuff that SVN merge lets you do, any time you are ready to do so (and test).

- Vendor branching is not SVN:extern, and is not just copy & paste. It's better than both.
posted Fri, May 9th 2008, 22:39 by Grant Cox.

Comment

10 Tutorial on Vendor Branching

I've just written up a tutorial for Vendor Branching, it'll be at http://bakery.cakephp.org/articles/view/vendor-branching when it is approved.
posted Sat, May 10th 2008, 02:45 by Grant Cox.

Login to Submit a Comment