ActiveRecord PHP implementation Part I

ActiveRecord UML

This is the first part of an attempt to implement the ActiveRecord design pattern in PHP.
This first implementation is very simple but will open doors for more advanced stuff, like foreign keys mapping(automatic or manually) or integration with Model, View and Controller components, in this case with the generation of PHP classes or objects.

Approach: A row in a database table or view is wrapped into a class, thus an object instance is tied to a single row in the database.

Imagine this table(person):

+-------------+---------------------+
| Field       | Type                |
+-------------+---------------------+
| id          | bigint(20) unsigned |
| name        | varchar(100)        |
| email       | varchar(150)        |
| last_update | datetime            |
+-------------+---------------------+

With this records:

+----+----------+---------------+---------------------+
| id | name     | email         | last_update         |
+----+----------+---------------+---------------------+
|  1 | Nuno     | nuno@xxx.xxx  | 2005-11-06 20:39:08 |
+----+----------+---------------+---------------------+
|  2 | Marta    | marta@xxx.xxx | 2005-11-06 20:39:08 |
+----+----------+---------------+---------------------+
|  3 | Pedro    | joao@xxx.xxx  | 2005-11-06 20:39:08 |
+----+----------+---------------+---------------------+

You don’t have to define any table structure, just extend de ActiveRecord class and call the parent __construct() method with the table name :

<?php

include_once ‘class.ActiveRecord.php’;

class Person extends ActiveRecord {
    public function __construct() {
        parent::__construct(‘person’);
    }
}

?>

To return all rows in the table:

<?php

$persons = new Person();

/**
 * This will print all records
 * $persons->findAll() will return a Recordset
 */
foreach($persons->findAll() as $person) {
    echo ‘id: ‘.$person->id;
    echo ‘name: ‘.$person->name;
    echo ‘email: ‘.$person->email;
    echo ‘last update: ‘.$person->last_update;
}

/**
 * Alternatively you can ‘walk’ the Recordset
 * with next(), prev(), etc. because Recordset
 * implements the Iterator interface
 */

?>

Insert a record:

<?php

$person = new Person();
$person->name = ‘Julia’;
$person->email = ‘julia@xxx.xxx’;
$person->insert();

?>

Update a record:

<?php

$personId = $_POST[‘id’];
$person = new Person();
$person->id = $personId;
$person->name = ‘Nuno Mariz’;
$person->update();

?>

UPDATE:
With the Pádraic Brady tip for merging the insert() and update() methods to only one save() method, now is possible to:

<?php

// insert
$person = new Person();
$person->name = ‘Nuno Mariz’;
$person->save();

// or update
$personId = $_POST[‘id’];
$person = new Person();
$person->find($personId);
$person->name = ‘Nuno Mariz’;
$person->save();

?>

You can view the UML for the implementation.
See you in part II…

20 Comments so far

  1. orixilus on January 7th, 2006

    will you release your code for us…? :)

  2. Nuno Mariz on January 7th, 2006

    Yes, in part II(soon).

  3. Pádraic Brady on January 11th, 2006

    Maybe some method of merging insert() and update() into a single method? Make it easier if that decision was made internally - an insert assumes the record was read from database, which can be tracked, and if such a “read” flag were not set it would be inserted instead.

    My 0.02c…

  4. Nuno Mariz on January 11th, 2006

    Yes, you are right.
    I will implement the method save() instead of insert() and update().
    Just like i said, this is the first approach, any sugestions are welcome.

    Thanks

  5. Joaquim Rendeiro on January 19th, 2006

    Hey!

    Looks like you’ve been trying Ruby on Rails (as I did recently), you were already a PHP developer (as I am) and you got to the same conclusion as I did:

    RoR is nice but it has a really weird syntax… it would be really nice if i just had some functionality of RoR in my PHP/Smarty apps.. well that ActiveRecord class in PHP would be just great!

    well, i also found out that there is PHP on Trax, wich seems to be a clone of RoR and has most (all?) the base classes implemented, but as i was looking at the source code, some parts seem to really be integrated in Trax, but i think it might be worthy to have a look ;) (http://www.phpontrax.com)

    Btw, I probably won’t be using Ruby on Rails or PHP on Trax, because I’m too used to PHP and Smarty… but I’ll definetly try to use some sort of standalone ActiveRecord in PHP.

  6. Nuno Mariz on January 20th, 2006

    My ActiveRecord implementation is 100% working(PHP4 and PHP5 versions) for one table without external keys.
    Right now i’m trying to figure out the best way to fetch a Record(or a Recordset) with foreign keys data. Maybe the best way is to delegate this to another pattern, like “Foreign Key Mapping“. My concerns now is in the performance field.
    In the second part II i will release some code, so stay tune.

  7. B. Remy on March 19th, 2006

    no more part II ? did u gave up on Active Record ?

  8. Nuno Mariz on March 20th, 2006

    Hi,
    Actually, i’ve already implemented the Active Record pattern just like Martin Fowler describes it. Right now i’m trying put together the foreigns tables relations, not that is difficult but i’m trying to figure out the best and the light way of doing it.
    The ZActiveRecord has not convinced me. Too much rules about the table and field names, etc.
    The second part will arrive soon as i have some free time.

  9. Ronald on May 8th, 2006

    This looks great - I’ve been looking at different ways of implementing ORM, and specifying the table name in the constructor follows my thinking entirely. Would you be kind enough to share your source?

  10. Nuno Mariz on May 8th, 2006

    Yes,
    In an couple of weeks(it’s a promise), I’m very very busy right now.

  11. Sam on September 13th, 2006

    Are you busy yet?

  12. Nuno Mariz on September 13th, 2006

    Yes, a lot. Read this.
    But is not forgotten.

  13. dodik on October 31st, 2006

    Congratulations about what you know ;)

    We’re still waiting for the release of your code.

  14. Nuno Mariz on October 31st, 2006

    Hi, now I have some time to work on it.
    Wait 1-2 weeks for the release.

    ..and, thanks ;)

  15. Solid on November 26th, 2006

    Any news?

  16. Jesse on December 31st, 2006

    Maybe you should make the release of this code your resolution for next year.

  17. Nuno Mariz on January 2nd, 2007

    Stay tuned this weekend ;)

  18. Leonel on February 6th, 2007

    Hey Nuno, looking forward for part II.

  19. Siemen Paulsen on February 18th, 2007

    I think it’s pretty clear that Nuno is not going to release the code. Why don’t you try CakePHP (cakephp.org), which is so much better than his code will ever be.

  20. Nuno Mariz on February 18th, 2007

    No need to release the code than.

Leave a reply

You must be logged in to post a comment.