Flat or deep hierarchy of model/db classes

Not for 'how-to' coding questions but PHP theory instead, this forum is here for those of us who wish to learn about design aspects of programming with PHP.

Moderator: General Moderators

Post Reply
matthijs
DevNet Master
Posts: 3360
Joined: Thu Oct 06, 2005 3:57 pm

Flat or deep hierarchy of model/db classes

Post by matthijs »

Ok, I've been hitting a wall I think. Been studying a bunch of advanced books on object oriented programming and design patterns and have a sort of clear understanding of the major design patterns used in models and db classes, like Table gateways, Active records, Datamappers, Row data gateways, etc etc

But one thing that is frustrating to me at this moment is that all examples given are very simple. Too simple. In all those books they apply these advanced patterns to a single db table with 3 fields. Fair enough, but even in the most basic web application with just a few tables things get much more complicated.

I'll try to explain the issue as clear as possible.

Dealing with a single table is easy. You have a class User with fields name, email, password. Methods Save, Find, Delete, Update. Now you can apply every pattern to this until the real sql is hidden so deep down you'll never have to view it again. Everybody's happy.

But let's take another example. A blog post. That has fields: Title, Bodytext, Author, Date, Category. Easy enough. But wait, designing your db you have neatly separated the Author to it's own table, as well as Categories. So when you save a blogpost from your controller, the Blogpost class is actually saving an AuthorId and a categoryId
So now your class Blogpost looks like

Code: Select all

 
class Blogpost {
  public function save(){
     // save Title, Bodytext, AuthorID, Date, CategoryId
  }
}
 
Now my question: were do I put all the logic needed to get those references sorted out?

From the controllers point of view, the easiest would be to just hand over all the posted data to the Blogpost model and let the Blogpost model figure out how to save everything in the right tables. That would mean the Blogpost class method Save instantiates an Author class and Category class, and checks if the author and category already exists, get their id's. etc etc

Or, the controller has to:
- get the author name posted.
- check the author table if that author already exists
-- if so get the corresponding authorid
-- if not, insert the author in author table, and then get the id
- check the category table if the category posted already exists
-- if so get the corresponding categoryid
-- if not, insert the category in category table, and then get the id
- finally, get all data together and insert into blogpost table.

Either one of them has to do this. But who?
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Re: Flat or deep hierarchy of model/db classes

Post by Christopher »

Part of your confusion may be the difference between a Model class and patterns such as TableDataGateway, RowDataGateway, ActiveRecords, DataMapper, etc. A Model is the representation in code of a thing in your system. The patterns are commons solution for accessing data. The confusion comes because often the Model is implemented as one of those patterns. Rails and its kin are famous for using their ActiveRecord+OR/M hybrid to solve every problem. So when reading you may hear the terms being mixed.

Models can many times be implemented with one of those patterns, but more often they use one or more of those patterns internally to access the datasource. Design the Model first and then see if using one or more patterns is appropriate.
(#10850)
matthijs
DevNet Master
Posts: 3360
Joined: Thu Oct 06, 2005 3:57 pm

Re: Flat or deep hierarchy of model/db classes

Post by matthijs »

Sorry, maybe I didn't made my question very clear. I do understand the difference between a model and the db patterns. I also do understand that in practice, a model will often contain a close connection to the db, in some way. Can be an active record, table gateway, etc.

I guess the two main points of my post were:
- I'd like to see more complex examples. Even in Jason's book about design pattern's the data mapper just deals with a single table.
- were would one put the logic in the example I gave. In the controller or in a sort of parent controller? I understand this is a difficult question to answer, as much will depend on the specific project. But what if you'd just stick with this example?

Code: Select all

 
class ArticleModel {
  function save($title,$text, $author,$category){
    // first check if the posted author already exists
    $authormodel = new Author();
    if($authormodel->exists($author)){
      $authorid = $authormodel->getId($author);
    } else {
       $authormodel->save($author);
       $authorid = $authormodel->getLastId();
    }
    // now repeat for all logic related to the category 
 
    // now we have the authorId, vategoryid and all data and we can insert that in the Article table
    $this->db->query("insert into articles title, text, authorid,... ");
  }
}
 
This is a good solution from the Controller's point of view, as the controller only has to call $article->save(...), without having to deal with all the logic of the related models.

But is this somehow how it's often done?
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Re: Flat or deep hierarchy of model/db classes

Post by Christopher »

Yes, I think $article->save() is a better interface than $article->insert() and $article->update() because the you are better separating concerns.
(#10850)
User avatar
Maugrim_The_Reaper
DevNet Master
Posts: 2704
Joined: Tue Nov 02, 2004 5:43 am
Location: Ireland

Re: Flat or deep hierarchy of model/db classes

Post by Maugrim_The_Reaper »

Either one of them has to do this. But who?
Let's say you have an EntryController with add() and edit() methods. Do you intend on duplicating the logic to save entries to each method? If not, that logic (and the validation of categoryId/authorId) likely belongs in the Model's save() method somewhere.

It really is important, just for emphasis, to differentiate between Model and the database access patterns. There are weird ideas out there about writing a Model on top of a database access solution - I believe you should write the database access solution under the Model. Model first, then assess access solutions like ORMs/DataMappers/etc.

Some Models only need simple access means, others demand more complex solutions. In the Zend Framework you see boatloads of people fighting to fit a Model onto Zend_Db, even if Zend_Db is obviously the wrong peg for that hole. I think I've used Zend_Db three times in total - it sucks badly for anything really complex that an ORM could solve in 10 seconds.

Your last example works for me. I'd probably have a helper method for grabbing an Author model just so it's isolated and potentially reusable.
matthijs
DevNet Master
Posts: 3360
Joined: Thu Oct 06, 2005 3:57 pm

Re: Flat or deep hierarchy of model/db classes

Post by matthijs »

Ok cool, thanks for your replies. It's getting clearer with each day :)
It really is important, just for emphasis, to differentiate between Model and the database access patterns. There are weird ideas out there about writing a Model on top of a database access solution - I believe you should write the database access solution under the Model. Model first, then assess access solutions like ORMs/DataMappers/etc.

I think I understand what you mean.

So: first you design the Model. That's were you start when you build your web app. Say a class for Articles, a class for Authors, a class for Categories. Each of those get the right methods so that controllers have an easy interface to put stuff in, retrieve and manipulate the models. Let's say
$article->save();
Now the controller doesn't need to care in any way how the Model persists the data. Could be a file, could be a database, anything.

Then, next step, depending on your needs and the complexity of the model, you build a persistence layer below the model layer. In most cases that would be a db. Then, again depending on the complexity you could just write sql queries strait in the few model classes:

Code: Select all

 
class Article{
  function save(){
     $sql = "INSERT INTO ... ";
     $this->db->query($sql);
  }
}
 
or have a more complex db interaction layer deal with that so that you don't have all those sql queries in the model classes.

That's about right isn't it?
In the Zend Framework you see boatloads of people fighting to fit a Model onto Zend_Db, even if Zend_Db is obviously the wrong peg for that hole.
How would I envision that exactly? Having db classes with properties for the model items?
User avatar
Maugrim_The_Reaper
DevNet Master
Posts: 2704
Joined: Tue Nov 02, 2004 5:43 am
Location: Ireland

Re: Flat or deep hierarchy of model/db classes

Post by Maugrim_The_Reaper »

That's about right isn't it?
That's the general idea. A lot of it is knowing what you want to Model early enough that you pick an access solution that fits. Too late and your API might become more difficult to modify.
How would I envision that exactly? Having db classes with properties for the model items?
As above - get your Models visualised early enough that a decision on what kind of database access to use is easier. The problem with the Zend Framework is that it only offers one solution, and it's not a really great one at that. Just one level above SQL is barely adequate. Bare in mind those using Rails get the same problem - trying to fit Models onto ActiveRecord even if ActiveRecord is obviously causing problems.

This is all really down to applying OO - you design a Model with a certain API so that underlying changes down the line in how it operates under the hood don't break backwards compatibility.

It sounds more complex than it is in reality ;). In many cases a Model's save() with map exactly to an ORMs save(), but that doesn't mean they're identical. For example, I might have a Model save() which uses HTMLPurifier to clean up HTML before called the ORMs save() - there will be logic sitting between the Model and the Access Layer.
Post Reply