<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Rob Allen&#039;s DevNotes &#187; Around the web</title>
	<atom:link href="http://akrabat.com/category/around-the-web/feed/" rel="self" type="application/rss+xml" />
	<link>http://akrabat.com</link>
	<description>Developing PHP software in the Real World, by Rob Allen</description>
	<lastBuildDate>Wed, 01 Sep 2010 14:33:07 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>A new blog from someone new to PHP</title>
		<link>http://akrabat.com/php/a-new-blog-from-someone-new-to-php/</link>
		<comments>http://akrabat.com/php/a-new-blog-from-someone-new-to-php/#comments</comments>
		<pubDate>Sun, 13 Sep 2009 08:08:11 +0000</pubDate>
		<dc:creator>Rob...</dc:creator>
				<category><![CDATA[Around the web]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://akrabat.com/?p=771</guid>
		<description><![CDATA[I met Chris when he was temping for a client of mine doing data entry into an e-commerce system we were writing. Recently he contacted me to let me know that he has now started learning PHP and is starting to develop a career in web development with PHP. I was quite impressed that he [...]]]></description>
			<content:encoded><![CDATA[<p>I met Chris when he was temping for a client of mine doing data entry into an e-commerce system we were writing. Recently he contacted me to let me know that he has now started learning PHP and is starting to develop a career in web development with PHP. I was quite impressed that he had even managed to land himself some freelance work and had a client happy enough to pay him! </p>
<p>He asked me for some advice and I provided some information on the sorts of things he need to learn about and some ideas on where to find communities that will help. </p>
<p>I had recently read Cal Evans' <a href="http://blog.calevans.com/2009/08/10/php-and-community/">PHP and Community</a> post, which contains this gem:</p>
<blockquote><p>
Until all 4.6 million PHP developers are active in the community, there is always a seat at the table. If you are a PHP developer - junior level, architect level or just a weekend warrior - I urge you to get involved.</p>
<p>Start a blog and write about what you have learned. Trust me, if you put up something that isn’t accurate, someone will come along and correct you. That’s a win for everyone.
</p></blockquote>
<p>As a result, I also advised him to start a blog so that he can document what he now knows to the benefit of us all and also allow potential employers the opportunity to understand his skills much better than a mere CV can show.</p>
<p>He's taken this advice and <a href="http://jibbles.co.uk/">http://jibbles.co.uk/</a> has been born. It turns out that Chris is a very good writer - much better than I was when I started (and probably better than I am now too)!  If you are interested in watching a new coder develop into a better coder, then it may be worth keeping an eye on his blog. You could also comment periodically when he needs a pointer to something that he's probably never heard of before :)</p>
]]></content:encoded>
			<wfw:commentRss>http://akrabat.com/php/a-new-blog-from-someone-new-to-php/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Women in open source communities</title>
		<link>http://akrabat.com/around-the-web/women-in-open-source-communities/</link>
		<comments>http://akrabat.com/around-the-web/women-in-open-source-communities/#comments</comments>
		<pubDate>Fri, 01 May 2009 19:04:37 +0000</pubDate>
		<dc:creator>Rob...</dc:creator>
				<category><![CDATA[Around the web]]></category>
		<category><![CDATA[Me]]></category>

		<guid isPermaLink="false">http://akrabat.com/?p=620</guid>
		<description><![CDATA[An incident occurred at a Rails conference recently where pictures of scantily clad women were used on slides. The attitude behind the use of the images disturbs me. To be clear, this is not a Rails issue as I aware of a similar issue in the PHP community and it is prevalent in the the [...]]]></description>
			<content:encoded><![CDATA[<p>An incident occurred at a Rails conference recently where pictures of scantily clad women were used on slides. The attitude behind the use of the images disturbs me. To be clear, this is not a Rails issue as I aware of a similar issue in the PHP community and it is prevalent in the the entire IT industry.</p>
<p>Martin Fowler has <a target="_blank" href="http://martinfowler.com/bliki/SmutOnRails.html">summed up</a> pretty much how I feel about it: </p>
<blockquote><p>The nub is that whatever the presenter may think, people were offended - both in the talk and those who saw the slides later. It doesn't matter whether or not you think the slides were pornographic. The question is does the presenter, and the wider community, care that women feel <a target="_blank" href="http://www.ultrasaurus.com/sarahblog/2009/04/gender-and-sex-at-gogaruco/">disturbed, uncomfortable</a>,<a target="_blank" href="http://www.sarahmei.com/blog/?p=46"> marginalized and a little scared</a>.</p></blockquote>
<p>I find it discouraging that we need to ask this question in this day and age, but I'm assured by women I know in the IT industry, that they deal with prejudice because of their sex day in day out in their working lives.</p>
<p>Martin goes on to say: </p>
<blockquote><p>I have a different vision - one that sticks it to the suits so hard it will make their eyes water. How about a community where women are valued for their ability to program and not by the thickness of their skin? How about a community that edgily pushes new boundaries without reinforcing long running evils? Perhaps even a community where women reach equal numbers? Such a community would hand the suits the defeat in the long battle women have been fighting for centuries. I'd love to be part of that.</p></blockquote>
<p>Hear hear! That's what I want to be part of too. </p>
<p>I recommend that you read all of Martin Fowler's <a href="http://martinfowler.com/bliki/SmutOnRails.html">article</a> as it provides a good grounding in a lot of the issues involved, especially if you read the other articles he links to.</p>
]]></content:encoded>
			<wfw:commentRss>http://akrabat.com/around-the-web/women-in-open-source-communities/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Manning is on Twitter</title>
		<link>http://akrabat.com/zfia/manning-is-on-twitter/</link>
		<comments>http://akrabat.com/zfia/manning-is-on-twitter/#comments</comments>
		<pubDate>Thu, 19 Mar 2009 20:05:17 +0000</pubDate>
		<dc:creator>Rob...</dc:creator>
				<category><![CDATA[Around the web]]></category>
		<category><![CDATA[ZFiA]]></category>

		<guid isPermaLink="false">http://akrabat.com/?p=411</guid>
		<description><![CDATA[I use Twitter's search feature to create RSS feeds for useful terms, like "Zend Framework". Today I noticed a tweet from ManningBooks, my publisher for Zend Framework in Action! It turns out that they've put up a sample of the book on Scribed! Check out the book, then order it, remembering to use the coupon [...]]]></description>
			<content:encoded><![CDATA[<p>I use Twitter's search feature to create RSS feeds for useful terms, like "Zend Framework". Today I noticed a tweet from <a href="http://twitter.com/ManningBooks">ManningBooks</a>, my publisher for <a href="http://www.zendframeworkinaction.com">Zend Framework in Action</a>!</p>
<p>It turns out that they've put up a sample of the book on <a href="http://www.scribd.com/doc/13399974/Zend-Framework-in-Action">Scribed</a>!  Check out the book, then <a href="http://www.zendframeworkinaction.com/order">order it</a>, remembering to use the coupon code <strong>scribd25</strong>...</p>
]]></content:encoded>
			<wfw:commentRss>http://akrabat.com/zfia/manning-is-on-twitter/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>On models in a Zend Framework application</title>
		<link>http://akrabat.com/js/on-models-in-a-zend-framework-application/</link>
		<comments>http://akrabat.com/js/on-models-in-a-zend-framework-application/#comments</comments>
		<pubDate>Sat, 13 Dec 2008 17:15:25 +0000</pubDate>
		<dc:creator>Rob...</dc:creator>
				<category><![CDATA[Around the web]]></category>
		<category><![CDATA[JS]]></category>
		<category><![CDATA[Zend Framework]]></category>

		<guid isPermaLink="false">http://akrabat.com/?p=322</guid>
		<description><![CDATA[Let's talk about writing models that communicate with databases within a Zend Framework application. It's a popular topic at the moment as there's been a few threads recently on the ZF mailing lists about creating models. The "is a" relationship When working with models within Zend Framework, the simplest solution is to extend Zend_Db_Table_Abstract and [...]]]></description>
			<content:encoded><![CDATA[<p>Let's talk about writing models that communicate with databases within a Zend Framework application. It's a popular topic at the moment as there's been a few threads recently on the ZF mailing lists about creating models.</p>
<h3>The "is a" relationship</h3>
<p>When working with models within Zend Framework, the simplest solution is to extend Zend_Db_Table_Abstract and Zend_Db_Table_Row_Abstract along these lines:</p>
<pre class="phpcode"><span style="color: #0000BB">
</span><span style="color: #007700">class&nbsp;</span><span style="color: #0000BB">Users&nbsp;</span><span style="color: #007700">extends&nbsp;</span><span style="color: #0000BB">Zend_Db_Table_Abstract
</span><span style="color: #007700">{
&nbsp;&nbsp;&nbsp;&nbsp;protected&nbsp;</span><span style="color: #0000BB">$_name&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #DD0000">'users'</span><span style="color: #007700">;
&nbsp;&nbsp;&nbsp;&nbsp;protected&nbsp;</span><span style="color: #0000BB">$_rowClass&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #DD0000">'User'</span><span style="color: #007700">;
&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;function&nbsp;</span><span style="color: #0000BB">fetchAllInLastNameOrder</span><span style="color: #007700">()
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">fetchAll</span><span style="color: #007700">(</span><span style="color: #0000BB">null</span><span style="color: #007700">,&nbsp;array(</span><span style="color: #DD0000">'last_name'</span><span style="color: #007700">,&nbsp;</span><span style="color: #DD0000">'first_name'</span><span style="color: #007700">));
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;function&nbsp;</span><span style="color: #0000BB">fetchUserById</span><span style="color: #007700">(</span><span style="color: #0000BB">$id</span><span style="color: #007700">)
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$id&nbsp;</span><span style="color: #007700">=&nbsp;(int)</span><span style="color: #0000BB">$id</span><span style="color: #007700">;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">_fetchRow</span><span style="color: #007700">(</span><span style="color: #DD0000">'id&nbsp;=&nbsp;'</span><span style="color: #007700">.&nbsp;</span><span style="color: #0000BB">$id</span><span style="color: #007700">);
&nbsp;&nbsp;&nbsp;&nbsp;}
}

class&nbsp;</span><span style="color: #0000BB">User&nbsp;</span><span style="color: #007700">extends&nbsp;</span><span style="color: #0000BB">Zend_Db_Table_Row_Abstract
</span><span style="color: #007700">{
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;function&nbsp;</span><span style="color: #0000BB">name</span><span style="color: #007700">()
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">first_name&nbsp;</span><span style="color: #007700">.&nbsp;</span><span style="color: #DD0000">'&nbsp;'&nbsp;</span><span style="color: #007700">.&nbsp;</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">last_name</span><span style="color: #007700">;
&nbsp;&nbsp;&nbsp;&nbsp;}
}
</span>
</span></code></pre>
<p>This works fairly well for models where there is a one to one mapping to the underlying database table. It starts to falls down if a given model needs to know about two or more database tables to do its work.</p>
<p>The knack is to avoid using the functions defined in Zend_Db_Table_Abstract within your models or views as this will lead towards fat controllers that are too aware of the underlying database. This gets quite hard as it's much easier to start putting model logic into the controllers with this system, especially when it comes to choosing if you need to insert or update a record. A sure sign that you have this problem is that your controllers create SQL statements or Zend_Db_Table_Select objects. </p>
<p>To try and avoid these problems, there have been discussions on the ZF mailing lists for a little while now about using a "has a" relationship from the model object to the Zend_Db_Table object. Bill Karwin has long been a proponent of this idea and recently there's been much discussion about it. The question is: how do you implement it in practice without ending up writing lots of code for the sake of "cleanliness"?</p>
<p>I've started a new ZF project recently where I've started playing with these ideas and this is my first attempt at it, so I thought I'd share where I had got to in my thinking.</p>
<h3>The "has a" relationship</h3>
<p>When implementing this relationship we are trying to hide the fact that we are using <tt>Zend_Db_Table</tt> from the consumers of the models. The basic idea is that we have a gateway class that holds a protected <tt>$_table</tt> variable that is an instance of a <tt>Zend_Db_Table</tt> object. When fetching data, the gateway object will return either a single object or an array of objects of a type which I've not-very-imaginatively named "<tt>StandardObject</tt>".</p>
<p>This is a picture of the various objects and how they relate to each other:</p>
<p><img src="http://akrabat.com/wp-content/uploads/2008onmodels.png" alt="OnModels.png" border="0" width="823" height="447" /></p>
<p>To get this working, I first mapped out how I want the objects to work via a unit test and then built the classes behind it. I wouldn't call it TDD though as I didn't write tests for all the internals as I went along. This is the basic API that I want my consumers to use:</p>
<pre class="phpcode"><span style="color: #0000BB">
$userGateway&nbsp;</span><span style="color: #007700">=&nbsp;new&nbsp;</span><span style="color: #0000BB">UserGateway</span><span style="color: #007700">();

</span><span style="color: #FF8000">//&nbsp;insert&nbsp;a&nbsp;row
</span><span style="color: #0000BB">$data&nbsp;</span><span style="color: #007700">=&nbsp;array();
</span><span style="color: #0000BB">$data</span><span style="color: #007700">[</span><span style="color: #DD0000">'first_name'</span><span style="color: #007700">]&nbsp;=&nbsp;</span><span style="color: #DD0000">'John'</span><span style="color: #007700">;
</span><span style="color: #0000BB">$data</span><span style="color: #007700">[</span><span style="color: #DD0000">'last_name'</span><span style="color: #007700">]&nbsp;=&nbsp;</span><span style="color: #DD0000">'Smith'</span><span style="color: #007700">;
</span><span style="color: #0000BB">$row&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$userGateway</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">setFromArray</span><span style="color: #007700">(</span><span style="color: #0000BB">$data</span><span style="color: #007700">);

</span><span style="color: #FF8000">//&nbsp;update&nbsp;a&nbsp;row
</span><span style="color: #0000BB">$data&nbsp;</span><span style="color: #007700">=&nbsp;array();
</span><span style="color: #0000BB">$data</span><span style="color: #007700">[</span><span style="color: #DD0000">'id'</span><span style="color: #007700">]&nbsp;=&nbsp;</span><span style="color: #0000BB">1</span><span style="color: #007700">;
</span><span style="color: #0000BB">$data</span><span style="color: #007700">[</span><span style="color: #DD0000">'first_name'</span><span style="color: #007700">]&nbsp;=&nbsp;</span><span style="color: #DD0000">'Rob'</span><span style="color: #007700">;
</span><span style="color: #0000BB">$data</span><span style="color: #007700">[</span><span style="color: #DD0000">'last_name'</span><span style="color: #007700">]&nbsp;=&nbsp;</span><span style="color: #DD0000">'Allen'</span><span style="color: #007700">;
</span><span style="color: #0000BB">$row&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$userGateway</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">setFromArray</span><span style="color: #007700">(</span><span style="color: #0000BB">$data</span><span style="color: #007700">);

</span><span style="color: #FF8000">//&nbsp;fetch&nbsp;a&nbsp;single&nbsp;user
</span><span style="color: #0000BB">$row&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$userGateway</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">fetchUserById</span><span style="color: #007700">(</span><span style="color: #0000BB">1</span><span style="color: #007700">);

</span><span style="color: #FF8000">//&nbsp;fetch&nbsp;all&nbsp;users
</span><span style="color: #0000BB">$rows&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$userGateway</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">fetchAllInLastNameOrder</span><span style="color: #007700">();

</span><span style="color: #FF8000">//&nbsp;delete&nbsp;a&nbsp;user
</span><span style="color: #0000BB">$result&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$userGateway</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">deleteById</span><span style="color: #007700">(</span><span style="color: #0000BB">1</span><span style="color: #007700">);
</span>
</span></code></pre>
<p>The general idea is that I can write specific functionality into the UserGateway class as I need it. Note also that the row objects returned from the gateway class methods behave a little like ValueObjects only. As they are not attached to the database though, they cannot "save" themselves. (I couldn't find the "correct" design pattern name, which probably means, that my design is wrong!) This means that all interaction with the database is via the gateway class which makes this design similar in some ways to the <a href="http://martinfowler.com/eaaCatalog/tableModule.html">Table Module</a> design pattern.</p>
<p>The implementation is fairly involved, so get ready for lots of code!</p>
<p>Firstly we need the Gateway class:</p>
<pre class="phpcode"><span style="color: #0000BB">
</span><span style="color: #007700">class&nbsp;</span><span style="color: #0000BB">UserGateway&nbsp;</span><span style="color: #007700">extends&nbsp;</span><span style="color: #0000BB">App_Model_Db_StandardGateway&nbsp;
</span><span style="color: #007700">{
&nbsp;&nbsp;&nbsp;&nbsp;protected&nbsp;</span><span style="color: #0000BB">$_tableName&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #DD0000">'UsersTable'</span><span style="color: #007700">;
&nbsp;&nbsp;&nbsp;&nbsp;protected&nbsp;</span><span style="color: #0000BB">$_rowClass&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #DD0000">'UserObject'</span><span style="color: #007700">;
&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;function&nbsp;</span><span style="color: #0000BB">fetchUserById</span><span style="color: #007700">(</span><span style="color: #0000BB">$id</span><span style="color: #007700">)
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$id&nbsp;</span><span style="color: #007700">=&nbsp;(int)</span><span style="color: #0000BB">$id</span><span style="color: #007700">;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">_fetchRow</span><span style="color: #007700">(</span><span style="color: #DD0000">'id&nbsp;=&nbsp;'</span><span style="color: #007700">.&nbsp;</span><span style="color: #0000BB">$id</span><span style="color: #007700">);
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;function&nbsp;</span><span style="color: #0000BB">fetchAllInLastNameOrder</span><span style="color: #007700">()
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$orderBy</span><span style="color: #007700">=array(</span><span style="color: #DD0000">'last_name'</span><span style="color: #007700">,&nbsp;</span><span style="color: #DD0000">'first_name'</span><span style="color: #007700">);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">fetchAll</span><span style="color: #007700">(</span><span style="color: #0000BB">$orderBy</span><span style="color: #007700">);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;}
}
</span>
</span></code></pre>
<p>The <tt>UserGateway</tt> contains the specific methods for this model and has a couple of protected variables that are used to set up the system. We also need a table class, <tt>UsersTable</tt> that inherits from  <tt>App_Db_Table_Standard</tt> which inherits from <tt>Zend_Db_Table_Abstract</tt>. </p>
<pre class="phpcode"><span style="color: #0000BB">
</span><span style="color: #007700">class&nbsp;</span><span style="color: #0000BB">UsersTable&nbsp;</span><span style="color: #007700">extends&nbsp;</span><span style="color: #0000BB">App_Db_Table_Standard
</span><span style="color: #007700">{
&nbsp;&nbsp;&nbsp;&nbsp;protected&nbsp;</span><span style="color: #0000BB">$_name&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #DD0000">'users'</span><span style="color: #007700">;
}
</span>
</span></code></pre>
<p>Obviously we are going to have many gateway models, so it makes sense that common functionality will be in a parent class, which I've called App_Model_Db_StandardGateway. This is the big class and we'll look at it in chunks:</p>
<pre class="phpcode"><span style="color: #0000BB">
</span><span style="color: #007700">class&nbsp;</span><span style="color: #0000BB">App_Model_Db_StandardGateway
</span><span style="color: #007700">{
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #FF8000">/**
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@var&nbsp;App_Db_Table_Abstract
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #007700">protected&nbsp;</span><span style="color: #0000BB">$_table&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">null</span><span style="color: #007700">;
&nbsp;&nbsp;&nbsp;&nbsp;protected&nbsp;</span><span style="color: #0000BB">$_tableName&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">null</span><span style="color: #007700">;
&nbsp;&nbsp;&nbsp;&nbsp;protected&nbsp;</span><span style="color: #0000BB">$_rowClass&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #DD0000">'App_Model_StandardObject'</span><span style="color: #007700">;

&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;function&nbsp;</span><span style="color: #0000BB">__construct</span><span style="color: #007700">()
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(empty(</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">_tableName</span><span style="color: #007700">))&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw&nbsp;new&nbsp;</span><span style="color: #0000BB">Exception</span><span style="color: #007700">(</span><span style="color: #DD0000">'You&nbsp;must&nbsp;specificy&nbsp;_tableName'</span><span style="color: #007700">);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">_table&nbsp;</span><span style="color: #007700">=&nbsp;new&nbsp;</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">_tableName</span><span style="color: #007700">();
&nbsp;&nbsp;&nbsp;&nbsp;}
</span>
</span></code></pre>
<p>Every gateway has a <tt>$_table</tt> property which is instantiated in the constructor. The name of the table class to instantiate is stored in the <tt>$_tableName</tt> property which is set in the child class. Finally, we have a <tt>$_rowClass</tt> property which will be used to hold each row object when the data is retrieved from the database. Note that it defaults to <tt>App_Model_StandardObject</tt>, but I assume that the child class will override with a specific row class as the <tt>UserGateway</tt> class does when it specifies that it wants to use the <tt>UserObject</tt> row class. </p>
<p>The first thing in our API is the ability to create or update database rows. I've decided on a function called <tt>setFromArray()</tt> as a foundational function to allow this. The base implementation is performs these steps:</p>
<ol>
<li>Get hold of an instance of the row class</li>
<li>Call the row's <tt>setFromArray()</tt> method</li>
<li>Call the row's <tt>save()</tt> method</li>
</ol>
<p>This is implemented as:</p>
<pre class="phpcode"><span style="color: #0000BB">
</span><span style="color: #FF8000">//&nbsp;(part&nbsp;of&nbsp;App_Model_Db_StandardGateway)

&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #007700">public&nbsp;function&nbsp;</span><span style="color: #0000BB">setFromArray</span><span style="color: #007700">(</span><span style="color: #0000BB">$data</span><span style="color: #007700">)
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$row&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">_fetchRowOrCreate</span><span style="color: #007700">(</span><span style="color: #0000BB">$data</span><span style="color: #007700">);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$row</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">setFromArray</span><span style="color: #007700">(</span><span style="color: #0000BB">$data</span><span style="color: #007700">);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$row</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">save</span><span style="color: #007700">();

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;new&nbsp;</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">_rowClass</span><span style="color: #007700">(</span><span style="color: #0000BB">$row</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">toArray</span><span style="color: #007700">());
&nbsp;&nbsp;&nbsp;&nbsp;}
</span>
</span></code></pre>
<p>The tricky bit is getting the instance of the row class (an instance of <tt>Zend_Db_Table_Row</tt>) as we need to either create a new one or retrieve it from the database. Creating a new one is easy: <tt>$row = $table->createRow()</tt>. However, retrieving a row based on the <tt>$data</tt> array is more complicated. The simplest way I could think of was to retrieve the primary key info from the table and then call <tt>find()</tt> with the correct fields from <tt>$data</tt> array. To do this, I had to extend Zend_Db_Table_Abstract to implement a getPrimary() method like this:</p>
<pre class="phpcode"><span style="color: #0000BB">
</span><span style="color: #007700">class&nbsp;</span><span style="color: #0000BB">App_Db_Table_Standard&nbsp;</span><span style="color: #007700">extends&nbsp;</span><span style="color: #0000BB">Zend_Db_Table_Abstract
</span><span style="color: #007700">{
&nbsp;&nbsp;&nbsp;&nbsp;protected&nbsp;</span><span style="color: #0000BB">$_rowClass&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #DD0000">'App_Db_Table_Row_Standard'</span><span style="color: #007700">;
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;function&nbsp;</span><span style="color: #0000BB">getPrimary</span><span style="color: #007700">()
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">_primary</span><span style="color: #007700">;
&nbsp;&nbsp;&nbsp;&nbsp;}

}
</span>
</span></code></pre>
<p>Note that we also define a custom row class, <tt>App_Db_Table_Row_Standard</tt> which will allow us to perform operations on insert and delete.</p>
<p>Back to the <tt>App_Model_Db_StandardGateway</tt> class, we can now create <tt>_fetchRowOrCreate()</tt>:</p>
<pre class="phpcode"><span style="color: #0000BB">
</span><span style="color: #FF8000">//&nbsp;(part&nbsp;of&nbsp;App_Model_Db_StandardGateway)

&nbsp;&nbsp;&nbsp;&nbsp;/**
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;Either&nbsp;retrieve&nbsp;a&nbsp;row&nbsp;from&nbsp;the&nbsp;DB&nbsp;or&nbsp;create&nbsp;a&nbsp;new&nbsp;one
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;array&nbsp;$data
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@return&nbsp;App_Db_Table_Row_Standard
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #007700">protected&nbsp;function&nbsp;</span><span style="color: #0000BB">_fetchRowOrCreate</span><span style="color: #007700">(</span><span style="color: #0000BB">$data</span><span style="color: #007700">)&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$pk&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">_table</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getPrimary</span><span style="color: #007700">();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(!</span><span style="color: #0000BB">is_array</span><span style="color: #007700">(</span><span style="color: #0000BB">$pk</span><span style="color: #007700">))&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$pk&nbsp;</span><span style="color: #007700">=&nbsp;(array)&nbsp;</span><span style="color: #0000BB">$pk</span><span style="color: #007700">;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$pkData&nbsp;</span><span style="color: #007700">=&nbsp;array();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;foreach&nbsp;(</span><span style="color: #0000BB">$pk&nbsp;</span><span style="color: #007700">as&nbsp;</span><span style="color: #0000BB">$fieldName</span><span style="color: #007700">)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(</span><span style="color: #0000BB">array_key_exists</span><span style="color: #007700">(</span><span style="color: #0000BB">$fieldName</span><span style="color: #007700">,&nbsp;</span><span style="color: #0000BB">$data</span><span style="color: #007700">))&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$pkData</span><span style="color: #007700">[]&nbsp;=&nbsp;</span><span style="color: #0000BB">$data</span><span style="color: #007700">[</span><span style="color: #0000BB">$fieldName</span><span style="color: #007700">];
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;elseif&nbsp;(!empty(</span><span style="color: #0000BB">$pkData</span><span style="color: #007700">))&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw&nbsp;new&nbsp;</span><span style="color: #0000BB">Exception</span><span style="color: #007700">(</span><span style="color: #DD0000">"Could&nbsp;not&nbsp;find&nbsp;Primary&nbsp;Key&nbsp;part&nbsp;'</span><span style="color: #0000BB">$fieldName</span><span style="color: #DD0000">'"</span><span style="color: #007700">);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(empty(</span><span style="color: #0000BB">$pkData</span><span style="color: #007700">))&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$row&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">_table</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">createRow</span><span style="color: #007700">();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;else&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$rowset&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">call_user_func_array</span><span style="color: #007700">(array(</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">_table&nbsp;</span><span style="color: #007700">,&nbsp;</span><span style="color: #DD0000">'find'</span><span style="color: #007700">),&nbsp;</span><span style="color: #0000BB">$pkData</span><span style="color: #007700">);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(</span><span style="color: #0000BB">$rowset</span><span style="color: #007700">)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$row&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$rowset</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">current</span><span style="color: #007700">();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;else&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$row&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">_table</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">createRow</span><span style="color: #007700">();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;</span><span style="color: #0000BB">$row</span><span style="color: #007700">;
&nbsp;&nbsp;&nbsp;&nbsp;}
</span>
</span></code></pre>
<p>I'm nearly sure this can be improved, but it works for both a simple autoincrement primary key like <tt>id</tt> and also for compound primary keys of multiple columns which is nice. The method makes an assumption that if you have a compound key, then the <tt>$data</tt> array will have an entry for all fields that make up the primary key. If not, an exception is thrown. We also assume that if none of the fields that make up the primary key are present in <tt>$data</tt>, then you want to create a new record.</p>
<p>That covers creating and updating database records from our gateway class. Deletion is a simple proxy directly to the table class:</p>
<pre class="phpcode"><span style="color: #0000BB">
</span><span style="color: #FF8000">//&nbsp;(part&nbsp;of&nbsp;App_Model_Db_StandardGateway)

&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #007700">public&nbsp;function&nbsp;</span><span style="color: #0000BB">deleteById</span><span style="color: #007700">(</span><span style="color: #0000BB">$id</span><span style="color: #007700">)
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$count&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">_table</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">delete</span><span style="color: #007700">(</span><span style="color: #DD0000">'id&nbsp;=&nbsp;'</span><span style="color: #007700">.&nbsp;(int)</span><span style="color: #0000BB">$id</span><span style="color: #007700">);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;(bool)&nbsp;</span><span style="color: #0000BB">$count</span><span style="color: #007700">;
&nbsp;&nbsp;&nbsp;&nbsp;}
</span>
</span></code></pre>
<p> so let's look at fetching data. We need two methods in the <tt>App_Model_Db_StandardGateway</tt> class: <tt>_fetchRow()</tt> and <tt>fetchAll()</tt>. These are trivial to implement as we proxy directly to the table class and then all we need to do it turn each row returned into an instance of our <tt>StandardObject</tt> class:</p>
<pre class="phpcode"><span style="color: #0000BB">
</span><span style="color: #FF8000">//&nbsp;(part&nbsp;of&nbsp;App_Model_Db_StandardGateway)

&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #007700">protected&nbsp;function&nbsp;</span><span style="color: #0000BB">_fetchRow</span><span style="color: #007700">(</span><span style="color: #0000BB">$where</span><span style="color: #007700">,&nbsp;</span><span style="color: #0000BB">$order&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">null</span><span style="color: #007700">)
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$row&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">_table</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">fetchRow</span><span style="color: #007700">(</span><span style="color: #0000BB">$where</span><span style="color: #007700">,&nbsp;</span><span style="color: #0000BB">$order</span><span style="color: #007700">);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(</span><span style="color: #0000BB">$row</span><span style="color: #007700">)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$row&nbsp;</span><span style="color: #007700">=&nbsp;new&nbsp;</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">_rowClass</span><span style="color: #007700">(</span><span style="color: #0000BB">$row</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">toArray</span><span style="color: #007700">());
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;</span><span style="color: #0000BB">$row</span><span style="color: #007700">;
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;function&nbsp;</span><span style="color: #0000BB">fetchAll</span><span style="color: #007700">(</span><span style="color: #0000BB">$orderBy</span><span style="color: #007700">=</span><span style="color: #0000BB">null</span><span style="color: #007700">)
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$rows&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">null</span><span style="color: #007700">;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(</span><span style="color: #0000BB">is_null</span><span style="color: #007700">(</span><span style="color: #0000BB">$orderBy</span><span style="color: #007700">))&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw&nbsp;new&nbsp;</span><span style="color: #0000BB">Exception</span><span style="color: #007700">(</span><span style="color: #DD0000">'You&nbsp;must&nbsp;choose&nbsp;the&nbsp;order&nbsp;of&nbsp;the&nbsp;results'</span><span style="color: #007700">);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$rowset&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">_table</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">fetchAll</span><span style="color: #007700">(</span><span style="color: #0000BB">null</span><span style="color: #007700">,&nbsp;</span><span style="color: #0000BB">$orderBy</span><span style="color: #007700">);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(</span><span style="color: #0000BB">$rowset</span><span style="color: #007700">)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$rows&nbsp;</span><span style="color: #007700">=&nbsp;array();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;foreach(</span><span style="color: #0000BB">$rowset&nbsp;</span><span style="color: #007700">as&nbsp;</span><span style="color: #0000BB">$row</span><span style="color: #007700">)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$rows</span><span style="color: #007700">[]&nbsp;=&nbsp;new&nbsp;</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">_rowClass</span><span style="color: #007700">(</span><span style="color: #0000BB">$row</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">toArray</span><span style="color: #007700">());
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;</span><span style="color: #0000BB">$rows</span><span style="color: #007700">;
&nbsp;&nbsp;&nbsp;&nbsp;}
</span>
</span></code></pre>
<p>The StandardObject class' full name is <tt>App_Model_Db_StandardObject</tt> and is trivial:</p>
<pre class="phpcode"><span style="color: #0000BB">
</span><span style="color: #007700">class&nbsp;</span><span style="color: #0000BB">App_Model_Db_StandardObject
</span><span style="color: #007700">{
&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;</span><span style="color: #0000BB">__construct</span><span style="color: #007700">(</span><span style="color: #0000BB">$data&nbsp;</span><span style="color: #007700">=&nbsp;array())&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;foreach(</span><span style="color: #0000BB">$data&nbsp;</span><span style="color: #007700">as&nbsp;</span><span style="color: #0000BB">$fieldName</span><span style="color: #007700">=&gt;</span><span style="color: #0000BB">$value</span><span style="color: #007700">)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">$fieldName&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$value</span><span style="color: #007700">;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;}
}
</span>
</span></code></pre>
<p>Obviously, the intention is that the model specific version, <tt>UserObject</tt> in this case, is able to do provide model specific functionality. For testing, I simply added a <tt>name()</tt> method:</p>
<pre class="phpcode"><span style="color: #0000BB">
</span><span style="color: #007700">class&nbsp;</span><span style="color: #0000BB">UserObject&nbsp;</span><span style="color: #007700">extends&nbsp;</span><span style="color: #0000BB">App_Model_Db_StandardObject&nbsp;&nbsp;
</span><span style="color: #007700">{
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;function&nbsp;</span><span style="color: #0000BB">name</span><span style="color: #007700">()
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">first_name&nbsp;</span><span style="color: #007700">.&nbsp;</span><span style="color: #DD0000">'&nbsp;'&nbsp;</span><span style="color: #007700">.&nbsp;</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">last_name</span><span style="color: #007700">;
&nbsp;&nbsp;&nbsp;&nbsp;}
}
</span>
</span></code></pre>
<p>Clearly, I could provide additional methods as required and could overload the constructor if I wanted to do a more complicated mapping from the database row array to the value object representation.</p>
<h3>Summary</h3>
<p>This entry has turned out much longer than I expected! This is clearly my first attempt at putting the database inside the model and hiding it from the rest of the application. Having implemented this far, I'm not sure if using Zend_Db_Table is actually useful, so my next step will be to remove it and use SQL and a Zend_Db_Adapter instead. If it turns out well, I may blog about it :)</p>
<p>I'm also hoping to spark more debate on the actual implementation of how to do stuff like this. I know <a href="http://thepopeisdead.com/">Keith Pope</a> is working along similar lines for the example app in his upcoming book, so if you are interested in this approach, have a look at his tactics too as they may make more sense. <a href="http://weierophinney.net/matthew/">Matthew Weier O'Phinney</a> has also been doing something similar in his <a href="http://github.com/weierophinney/pastebin/tree/bugapp">pastebin app</a> which is worth looking at too, though he's halfway through refactoring.</p>
<p>Obviously, comments and suggested improvements are welcome!</p>
]]></content:encoded>
			<wfw:commentRss>http://akrabat.com/js/on-models-in-a-zend-framework-application/feed/</wfw:commentRss>
		<slash:comments>30</slash:comments>
		</item>
		<item>
		<title>Recursion</title>
		<link>http://akrabat.com/php/recusion/</link>
		<comments>http://akrabat.com/php/recusion/#comments</comments>
		<pubDate>Wed, 16 Jul 2008 20:11:37 +0000</pubDate>
		<dc:creator>Rob...</dc:creator>
				<category><![CDATA[Around the web]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://akrabat.com/?p=255</guid>
		<description><![CDATA[PHPWomen are running an article contest at the moment. All you have to do is write an article for the Best Practices forum and you could win a Zend Studio for Eclipse license and a a 1-year subscription to Linux Pro magazine! Obviously, never one to miss an opportunity to win free swag, I've entered [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.phpwomen.org/">PHPWomen</a> are running an <a href="http://www.phpwomen.org/wordpress/2008/06/24/phpwomen-article-competition/">article contest</a> at the moment. All you have to do is write an article for the <a href="http://www.phpwomen.org/forum/index.php?t=thread&#038;frm_id=20&#038;S=974919fead67c20aac41d9eda5856025">Best Practices forum</a> and you could win a <a href="http://www.zend.com/en/products/studio/">Zend Studio for Eclipse</a> license and a a 1-year subscription to <a href="http://www.linuxpromagazine.com/">Linux Pro magazine</a>!</p>
<p>Obviously, never one to miss an opportunity to win free swag, I've entered with an article on <a href="http://www.phpwomen.org/forum/index.php?t=msg&#038;th=477&#038;start=0&#038;S=974919fead67c20aac41d9eda5856025">recursion</a>. </p>
<p>Now it's your turn. Write a article on a best practice when coding PHP, but don't make it too good as I want to win! </p>
]]></content:encoded>
			<wfw:commentRss>http://akrabat.com/php/recusion/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>IE8 will work like IE8 by default!</title>
		<link>http://akrabat.com/around-the-web/ie8-will-work-like-ie8-by-default/</link>
		<comments>http://akrabat.com/around-the-web/ie8-will-work-like-ie8-by-default/#comments</comments>
		<pubDate>Tue, 04 Mar 2008 12:24:00 +0000</pubDate>
		<dc:creator>Rob...</dc:creator>
				<category><![CDATA[Around the web]]></category>

		<guid isPermaLink="false">http://akrabat.com/2008/03/04/ie8-will-work-like-ie8-by-default/</guid>
		<description><![CDATA[We’ve decided that IE8 will, by default, interpret web content in the most standards compliant way it can. This decision is a change from what we’ve posted previously. From Microsoft's Interoperability Principles and IE8. This is good news all round. It's nice to see that Microsoft have listened to the comments surrounding their original intention [...]]]></description>
			<content:encoded><![CDATA[<blockquote><p>We’ve decided that IE8 will, by default, interpret web content in the most standards compliant way it can. This decision is a change from what we’ve posted previously.</p></blockquote>
<p>From <a href="http://blogs.msdn.com/ie/archive/2008/03/03/microsoft-s-interoperability-principles-and-ie8.aspx">Microsoft's Interoperability Principles and IE8</a>.</p>
<p>This is good news all round. It's nice to see that Microsoft have listened to the comments surrounding their original intention to make IE8 render like IE7 by default. Well done!</p>
]]></content:encoded>
			<wfw:commentRss>http://akrabat.com/around-the-web/ie8-will-work-like-ie8-by-default/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Cure for BSS announced!</title>
		<link>http://akrabat.com/computing/cure-for-bss-announced/</link>
		<comments>http://akrabat.com/computing/cure-for-bss-announced/#comments</comments>
		<pubDate>Sat, 23 Feb 2008 19:02:58 +0000</pubDate>
		<dc:creator>Rob...</dc:creator>
				<category><![CDATA[Around the web]]></category>
		<category><![CDATA[Computing]]></category>

		<guid isPermaLink="false">http://akrabat.com/2008/02/23/cure-for-bss-announced/</guid>
		<description><![CDATA[Cal Evans has announced a cure for Blank Stare Syndrome! You know the problem: you're in a conversation and someone mentions something about a new technology that you haven't heard of. Your eyes glaze and you have that Blank Stare... Sixty Second Tech is the solution. Once a week, it will deliver a short podcast [...]]]></description>
			<content:encoded><![CDATA[<p>Cal Evans has <a href="http://blog.calevans.com/2008/02/23/sixty-second-tech-the-tech-podcast-for-non-tech-people/">announced</a> a cure for Blank Stare Syndrome!</p>
<p>You know the problem: you're in a conversation and someone mentions something about a new technology that you haven't heard of. Your eyes glaze and you have that <em>Blank Stare</em>... </p>
<p><a href="http://www.sixtysecondtech.com/">Sixty Second Tech</a> is the solution. Once a week, it will deliver a short podcast (presumably about 60 seconds long!) that explains one technological concept per episode that you (or your less-techy friends!) need to know.</p>
<p>Head on over there and subscribe to the <a href="http://www.sixtysecondtech.com/feed/">RSS Feed</a> now - or wait for it to turn up on iTunes shortly.</p>
]]></content:encoded>
			<wfw:commentRss>http://akrabat.com/computing/cure-for-bss-announced/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
