SitePoint Sponsor

User Tag List

Results 1 to 4 of 4
  1. #1
    SitePoint Enthusiast
    Join Date
    Nov 2004
    Location
    Canberra, Australia
    Posts
    66
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Suggestions for my data model/ORM approach?

    Hi all,

    Apologies if what I'm about to mention has been discussed to death already, but I'm just having trouble getting my head around a design issue to do with my web apps. A bit of back story... a few years back I made my own framework in PHP4 (it was, perhaps mistakenly, similar in operation to Struts)... it was never released publicly and we used it in-house to create a wide range of sites, for which it worked well enough, despite some major performance tuning and optimisation (the number of things it was doing per R/R cycle was *ridiculous*, as was the number of object instances created)...

    Anyway, these days I've pretty much abandoned it in favour of a very lightweight... uhh... I dunno if you'd even call it a framework; it's more of a set of mostly static classes with commonly-used functionality, config arrays, include() based templates with minimal scriptlet code for views, and the odd object instance here and there mixed with Page Controllers to run it all. It's pretty old school really, and while it has much, *much* room for improvement, it's quick and easy and works well for most sites we care to throw at it.

    But I'll stop boring you with back story and now bore you with the issue at hand. It's to do with how I handle my "model" as such. What I've been doing currently (and this can change from project to project!) is structuring my model as classes much like this (let's use a blog for example - the code is not meant to be functional, it's more of an example of structure):

    PHP Code:
    class Record
    {
       
    /* some basic common Record functions as well as some abstract: */

       
    function save();
       function 
    delete();

       function 
    toRecord();
       function 
    toDatabase();

       function 
    fromRecord($record);
       function 
    fromDatabase($record);

       var 
    $id;
    }

    class 
    BlogEntry extends Record
    {
       function 
    save()
       {
          
    /* define insert or update SQL and save accordingly
       }

       function delete()
       {
          /* deletes this object from the DB */
       
    }

       function 
    toRecord()
       {
          
    /* converts this object to a record array for use in a web form */
       
    }

       function 
    toDatabase()
       {
          
    /* converts this object to a record array for a database operation (slashes added, foreign ID's obtained etc.) */
       
    }

       function 
    fromRecord($record)
       {
          
    /* defines this object from the given web form record */
       
    }

       function 
    fromDatabase($record)
       {
          
    /* defines this object from the given database result record */
       
    }

       function 
    FindAll()
       {
          
    /* static: answer an array of all BlogEntry objects */
       
    }

       function 
    FindById($id)
       {
          
    /* static: answer the BlogEntry object with the given ID */
       
    }

       var 
    $title;
       var 
    $body;
       var 
    $date;
       var 
    $author;  // <-- this is a BlogAuthor object


    Now, if you've got this far, here is my question: how much should I pull into memory as resolved objects? In this example, the BlogEntry has a BlogAuthor object associated with it, which in turn has an ID. When the record is saved, the "toDatabase()" function knows to return the $author->id as to create a foreign key for the DB operation. Vice versa, the "fromDatabase()" function does the opposite - it takes the obtained foreign key ID, and calls "BlogAuthor::FindById($id)" to obtain the object associated with this one.

    I guess this is all simple ORM (object relational mapping)... but how far do you go with this? What if we have multiple objects (lists, collections) associated - do we pull all them in as well? What about objects associated with those objects? I guess Lazy Load could come into play here (like a good man, I do have PoEAA), but it's always confused me and I've wondered if it's overkill for PHP stuff.

    So I guess what I'm asking is:

    a) is this approach to model data sensible, or flawed?
    b) should I be looking at implementing Lazy Load, and if so, what method is recommended (concerning 1:1 and 1:M relations)
    c) because each PHP R/R cycle is so fleeting, should I be worried about model/data objects at all? Should I just be playing around with DB record arrays? Is it overkill?

    I would love to hear the thoughts and opinions of those here who are much more intelligent and experienced than I. Oh and greetings from Canberra, AU - it's BLOODY cold here at the moment.

    Cheers,

    {R}

  2. #2
    eschew sesquipedalians silver trophy sweatje's Avatar
    Join Date
    Jun 2003
    Location
    Iowa, USA
    Posts
    3,749
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    One approach I have used is to have something like an author_id field, which gets mapped to the object as an attribute using generic code which transforms the database row to the object which I have all models descend from (in your case, this looks like and ActiveRecord pattern, where I tend to favor a TableDataGateway myself). For the custom Model class, I might ad an author() function which would allow me to perform lazy loading of the author object and (since I am using php5 which supports method chaining) do things like:
    PHP Code:
    echo $model->author()->full_name
    Jason Sweat ZCE - jsweat_php@yahoo.com
    Book: PHP Patterns
    Good Stuff: SimpleTest PHPUnit FireFox ADOdb YUI
    Detestable (adjective): software that isn't testable.

  3. #3
    SitePoint Enthusiast
    Join Date
    Nov 2004
    Location
    Canberra, Australia
    Posts
    66
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by sweatje View Post
    One approach I have used is to have something like an author_id field, which gets mapped to the object as an attribute using generic code which transforms the database row to the object which I have all models descend from (in your case, this looks like and ActiveRecord pattern, where I tend to favor a TableDataGateway myself). For the custom Model class, I might ad an author() function which would allow me to perform lazy loading of the author object and (since I am using php5 which supports method chaining) do things like:
    PHP Code:
    echo $model->author()->full_name
    Hi, Jason... thanks for your reply... so what it looks like you're suggesting there is a lazy load implementation as such:

    1. Hold a pointer (ID) to an object.
    2. Always use a method to access the object, which first checks if it has been loaded or not...
    3. If not, load the object from the DB, if so, just return the already obtained object.

    Does that sound right? How about collections of objects? I remember PoEAA mentioning that collections should be considered carefully as you will want to grab a whole heap of objects at once using a single query rather than a query for each object in the collection.

    Regarding TableDataGateway vs ActiveRecord, would you be able to post the reasons why you prefer TableDataGateway? I don't really have a preference at the moment, it just seems the stuff I've been doing resembles ActiveRecord, and I'd like to know of any advantages of the alternative patterns.

    Cheers,

    {R}

  4. #4
    eschew sesquipedalians silver trophy sweatje's Avatar
    Join Date
    Jun 2003
    Location
    Iowa, USA
    Posts
    3,749
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by {RainmakeR} View Post
    Hi, Jason... thanks for your reply... so what it looks like you're suggesting there is a lazy load implementation as such:

    1. Hold a pointer (ID) to an object.
    2. Always use a method to access the object, which first checks if it has been loaded or not...
    3. If not, load the object from the DB, if so, just return the already obtained object.

    Does that sound right?
    With regards to #1, it is not a pointer, but rather just a piece of data which you can used with the "findById()" method of your finder object.


    Quote Originally Posted by {RainmakeR} View Post
    How about collections of objects? I remember PoEAA mentioning that collections should be considered carefully as you will want to grab a whole heap of objects at once using a single query rather than a query for each object in the collection.
    In part, see my answer below regarding TableDataGateway vs ActiveRecord, but one additional thought here is inside of your Finder methods of your gateway object, you can implement a registry (called an IdentityMap as a design pattern) to hold instances of the objects of that type which you have already loaded. This can let you avoid reloading them from the database, and may allow you to intelligently query a result set from your database and populate a collection of your model objects.


    Quote Originally Posted by {RainmakeR} View Post
    Regarding TableDataGateway vs ActiveRecord, would you be able to post the reasons why you prefer TableDataGateway? I don't really have a preference at the moment, it just seems the stuff I've been doing resembles ActiveRecord, and I'd like to know of any advantages of the alternative patterns.

    Cheers,

    {R}
    My web applications tend to be reporting applications, and as such tend to get results sets back composed of many rows rather than working with an individual row at a time (which would be more common with a transactional type of application). These two design patterns could be summarized as ActiveRecord is the simplest data access pattern focused on at the row level, and TableDataGateway is the simplest data access pattern focused at the result set level. Since my application tend to operate at the result set level, it is more natural for me to want to operate with a TableDataGateway in preference to the ActiveRecord pattern.

    HTH

    Regards,
    Jason Sweat ZCE - jsweat_php@yahoo.com
    Book: PHP Patterns
    Good Stuff: SimpleTest PHPUnit FireFox ADOdb YUI
    Detestable (adjective): software that isn't testable.


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •