January 21st, 2010
Once upon a time I stumbled across Ruby on Rails, a MVC framework on top of the programming language Ruby. Through RoR I became familiar with the MVC-pattern, ActiveRecord-pattern, and soon lots an lots of other patterns. About 4 months ago I came in contact with Zend Framework, which also follows the MVC-pattern.
While working with ZF a had a couple of my old "if you need something done right, you should do it yourself"-moments. One of which was working with the Model of ZF. Say what? Yes, those of you familiar with ZF will know there is no such thing as a Zend_Model! But this is quite understandable; there are a lot of patterns dealing with data. ActiveRecord, Repository, Row Data Gateway, Table Data Gateway, Table Mapper to name a few of these patterns.
I chose the ActiveRecord-pattern for managing Models in ZF. Though I realize the limitations of the ActiveRecord-pattern, I do quite like it where no complex business-logic is needed. So I started writing a library to handle basic ActiveRecord-like behavior. Soon I discovered I needed more that the basics and started searching for existing PHP implementations of ActiveRecord. I found a few: Doctrine, Propel and PHP.ActiveRecord. The last one is a very new implementation and is based on the RoR implementation of the ActiveRecord-pattern. So I gave it a try!
Almost immediately I started rewriting pieces of code within phpAR:
Records will frequently need attributes not stored in a database. Say you want to have a "name" which is built out of a "firstname" and "lastname" stored in a database. I'd like to have such pseudo-attributes. While phpAR does enable you to define custom Setters for such attributes, it lacks the ability to define custom Getters. Weird...
I needed to fix a few bugs on the way too. A bit frustrating but expected when working with a brand-new implementation.
It completely lacks translation, and makes implementing it quite hard. Validation done on the Records report errors in the form of messages (which obviously need to be translated). You can add custom messages to validation, but because validation is defined statically you can't translate directly. I had to hack a bit around it which took me a step back in the sense of "cleanness".
In fact, almost everything is defined statically, which makes dynamic operations impossible (duh). Well ok, not impossible, but I'm "hacking" again to make things work. I presume this static business is done in order to mimic RoR behavior (and phpAR does mimic it quite nicely).
Another bit of "dynamicness" I found missing was the ability to pass along data to associated Records (through relations between Records). But I have to admit that I haven't seen this in any implementation of the ActiveRecord-pattern (including RoR). Maybe it doesn't even fit into the pattern? I've rewritten a few lines of code (where associated Records are loaded) anyway, and now a callback-method is (optionally) run on every associated Record when it's loaded.
Enough "bad" things said! Overall phpAR is a neat creation. The lack of "good" things I have to say prove that it's an easy to use, to the point, implementation of the ActiveRecord-pattern. It really does what it claims it does.
Thank you Kien La and Jacques Fuentes for this experience! I do have one final tip: I think it's wise to consider that PHP and Ruby have a very different approach to the imperative programming language. Some Ruby syntax just can't be mimicked in PHP because PHP simply lacks the support for certain constructs. Maybe a change of focus will put PHP.ActiveRecord "out there!"?