Quick search:

How to keep your application code separated from customization code

If you have developed an application you may want to install several copies of it, for example for different customers. If so, you may at some point need to customize a copy to meet specific customer demands. This creates a maintenance problem: if you need to do maintenance on the common code base of the application, you will have to change each copy separately. This is unnecessarily elaborate and error-prone.

Copying one or two folders with common code is not a problem as long as you do not modify the copied code. To avoid modifications to the common code you can put the common code in abstract superclasses and override it in customization subclasses. We call this a code maintenance scheme.

When you introduce a code maintenance scheme you first need to identify the concrete subclasses you want to be customizable. In general this will be all the concrete classes in the domain model and all the concrete classes in the user interface. Then you need to create a separate classFolder for the abstract superclasses. We advise you create a common classFolder for all your (organizations) abstract superclasses and a subfolder in that folder for each application. Then you create an abstract superclass for each concrete subclass, with a prefixed name. You put all the code in the abstract superclass and leave the concrete subclass empty for future customization. Make sure you do never instantiate an abstract superclass. Always instantiate the concrete subclass instead. For an example of an application using a code maintenance scheme
see example 10.

Your application will probably not only use its own concrete subclasses, but also some of the predefined concrete subclasses defined by the phpPeanuts framework. PhpPeanuts follows a code maintenance scheme of its own: to separate your code from the framework code many classes of the phpPeanuts user interface have already been subclassed. You can find these subclasses in the root classFolder. You can copy these concrete subclasses to your application classFolder if you need to override framework behavior when you want your overrides to be specific to the application.

Now what if you need to customize the above overrides of framework behavior for a specific deployment? You can put your own abstract superclasses IN BETWEEN the concrete subclasses and the framework superclasses. Basically you do the same as you did with your own concrete subclasses: subclass them from your own abstract superclasses. Only, in order to inherit the common framework behavior, subclass each abstract superclass from the frameworks abstract superclass. For an example see example10.MenuPart, its abstract superclass my.example10.MyMenuPart and the original concrete class from before the code maintenance scheme was introduced: example9.MenuPart.

With intermediate abstract superclasses you can not only combine your own code maintenance scheme with that of the phpPeanuts framework, but also add more separation layers to your own code. For example you may first customize an application for different locales and then customize further for different deployments of different customers. The locale specific intermediate superclasses will then be in between the generic application superclasses and the deployment-specific concrete subclasses. Or the other way around, if you have a customer that needs the same application in different localizations, and he needs customizations that are common to all locales.

Finally a word about the limitations of these code maintenance schemes: if you need to customize behavior inherited from higher layers of abstract superclasses, it may lead to duplication of overrides in all concrete subclasses. This can be resolved by using delegation instead of inheritance. For example we could have printed all buttons from a method printButtonsPanel defined on PntPage. But then you could only override the printing of buttons for an individual page class. Instead we created a ButtonsPanel part that prints the panel and lets instances of ButtonPart print the buttons. Now you can override one of these and it will work for all pages.