<?xml version="1.0" encoding="UTF-8"?><!-- generator="wordpress/2.3.3" -->
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	>
<channel>
	<title>Comments on: DomainObject and DataMappers</title>
	<link>http://loveandtheft.org/2008/04/07/domainobject-and-datamappers/</link>
	<description>Mr Quinn, one word for your fans? "Ehm, astronaut."</description>
	<pubDate>Fri, 21 Nov 2008 03:13:01 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.3.3</generator>
		<item>
		<title>By: Erik</title>
		<link>http://loveandtheft.org/2008/04/07/domainobject-and-datamappers/#comment-537</link>
		<dc:creator>Erik</dc:creator>
		<pubDate>Wed, 09 Jul 2008 21:47:07 +0000</pubDate>
		<guid>http://loveandtheft.org/2008/04/07/domainobject-and-datamappers/#comment-537</guid>
		<description>I'm curious as to this DomainObject-fellow. His children, how is the error-handling taken care of? Lets say I have a Post-object, and it has a $message-field. The message cannot be empty, it cannot be longer than 200 characters and let's say (for the fun of it) it cannot contain the word "sausage". Is all this checked inside or outside the Post-object? For example:

http://pastebin.se/195238

Or how exactly is it handled in a smooth'n'efficient way?</description>
		<content:encoded><![CDATA[<p>I&#8217;m curious as to this DomainObject-fellow. His children, how is the error-handling taken care of? Lets say I have a Post-object, and it has a $message-field. The message cannot be empty, it cannot be longer than 200 characters and let&#8217;s say (for the fun of it) it cannot contain the word &#8220;sausage&#8221;. Is all this checked inside or outside the Post-object? For example:</p>
<p><a href="http://pastebin.se/195238" rel="nofollow">http://pastebin.se/195238</a></p>
<p>Or how exactly is it handled in a smooth&#8217;n'efficient way?</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Toowit</title>
		<link>http://loveandtheft.org/2008/04/07/domainobject-and-datamappers/#comment-38</link>
		<dc:creator>Toowit</dc:creator>
		<pubDate>Fri, 11 Apr 2008 06:33:18 +0000</pubDate>
		<guid>http://loveandtheft.org/2008/04/07/domainobject-and-datamappers/#comment-38</guid>
		<description>Simply outstanding ^_^! I like posts like that. Your blog is added to my favorites ;-). Continue writing.</description>
		<content:encoded><![CDATA[<p>Simply outstanding ^_^! I like posts like that. Your blog is added to my favorites ;-). Continue writing.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Charles Odili</title>
		<link>http://loveandtheft.org/2008/04/07/domainobject-and-datamappers/#comment-37</link>
		<dc:creator>Charles Odili</dc:creator>
		<pubDate>Wed, 09 Apr 2008 03:54:37 +0000</pubDate>
		<guid>http://loveandtheft.org/2008/04/07/domainobject-and-datamappers/#comment-37</guid>
		<description>This is both quite good and timely, it's treatment of the DataMapper pattern is elegant and clear, however I am just trying to start application development with patterns and had to go through the Apress title 'PHP Objects, Patterns and Practice' which also dealt with this pattern and evolved it to something quite complex but more thorough, my issue is how do you use all these patterns with say the Zend framework's MVC in an Ajax application, putting them altogether just eludes me. Great post, thanks.</description>
		<content:encoded><![CDATA[<p>This is both quite good and timely, it&#8217;s treatment of the DataMapper pattern is elegant and clear, however I am just trying to start application development with patterns and had to go through the Apress title &#8216;PHP Objects, Patterns and Practice&#8217; which also dealt with this pattern and evolved it to something quite complex but more thorough, my issue is how do you use all these patterns with say the Zend framework&#8217;s MVC in an Ajax application, putting them altogether just eludes me. Great post, thanks.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Fredrik Holmström</title>
		<link>http://loveandtheft.org/2008/04/07/domainobject-and-datamappers/#comment-35</link>
		<dc:creator>Fredrik Holmström</dc:creator>
		<pubDate>Tue, 08 Apr 2008 20:07:47 +0000</pubDate>
		<guid>http://loveandtheft.org/2008/04/07/domainobject-and-datamappers/#comment-35</guid>
		<description>Mike Seth, (I don't mean to flame you either) Maybe it wasn't clear in my example, but when talking about decoupling the application from the database I was talking about decoupling the actual domain objects from the way they are stored, which I do (although it's very simple and I still hard-code the Mapper+Method names, but again they are only examples on ~50 lines of code and not a complete ORM) - and never mention database independence (which is one of the great lies of our programming generation, or well - at least mine.) - and yes to achieve even this separation I would need a good high level layer that abstracts it all away,  but again - they are examples meant for the people that have no or almost no idea on how to work with the very basics of a data mapper, the concept if you will.

The implicit caching with the identity map is indeed a minefield, but you shouldn't really clone a domain object now should you? And the race condition will always exist in one way or another no matter how much you try to work around it (at least in php) due to the nature of php and it's share-nothing-architecture, no?</description>
		<content:encoded><![CDATA[<p>Mike Seth, (I don&#8217;t mean to flame you either) Maybe it wasn&#8217;t clear in my example, but when talking about decoupling the application from the database I was talking about decoupling the actual domain objects from the way they are stored, which I do (although it&#8217;s very simple and I still hard-code the Mapper+Method names, but again they are only examples on ~50 lines of code and not a complete ORM) - and never mention database independence (which is one of the great lies of our programming generation, or well - at least mine.) - and yes to achieve even this separation I would need a good high level layer that abstracts it all away,  but again - they are examples meant for the people that have no or almost no idea on how to work with the very basics of a data mapper, the concept if you will.</p>
<p>The implicit caching with the identity map is indeed a minefield, but you shouldn&#8217;t really clone a domain object now should you? And the race condition will always exist in one way or another no matter how much you try to work around it (at least in php) due to the nature of php and it&#8217;s share-nothing-architecture, no?</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Mike Seth</title>
		<link>http://loveandtheft.org/2008/04/07/domainobject-and-datamappers/#comment-34</link>
		<dc:creator>Mike Seth</dc:creator>
		<pubDate>Tue, 08 Apr 2008 19:08:11 +0000</pubDate>
		<guid>http://loveandtheft.org/2008/04/07/domainobject-and-datamappers/#comment-34</guid>
		<description>I don't mean to flame you or anything, but if you are trying to decouple your database from your application, this pattern is doing the exact opposite. By hardwiring the relationship between the field names and the method names, and by adding application-specific methods, even as simple as findAll(), you are in fact binding your application to your storage method. This is why serious ORM such as Doctrine has a notion of abstract "domain objects" and a superior query language for their manipulation; in order to truly make your code database-independent, you need a high level (and fat) indirection layer that provides reliable interfaces both to your application and to the database. 

Also, I spotted that you use implicit caching in your example. This is a great idea, but it is also a minefield. Imagine if I clone one of your object instances, change a field and save it. Worse yet, imagine that another concurrent script execution modifies and saves it. This inevitably means that all subsequent code in the current execution will break, because any subsequent request for the object would return an inaccurate copy of an object, which will be modified and saved back eventually, resulting in mysterious data loss that is nearly impossible to debug.</description>
		<content:encoded><![CDATA[<p>I don&#8217;t mean to flame you or anything, but if you are trying to decouple your database from your application, this pattern is doing the exact opposite. By hardwiring the relationship between the field names and the method names, and by adding application-specific methods, even as simple as findAll(), you are in fact binding your application to your storage method. This is why serious ORM such as Doctrine has a notion of abstract &#8220;domain objects&#8221; and a superior query language for their manipulation; in order to truly make your code database-independent, you need a high level (and fat) indirection layer that provides reliable interfaces both to your application and to the database. </p>
<p>Also, I spotted that you use implicit caching in your example. This is a great idea, but it is also a minefield. Imagine if I clone one of your object instances, change a field and save it. Worse yet, imagine that another concurrent script execution modifies and saves it. This inevitably means that all subsequent code in the current execution will break, because any subsequent request for the object would return an inaccurate copy of an object, which will be modified and saved back eventually, resulting in mysterious data loss that is nearly impossible to debug.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Fredrik Holmström</title>
		<link>http://loveandtheft.org/2008/04/07/domainobject-and-datamappers/#comment-33</link>
		<dc:creator>Fredrik Holmström</dc:creator>
		<pubDate>Tue, 08 Apr 2008 13:44:37 +0000</pubDate>
		<guid>http://loveandtheft.org/2008/04/07/domainobject-and-datamappers/#comment-33</guid>
		<description>Chris C and Heresy.Mc - thanks for your comments.

Kyle:
Yes, in fact the original article and examples had a LazyLoad class that worked like a proxy for the User-object in the Post, but I felt that the examples became to complicated and the article was getting to long so I decided to cut it as I thought of this as more of a introduction do DO/DM:ing then a "complete" guide to all techniques you can use (locking, unit-of-work, value fields, etc.), maybe for a follow up article. The thing about writing articles is to know where to limit yourself, I could've written a smaller doctoral thesis on this subject ;p

About the getObjectForRow()-method, I think I just missed putting protected in front of it and creating an abstract base method in DataMapper(), or I could've left it out on purpose to keep things clear - don't remember.

Also I wouldn't tangle the Domain Objects with knowledge of the mappers, as one of the main benefits of using a Data Mapper is that your DO's are completely ignorant of any type of database / persistence and can act as pure in memory objects.

 - Fredrik</description>
		<content:encoded><![CDATA[<p>Chris C and Heresy.Mc - thanks for your comments.</p>
<p>Kyle:<br />
Yes, in fact the original article and examples had a LazyLoad class that worked like a proxy for the User-object in the Post, but I felt that the examples became to complicated and the article was getting to long so I decided to cut it as I thought of this as more of a introduction do DO/DM:ing then a &#8220;complete&#8221; guide to all techniques you can use (locking, unit-of-work, value fields, etc.), maybe for a follow up article. The thing about writing articles is to know where to limit yourself, I could&#8217;ve written a smaller doctoral thesis on this subject ;p</p>
<p>About the getObjectForRow()-method, I think I just missed putting protected in front of it and creating an abstract base method in DataMapper(), or I could&#8217;ve left it out on purpose to keep things clear - don&#8217;t remember.</p>
<p>Also I wouldn&#8217;t tangle the Domain Objects with knowledge of the mappers, as one of the main benefits of using a Data Mapper is that your DO&#8217;s are completely ignorant of any type of database / persistence and can act as pure in memory objects.</p>
<p> - Fredrik</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Kyle</title>
		<link>http://loveandtheft.org/2008/04/07/domainobject-and-datamappers/#comment-32</link>
		<dc:creator>Kyle</dc:creator>
		<pubDate>Tue, 08 Apr 2008 13:10:53 +0000</pubDate>
		<guid>http://loveandtheft.org/2008/04/07/domainobject-and-datamappers/#comment-32</guid>
		<description>It's nice to see a sophisticated article about PHP and persistence layers - thanks for this excellent work.

I'm working with a similar approach for a while now an the only drawback of your solution is, that for larger tables resolving associated classes immediately (like in Post-&#62;User) might be a performance issue - especially when using your implementation of PostMapper::findAll(). Using lazy loading for associated classes - in most cases - solves such problems.

So, one would have an internal variable $_userId (or whatever) and the implementation of Post-&#62;getUser() would be like this:

class Post
{
	// ...
	public function getUset() { UserMapper::find( $this-&#62;_userId ); }
	// ...
}

This solves also the problem of association chains: Imagine an enhanced version of your model, where you have (multiple) addresses associated to users. In other words you have a foreign key from the address table to the user table and from the post table to the user table. You'd have to change your implementation of PostMapper::findAll(), which in first place has nothing to do with the address table (and IMHO should't have to).

And further more the PostMapper::getObjectForRow() doesn't return a valid object when called not from within findAll(). Public interfaces shouldn't depend on the the way they are used.

And to finally spin the wheel a bit further: Think of a solution that hides the concrete persistence layer behind the DomainObject (the persistence layer might be changed from database to XML or a concrete db to another (MySQL to Oracle)). The DomainObject would then function as a bridge to the Mapper like this:

$yoda = new User( "Yoda" );
$yoda-&#62;save();
var_dump( $yoda );
$yoda2 = User::find( $yoda-&#62;getId() );

Regards, Kyle</description>
		<content:encoded><![CDATA[<p>It&#8217;s nice to see a sophisticated article about PHP and persistence layers - thanks for this excellent work.</p>
<p>I&#8217;m working with a similar approach for a while now an the only drawback of your solution is, that for larger tables resolving associated classes immediately (like in Post-&gt;User) might be a performance issue - especially when using your implementation of PostMapper::findAll(). Using lazy loading for associated classes - in most cases - solves such problems.</p>
<p>So, one would have an internal variable $_userId (or whatever) and the implementation of Post-&gt;getUser() would be like this:</p>
<p>class Post<br />
{<br />
	// &#8230;<br />
	public function getUset() { UserMapper::find( $this-&gt;_userId ); }<br />
	// &#8230;<br />
}</p>
<p>This solves also the problem of association chains: Imagine an enhanced version of your model, where you have (multiple) addresses associated to users. In other words you have a foreign key from the address table to the user table and from the post table to the user table. You&#8217;d have to change your implementation of PostMapper::findAll(), which in first place has nothing to do with the address table (and IMHO should&#8217;t have to).</p>
<p>And further more the PostMapper::getObjectForRow() doesn&#8217;t return a valid object when called not from within findAll(). Public interfaces shouldn&#8217;t depend on the the way they are used.</p>
<p>And to finally spin the wheel a bit further: Think of a solution that hides the concrete persistence layer behind the DomainObject (the persistence layer might be changed from database to XML or a concrete db to another (MySQL to Oracle)). The DomainObject would then function as a bridge to the Mapper like this:</p>
<p>$yoda = new User( &#8220;Yoda&#8221; );<br />
$yoda-&gt;save();<br />
var_dump( $yoda );<br />
$yoda2 = User::find( $yoda-&gt;getId() );</p>
<p>Regards, Kyle</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Heresy.Mc</title>
		<link>http://loveandtheft.org/2008/04/07/domainobject-and-datamappers/#comment-31</link>
		<dc:creator>Heresy.Mc</dc:creator>
		<pubDate>Tue, 08 Apr 2008 12:18:16 +0000</pubDate>
		<guid>http://loveandtheft.org/2008/04/07/domainobject-and-datamappers/#comment-31</guid>
		<description>This sound perfectly.
I am a PHPer also, and learn more from your post,thanks.</description>
		<content:encoded><![CDATA[<p>This sound perfectly.<br />
I am a PHPer also, and learn more from your post,thanks.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Chris C</title>
		<link>http://loveandtheft.org/2008/04/07/domainobject-and-datamappers/#comment-30</link>
		<dc:creator>Chris C</dc:creator>
		<pubDate>Tue, 08 Apr 2008 11:02:26 +0000</pubDate>
		<guid>http://loveandtheft.org/2008/04/07/domainobject-and-datamappers/#comment-30</guid>
		<description>Fantastic article! Clear, well thought out code and enough 'back-story' to put the article in context without straying from the point. I had not long started on a sort of poor-man's ActiveRecord clone for a 'fun' project I've been toying with, I think now I will go back and rewrite the DB side of things using this approach - not only will it be less DB intensive thanks to the map, but this way also seems to 'fit' a little easier with my own personal way of thinking. Thanks greatly, and I look forward to exploring your past articles!</description>
		<content:encoded><![CDATA[<p>Fantastic article! Clear, well thought out code and enough &#8216;back-story&#8217; to put the article in context without straying from the point. I had not long started on a sort of poor-man&#8217;s ActiveRecord clone for a &#8216;fun&#8217; project I&#8217;ve been toying with, I think now I will go back and rewrite the DB side of things using this approach - not only will it be less DB intensive thanks to the map, but this way also seems to &#8216;fit&#8217; a little easier with my own personal way of thinking. Thanks greatly, and I look forward to exploring your past articles!</p>
]]></content:encoded>
	</item>
</channel>
</rss>
