Object Relational Mapping

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

chris12295
Forum Contributor
Posts: 113
Joined: Sun Jun 09, 2002 10:28 pm
Location: USA
Contact:

Object Relational Mapping

Post by chris12295 »

What are some good tips to designing an ORM class? Specifically, is it more efficient for the object to represent a row in a table or the whole table?
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Post by Christopher »

Typically the mapping would be between an object and a row or related rows from several tables.
(#10850)
chris12295
Forum Contributor
Posts: 113
Joined: Sun Jun 09, 2002 10:28 pm
Location: USA
Contact:

Post by chris12295 »

So by mapping rows wouldn't the queries to the database be inefficient if you need several user's info? For example if the object maps to a row then each user would require a seperate database query
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Post by Chris Corbyn »

chris12295 wrote:So by mapping rows wouldn't the queries to the database be inefficient if you need several user's info? For example if the object maps to a row then each user would require a seperate database query
Not really no. What usually happens is that all rows are pulled out as normal, then objects are hydrated with the values from the resultset before finally being returned as an array. If a single object represents a row it makes it easier to create new rows simply by creating new objects. It's a nicer interface.

Code: Select all

$user = new User();
$user->setUsername("foo");
$user->setPassword(md5("xxxxx"));
$user->save();

echo $user->getId();
It also makes it easy to join records at an object level:

Code: Select all

$thread = new Thread();
$thread->setTitle("foobar");
$thread->save();

$forumPost->setThread($thread);
$forumPost->save();
You may want to look at ActiveRecord too.
User avatar
Kieran Huggins
DevNet Master
Posts: 3635
Joined: Wed Dec 06, 2006 4:14 pm
Location: Toronto, Canada
Contact:

Post by Kieran Huggins »

Also check out Maugrim's awesome article on PHP data objects - just brilliant.

viewtopic.php?t=48499
wei
Forum Contributor
Posts: 140
Joined: Wed Jul 12, 2006 12:18 am

Post by wei »

Here is an implementation of active record, table gate, and a data mapper. The data mapper is a good supplement to active records when the query get very complex, while active records are great for simple data access.

Docs and an example using the Northwind sample database (sqlite) are included. Requires php 5.1+ and the specific pdo database drivers.

http://xlab6.com/compact-db.zip

Wei.
Z3RO21
Forum Contributor
Posts: 130
Joined: Thu Aug 17, 2006 8:59 am

Post by Z3RO21 »

Kieran Huggins wrote:Also check out Maugrim's awesome article on PHP data objects - just brilliant.

viewtopic.php?t=48499
Kieran beat me to it, but he is absolutely right. That tutorial is a very in depth tutorial. It helped me understand and implement object relational mapping.
mikesmith76
Forum Commoner
Posts: 34
Joined: Fri Aug 25, 2006 7:10 am
Location: Manchester, UK

Post by mikesmith76 »

Hi all,

Sorry to hijack someone else's thread but I have a question about this topic. I've read Maugrim's tutorial and like the others found it to be an excellent read. However one part of it just doesn't feel right

Sticking with the example of a user, each object should contain the data for a single user. We would add / edit / delete a user by interacting with an object containing that user's data.

Copied from Maugrim's Tutorial

Code: Select all

<?php

$user = new User();
$user->setName('Maugrim');
$user->setEmail('email@example.com');
$user->setWww('http://blog.quantum-star.com');
$user->save(); // insert data on database table

?>
This is all great, but how about pulling multiple users at once. From the same tutorial Maugrim showed the following example

Code: Select all

<?php

$user_collection = new User();
$user_collection->getAll();
echo '<strong>List of User Names</strong><br /><br />';
foreach($user_collection as $key=>$user)
{
        echo $user->getName(), '<br />';
}

?>
So here we are using an object designed to hold a single user's information to build an array of users? This is the part that doesn't look or feel right to me. The tutorial did mention this is just meant as a brief example. The approach I am leaning towards at the moment would be using a UserCollection object as in

Code: Select all

$user_collection = new UserCollection();
$user_collection->getAll();

//then using iterator type logic
while($user_collection->hasNext()){
    //$user now contains an object of type User
    $user = $user_collection->getNext();
}
Am I on the right lines with this? Please don't take this as an attack against Maugrim, his tutorial is excellent and his knowledge is much greater than mine. I'm just trying to adapt his tutorial to how I like to see things organised.

Thanks all

Mike
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Post by Chris Corbyn »

Propel would do this:

Code: Select all

//Search criteria
$criteria = new Criteria();

$users = User::doSelect($criteria);
Using static methods as factories for objects which are an instance of the class they come from feels natural, so on that token, returning a collection of objects of that type seems logical too.

Of course, using Criteria like this means you can be smart about what you want:

Code: Select all

$criteria = new Criteria();
$criteria->add(User::GROUP, "moderator");

$users = User::doSelect($criteria); //all moderators
You can join tables with Criteria too, so because the above table probably isn't normalized, once normalized you'd have something like this.

Code: Select all

$criteria = new Criteria();
$criteria->addJoin(User::GROUP_ID, UserGroup::ID);
$criteria->add(UserGroup::TITLE, "moderator");

$users = User::doSelect($criteria); //all moderators
wei
Forum Contributor
Posts: 140
Joined: Wed Jul 12, 2006 12:18 am

Post by wei »

I think either approach is fine and both have trade-offs. Using collections, you may be able to construct a query that performs a batch insert and/or update (although you may that tricky if the table contains sequences and they need to be retrieved). Combining the fetching of collections in to the Record class is reasonable approach in simplifying the design.
mikesmith76
Forum Commoner
Posts: 34
Joined: Fri Aug 25, 2006 7:10 am
Location: Manchester, UK

Post by mikesmith76 »

Thanks for the reply, just found the Propel website so much more reading to go.

The main problem I'm having at the moment is i've never seen a large scale OOP application built in PHP, or any language for that matter. I'm just guessing as to how things like a collection of users should be organised, trying to educate my guesses with lots of reading!

I'm looking into ORM at the moment as I love the idea of being able to insert database records just by manipulating an object / set of objects. The code looks so much cleaner than having SQL statements littered around the place, and I imagine it will be much easier to maintain.

Thanks again
Mike
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Post by Chris Corbyn »

mikesmith76 wrote:I'm looking into ORM at the moment as I love the idea of being able to insert database records just by manipulating an object / set of objects. The code looks so much cleaner than having SQL statements littered around the place, and I imagine it will be much easier to maintain.
There are some things that ORM simply isn't going to do for you (complex SQL queries which don't actually select records). I think the main objective of ORM is to overcome the issue of working with a database in a fully object-oriented environment. ORM *usually* happens on top of an abstraction layer which cleans and optimizes the SQL too as you have seen. This inveitably makes it much easier turn around in 3 years time and say "ditch mysql, we're going to Oracle".

EDIT | Actually, I have to say one of the other big benefits of ORM is when working with MVC it's really easy to get Model data *cleanly* into the view.

Hmmm, I only only just noticed by Propel have stopped using Creole (their own abstracton layer) and implemented PDO instead.
mikesmith76
Forum Commoner
Posts: 34
Joined: Fri Aug 25, 2006 7:10 am
Location: Manchester, UK

Post by mikesmith76 »

Thanks for all the advice. I don't expect ORM to be a magical quick fix but definitely think it will be a useful tool.

You've mentioned Propel quite a few times so far, is this something you have a lot of experience with?
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Post by Chris Corbyn »

mikesmith76 wrote:You've mentioned Propel quite a few times so far, is this something you have a lot of experience with?
I have a little experience with it from working with the symfony framework. It's PHP5-only though. It seems to be held in pretty high regard.
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Post by Christopher »

I built a really simple Data Mapper example for an O/RM thread a while back. It was just to show the idea and never finished -- as I recall it still needed Unit of Work implemented. The code was posted here:

viewtopic.php?p=342096#342096
(#10850)
Post Reply