Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

Background / The Problem

I need to make a (large) application with a certain set of core functionality, and certain functionality for multiple clients within it. Each client has different requirements and while they may share some functionality, I need to separate the code for each client, so a change to one won't affect others. Each client section of the application should also inherit some features from the core application. Ideally I would like to separate the databases for each client too. In terms of a user system, core users should be able to have access to each client's functionality, but client users should only be able to interact with their specific client section of the site.

Current Solution

Each client has its own subdomain and the MVC can override the core's MVC files IF they exist. In a nutshell, my custom MVC's autoloader checks the client directory for the matching M,V, or C file when a subdomain is present in the URL and loads that particular client's file INSTEAD OF the core file. It's an override ability in a sense.

Questions

  1. Am I solving this problem in a way that would be considered good practice in terms of software design?

  2. If I were to use an existing PHP Framework (I would like to), how might I go about setting it up to solve this problem? Specifically I have been looking at Yii and CodeIgniter.

Thanks in advance!

Update: I have discovered a design pattern called HMVC (Hierarchical MVC) and it seems to be essentially what I have described. I see that Kohana 3 is built using it and that Codeigniter has an extension that allows it.

share|improve this question
add comment

3 Answers

This may or may not be of any use to you, but look at Symfony 2's "Bundle Inheritance". It allows you to override functionality from distributed bundles on an application level.

If you developed your core functionality in a bundle, you could deploy multiple applications and do the overrides there. Keep the core bundle in sync with via version control and a Composer repository, and the only things that would differ between these applications would be the client-specific modifications.

The downfall with this approach is that you're managing N deployed applications, which isn't exactly friendly. Perhaps you could fork Symfony 2 and alter the class loader to be client-aware so you can have multiple client folders in your application deployment. It should be a relatively simple fork, so keeping Symfony updated would be trivial.

share|improve this answer
    
It shouldn't be necessary to fork Symfony - a Symfony application can override any of the core Symfony classes without a fork. –  Jonathan Rich Mar 12 '13 at 15:41
    
This is an interesting idea, thank you for the input. –  Austen Cameron May 23 '13 at 14:00
add comment

What you want is a form of dependency injection.

Try symbolic classes:

namespace Core;
class X { }
class Y { }

 

namespace MrSmith\Core;
class X extends \Core\X { } // extend specific core class for Mr. Smith

 

define('CLIENT_NAME','MrSmith');
$x = new \Sym\Core\X();
$y = new \Sym\Core\Y();

Have the autoloader see "Sym" in the namespace and load \MrSmith\Core\X and then alias it with \Sym\Core\X.

Then it attempts the same with \Sym\Core\Y, can't find one for Mr. Smith, and falls back to \Core\Y.

This way you only need to define deviations on a per-client basis, with each client in their own sandbox.

If you're deploying the system by giving each client a copy and they're sandboxed already in their own subdomain/document root, you could skip using CLIENT_NAME and just have it look in a "Sym" directory, and use "Sym" as the namespace instead of "MrSmith".

share|improve this answer
add comment

Working with CakePHP but doable in many different systems which are capable of some plugins concept.

What we do is develop the core functionality in plugins first.So for example: users management feature. That plugin is stored at GitHub as a separate repository.

The we create one general application setup, that is files like index.php, example css file etc. For each client install this basic setup and start loading plugins to get the desired features.

So in GitHub you have:

Template Application (index.php / example css file / pluginloader)
Plugin 1 (users management)
Plugin 2 (accounting)
etc.

The client application can be fully customized and use the features of the plugin as desired.

Then, to go further, you can even override a single view of a plugin. Example of that can be found here: http://book.cakephp.org/2.0/en/plugins.html#overriding-plugin-views-from-inside-your-application

If you like you can get the copy of the template and then push it as a new repository at GitHub so you get in the end all separate repositories loaded together.:

Template Application (index.php / example css file / pluginloader)
Plugin 1 (users management)
Plugin 2 (accounting)
Plugin 3 (custom feature for Client 1 - link to their production site)
etc.
Client 1 (you're first copy of template)
Client 2 (the second copy of template)

Nice thing is also that you have separate modules which can be tested separately, re-used etc.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.