What exactly is a software hook? whatis.com provides the following definition:
In programming, a hook is a place and usually an interface provided in packaged code that allows a programmer to insert customized programming.
A hook may also be known as a plug-in, as indicated by the following definition from Wikipedia:
In computing, a plug-in (or plugin, add-in, addin, add-on, addon, or extension) is a software component that adds a specific feature to an existing computer program. When a program supports plug-ins, it enables customization.
In other words where you have a processing flow you provide the ability for a developer to interrupt that processing flow by saying:
When you get to this place you should execute this code
I recently came across an article on How CodeIgniter's Hook System Works, and I was fascinated to see how much effort it requires. After a quick search on the interweb thingy I found Best way to do PHP hooks and Best way to allow plugins for a PHP application which propose the use of the observer or mediator pattern, or having a hook object which contains the customisable methods, or even having a separate script with a name that indicates where and when it should be executed.
This is not how it's done in the RADICORE framework. As a long-time follower of the KISS principle I prefer to avoid unnecessary complications.
Before you can interrupt a processing flow you must have a processing flow to begin with, plus a method of interrupting that flow on demand. The RADICORE framework was designed specifically for the development of web-based database applications which utilise HTML forms at the front end and a relational database at the back end. It uses a combination of the 3-Tier Architecture and Model-View-Controller design pattern where the application logic is split into the following parts:
As each user transaction (use case) accesses one or more database tables in some way this led me to the following implementation decisions:
When a Controller calls one of the insertRecord(), getData(), updateRecord() or deleteRecord() methods you will see that it actually steps through a series of internal methods in a pre-defined sequence. Those with a "_dml_" prefix will generate and execute the relevant SQL query. Those with a "_cm_" prefix are customisable methods which provide the hooks. These methods are defined in the abstract table class but do not contain any code, which means that when called they do nothing at all.
All the developer has to do in order to have some custom code executed at a point in the processing flow is to identify which customisable method will be called at that point, then copy the empty method from the abstract class into the relevant concrete class, then fill it with code. At run-time the software will execute the method in the concrete class (if it exists), otherwise it will execute the empty method in the abstract class.
There may be occasions where you have a different user transaction which needs different code in a particular customisable method. Instead of populating the same method with different sets of code which are executed depending on different conditions, I prefer to isolate the different code in its own subclass with their own naming convention.
If you find pretty pictures more interesting than boring text, then perhaps this series of UML diagrams will help you understand the interactions between the controller, abstract class, concrete class (the table subclass) and DAO (the DML class).
As you should be able to see the system of hooks provided in the RADICORE framework does not require any configuration file or complicated processing like the methods provided in other frameworks. Instead it provides a well-documented processing flow with a series of pre-defined yet empty methods which can be used as hooks for custom code. All the developer has to do is fill in the blanks where necessary. This technique relies on nothing except inheritance. Could it be any simpler?
Here endeth the lesson. Don't applaud, just throw money.
© Tony Marston
16th September 2017