One of the most essential skills for any object oriented developer is figuring out what aspects two different objects have in common – and every object has something in common with another object. By finding out common aspects, he can use abstraction and encapsulation to pull common properties and methods into a single, centralized core. This core would then be expanded into a large variety of objects for use throughout the system.
Two of the most commonly used tools within a decent sized framework are dealing with validation and persistent storage – so these are pieces that can be abstracted for all objects that will be used throughout the system. All objects will contain properties that require validation, and the vast majority of objects will require some kind of persistent storage, be it XML, session, MySQL or plain text files.
Septuro uses a three tier system that I find to be highly useful and flexible for creating a tremendous number of objects as quickly as possible. In a nutshell – tier one contains validation, tier two contains persistent storage and tier three contains customization. Each tier handles its own functionality in a very abstract way, allowing it to be extended infinitely for a large number of objects.
As an example of each tier, I will focus on the user object, which contains the data for user login. I will only focus on the user id, username and password fields, which is structured as follows:
- user id – int 10 – required – no input – primary key
- username – varchar 50 – required – text input
- password – varchar 50 – md5 hash – required – password input
The property and validation tier
class object
The first tier purely contains property validation specifications, and this tier is common to every object in Septuro. This tier contains a few critical methods that are used for defining the rules of the properties and for altering the values of the properties. The properties will be customized within the third tier and the values will be set inside an individual module. So for the user object, there are three properties to specify.
The extended user object will specify these properties in the third tier, but the first tier contains the rules for accepting these properties. The properties are defined, and the ability to change the value are set in the first tier. Once the properties are defined (which happens in the constructor), the values can be altered through a method defined in this first tier. When any value is being altered, it checks the validation rules that were defined in the third tier. Through this method, every object in Septuro has the exact same structure for validating properties, but every object can define its own validation rules.
This property and validation layer can be thought of like a large press at a factory. It does the grunt work for building the objects, but only once the proper mold has been fitted onto it, and that mold will be defined in the third tier.
The persistent storage tier
class databaseObject extends object
The second tier in this model deals with persistent storage. In Septuro, this tier is the only place that persistent storage is dealt with. At no other point in any file will you find database connectivity, file reading or writing, or session interaction. Any module that is creating an instance of an object has no knowledge of where the data is stored, and that is just the way it should be.
Once the properties are defined, it is a piece of cake to convert any attempt at saving data into a valid command in a persistent storage layer. For instance, the user object is stored in the database, and since user extends databaseObject, when a request is sent to save user, that request is passed to databaseObject.
The module that requested the saving is not aware of any of this database interaction. This is done by having the first tier define some abstract methods for the second tier – create, read, update, delete. When a module asks an object to save, it always calls the same method – update. Exactly how update operates is defined in the second tier, and in the case of a databaseObject, it converts the properties into a valid SQL call and executes that call.
Any number of persistent storage layers can extend object – such as xmlObject, sessionObject, cookieObject or fileObject. Each of these defines the exact rules for interacting with the storage when asked to create, read, update or delete. The first tier is not concerned with persistent storage, and the third layer only defines the custom rules for the particular object.
The customization tier
class user extends databaseObject
The third tier is used to define the final object (although even this can be extended). It will only contain a list of properties that the object contains, and the validation rules for that property. In the example of our user object, it contains a function that defines the three properties (this function will be called by the first tier constructor), listing the rules for what is allowed and where it is stored.
In the end, when a user object is created, edited and saved, the following sequence will be executed:
- module calls new user()
- tier one constructor is called, which begins the property definition setup
- tier one constructor checks to see if any custom set up rules have been defined
- custom rules are found in tier two
- tier two establishes a database connection
- tier one constructor calls an abstract function to set up the properties
- this abstract function is defined in tier three
- user-id, username and password rules are defined
- tier one constructor finishes and exits
- module requests a change in value to username and password
- tier one processes the value change, making sure the values match the validation rules
- module requests the object is updated (saved)
- tier one sends the update request to tier two
- tier two converts the property list into a SQL call, executes the call
As you can see, in this three tier system, the first tier only processes changes to properties. It knows what rules are allowed, how to process those rules, and how to approve or deny changes. The second tier only deals with persistent storage. It knows how to convert those properties into a valid persistent storage command and process it. It does not care what the properties are or how they are validated. The third tier customizes the properties, defining what this exact object will contain.
Through this system, once the Septuro team finished the first tier and the databaseObject second tier, we will never again write a SQL call. We will just define third tier objects and let our previous work do the rest. It is even set up so that the third tier can be extended and foreign key relationships automatically defined! For instance, the user object can be extended to either client or employee, both of which have their own table. This object will seamlessly connect the user and employee table or the user and client table, and all properties of user are transferred over without being rewritten.
If you would like to see this system in action, download the Septuro source code from the repository and look at the files in /septuro/object/abstract, and sample objects in /application/sample/object.