Through Agile Toolkit I’m sharing with the world my improved vision for a better Active Record Implementation. I believe that the widely popular Active Record implementations are examples of a bad software design. Here is the reason.
What is Active Record?
Active Record pattern have been hugely popular due to adoption in Ruby on Rails and in other frameworks. (Active Record explained on wikipedia). Typically a class is generated based on the database table schema. All the fields of the database are reflected as properties of the model. Class has several constructors allowing to load model directly by ID or search for records. Only one record can be loaded at a time.
Why Classic Active Record is Broken?
No Testability
When the object is created, constructors does not accept reference to the database engine. Instead, they manage to pull it from some global namespace. That makes it very difficult to use Active Record with multiple database configuration or for testing.
Static methods / Constructors
A static method of a class which creates new instance of that class is called “constructor”. With Active Record there are multiple constructors present which can load record in a different ways. Number of constructors depend on the table structure in some implementation such as loadByCode() would only be applicable if “code” field exists.
Abusive properties
Potentially table can contain any field therefore model may have no “reserved” properties. That makes it virtually impossible to build any decent logic in the abstract model class.
Code generation = duplication
I am always amazed how same people preach about code re-use and how awful it is to copy-paste your code and then use code generators which effectively build thousands of lines of code for them. It might look good in your versioning system, but it is a very bad development practice.
One table = one class
While frameworks typically allow you to specify “parent class” in the YAML definition, in practice it is rarely used. We know that sometimes one table may contain different entity types, but Active Record implementations does not help in separating them into different classes.
Operations with multiple records
By definition Active Record object can hold one record only. If you need to iterate through multiple records you will end up creating and destroying objects, which introduces performance overheads.
Lack of conditioning
Active Record typically allow to load ANY record present in the table. It’s virtually impossible in many implementation of Active Record to restrict loading to certain types of data. That is, for example, implementation of soft-deletion. Implementing it often is a major effort.
Recipe for an Improved Active Record
Dependency Injection
There might be many variables model may require. Database driver object is one thing, but it might also require some other information. Specifying multiple objects for constructor is troublesome and inconsistent. My suggestion is to specify just one object which contains links to other necessary resources.
This object can be passed through the factory class. I have solved this problem having each object carry reference to such an object and whenever new object is created, it also receives that reference. That is a “api” class which can be used to reference database connection: $this->api->db. In practice, there may be multiple API classes, which makes it possible to inject dependency into any object.
Avoiding Constructors
If a model object could have a state where it is not associated with the database record, then the same object could be reused multiple times. If object is created first and then load() method is used to load new record from database then it can be subsequently called to add more records without the need to create model instance every time.
That means other methods can be used for loading data. As developer you may define new methods for data loading in your model classes which would override default methods.
Avoiding using properties for fields
In a database one field usually is a primary key. In most cases it’s called “id” but not always. If we want to introduce a property in our model, which will always refer to this primary key it may clash with non-primary key in a classic implementation of Active Record.
Fortunately PHP objects can also act as arrays. By using $model['name']=’John’ the requests can be easily routed and saved inside internal array w
Truncated by Planet PHP.ie, read more at the original (another 3527 bytes)