<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">

  <title><![CDATA[Deprecated Behaviour]]></title>
  
  <link href="http://blog.tekerson.com/" />
  <updated>2013-03-28T23:17:07+10:00</updated>
  <id>http://blog.tekerson.com/</id>
  <author>
    <name><![CDATA[Brenton Alker]]></name>
    
  </author>
  <generator uri="http://octopress.org/">Octopress</generator>

  
  <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/DeprecatedBehaviour" /><feedburner:info uri="deprecatedbehaviour" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry>
    <title type="html"><![CDATA[Ideas of March: Where's the love?]]></title>
    <link href="http://feedproxy.google.com/~r/DeprecatedBehaviour/~3/GPAiJ52qtWY/" />
    <updated>2013-03-28T21:43:00+10:00</updated>
    <id>http://blog.tekerson.com/2013/03/28/ideas-of-march-wheres-the-love</id>
    <content type="html">&lt;p&gt;As I previously blogged, I&amp;#8217;ve recently changed blogging platform to use a static generator. One of the disadvantages that comes with serving only static files is a lack of interactivity; There is no server-side scripts to handle things like comments. The most common solution is to use a third party service, such as &lt;a href="http://disqus.com"&gt;Disqus&lt;/a&gt; that provides a JavaScript widget for you.&lt;/p&gt;

&lt;p&gt;Of course, as Chris Shiflett in his (now traditional :P) &lt;a href="http://shiflett.org/blog/2013/mar/ideas-of-march"&gt;Ideas of March&lt;/a&gt; post espouses, the disadvantage of any third party service is the lack of data ownership; &amp;#8220;You never know when it&amp;#8217;s going to disappear.&amp;#8221; citing the recent announcement that Google Reader is to be shut down. This is why I am reluctant to implement such a solution. And given Lorna Mitchell&amp;#8217;s suggestion, &lt;a href="http://www.lornajane.net/posts/2013/ideas-of-march-dont-read-the-comments"&gt;&amp;#8220;don&amp;#8217;t read the comments&amp;#8221;&lt;/a&gt;, I have to wonder if having comments is worth the effort involved?&lt;/p&gt;

&lt;p&gt;For now, it looks like I&amp;#8217;m going to remain comment free. Which is a shame. The occasional grateful comment from a random stranger on the Internet has a certain way of almost making up for some of the not-so-nice the Internet thrusts upon us. Without this feedback, where&amp;#8217;s the love?&lt;/p&gt;

&lt;p&gt;Both Lorna Mitchell and Rob Allen (in &lt;a href="http://akrabat.com/me/ideas-of-march-its-my-content-and-my-opinion/"&gt;his response&lt;/a&gt;) assert that they intend to sometimes &amp;#8220;turn off comments and encourage others to respond by writing [&amp;#8230;] on their own blog.&amp;#8221; I think this is a fantastic idea (I&amp;#8217;m doing so right now), though I do have some concern about how well fragmented blog posts can coalesce into a meaningful conversation, &amp;#8220;trackbacks&amp;#8221; were an attempt at solving this issue, but I&amp;#8217;m not sure that worked too well.&lt;/p&gt;

&lt;p&gt;This is one advantage the &amp;#8220;walled gardens&amp;#8221; currently hold - they have the ability to aggregate the posts into a single congruous conversation.&lt;/p&gt;

&lt;p&gt;If you have any solutions to the fragmented conversation problem, write a response on your blog and I&amp;#8217;ll&amp;#8230; Probably never see it&amp;#8230; Ping me on &lt;a href="http://twitter.com/tekerson"&gt;twitter&lt;/a&gt;, maybe?&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/DeprecatedBehaviour/~4/GPAiJ52qtWY" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://blog.tekerson.com/2013/03/28/ideas-of-march-wheres-the-love/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Reboot]]></title>
    <link href="http://feedproxy.google.com/~r/DeprecatedBehaviour/~3/JU-JI9Va4aA/" />
    <updated>2013-03-24T18:25:00+10:00</updated>
    <id>http://blog.tekerson.com/2013/03/24/reboot</id>
    <content type="html">&lt;p&gt;Wow, it&amp;#8217;s been over 3 years since my last post! And, like so many entertainment franchises, I think it&amp;#8217;s time for a reboot. I stopped blogging when I moved away from PHP because I no longer felt confident enough in my work to open up anything I was doing to any kind of public scrutiny. Having since (mostly) returned to PHP, doing some consulting and contracting and embarking on a venture of my own, I feel it is time once again to put some of my experiences and thoughts into writing.&lt;/p&gt;

&lt;p&gt;To facilitate this, and because my Wordpress install was so hideously out of date, I&amp;#8217;ve decided to changed to a static blogging solution: &lt;a href="http://octopress.org/"&gt;Octopress&lt;/a&gt;. As such, the blog is currently without much of a design. This may (or may not) be remedied at a later time. I will write in more detail about the platform and the migration in a future post.&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/DeprecatedBehaviour/~4/JU-JI9Va4aA" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://blog.tekerson.com/2013/03/24/reboot/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[The Silver Lining of the ReadWriteWeb/Facebook Login Debacle]]></title>
    <link href="http://feedproxy.google.com/~r/DeprecatedBehaviour/~3/8ep7LScmQg4/" />
    <updated>2010-02-18T00:11:13+10:00</updated>
    <id>http://blog.tekerson.com/2010/02/18/the-silver-lining-of-the-readwriteweb-facebook-login-debacle</id>
    <content type="html">&lt;p&gt;The furor surrounding the amusing chaos that ensued following &lt;a href="http://www.readwriteweb.com/archives/facebook_wants_to_be_your_one_true_loginpage5.php"&gt;ReadWriteWeb&amp;#8217;s article on Facebook Connect&lt;/a&gt; has been interesting, in that it brings attention to developers assumptions about the way users interact with their products.&lt;/p&gt;

&lt;p&gt;There have been articles debating who is the cause of the confusion; whether it&amp;#8217;s the &lt;a href="http://funkatron.com/site/comments/were-the-stupid-ones-facebook-google-and-our-failure-as-developers/"&gt;Developers&lt;/a&gt; or the &lt;a href="http://www.lastpodcast.net/2010/02/10/facebook-login-is-hard-welcome-to-idiocracy"&gt;Users&lt;/a&gt; that need to try harder.&lt;/p&gt;

&lt;p&gt;But in all this, what I think has been missed is the &lt;em&gt;success&lt;/em&gt; of &lt;a href="http://developers.facebook.com/connect.php"&gt;Facebook Connect&lt;/a&gt;. There are hundreds of comments on the ReadWriteWeb article from users who failed (for whatever reason) to find their way to Facebook, yet still managed to use Facebook Connect to leave a comment.&lt;/p&gt;

&lt;p&gt;Sounds like a testament to the usability of Facebook Connect to me!&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/DeprecatedBehaviour/~4/8ep7LScmQg4" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://blog.tekerson.com/2010/02/18/the-silver-lining-of-the-readwriteweb-facebook-login-debacle/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Bootstrapping the Doctrine 2.0 Autoloader in Zend Framework]]></title>
    <link href="http://feedproxy.google.com/~r/DeprecatedBehaviour/~3/kLccxBlwWeI/" />
    <updated>2009-09-08T01:03:53+10:00</updated>
    <id>http://blog.tekerson.com/2009/09/08/bootstrapping-the-doctrine2-autoloader-in-zend-framework</id>
    <content type="html">&lt;p&gt;&lt;em&gt;&lt;strong&gt;Please Note:&lt;/strong&gt; This post was based on the Alpha release of Doctrine2. They have since added Doctrine\Common\IsolatedClassLoader which (among other things) doesn&amp;#8217;t automatically register itself so we no longer have to unregister it, making things much easier.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Doctrine 2.0 looks like it might finally be the ORM framework I have been seeking for PHP. While the older versions of Doctrine provided great functionality, they were too intrusive for my taste. I think an ORM should provide a true &lt;a href="http://martinfowler.com/eaaCatalog/dataMapper.html"&gt;data mapper&lt;/a&gt;; in which the domain entities need know nothing about their persistence.&lt;/p&gt;

&lt;p&gt;Matthew Weier O&amp;#8217;Phinney has already posted about &lt;a href="http://weierophinney.net/matthew/archives/220-Autoloading-Doctrine-and-Doctrine-entities-from-Zend-Framework.html"&gt;autoloading Doctrine in Zend Framework&lt;/a&gt;, but Doctrine2 presents some new challenges. Mainly that Doctrine2 is fully PHP5.3, including &amp;#8220;real&amp;#8221; namespaces, so its classes don&amp;#8217;t follow the (current) Zend naming standard and the ZF autoloader won&amp;#8217;t load them for us.&lt;/p&gt;

&lt;p&gt;Good News, Doctrine provides its own autoloader that we can leverage to load its own classes.&lt;/p&gt;

&lt;p&gt;Bad News, the Doctrine autoloader automatically registers itself with spl_autoload_register, causing the normal Zend loader to be forgotten (well, pushed down the stack, where it isn&amp;#8217;t very useful).&lt;/p&gt;

&lt;p&gt;Good News, it&amp;#8217;s easy to remove the doctrine autoloader using spl_autoload_unregister, then push it onto the ZF autoloader stack, targeting the Doctrine namespace. Letting the ZF autoloader call it as necessary.&lt;/p&gt;

&lt;p&gt;Enough jibber-jabber, how do we do all this? In the bootstrap! Adding this method to your Bootstrap.php will achieve what we want; adding the Doctrine autoloader to the Zend Framework autoloader queue for the &amp;#8220;Doctrine&amp;#34; namespace.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;span class='line-number'&gt;13&lt;/span&gt;
&lt;span class='line-number'&gt;14&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='php'&gt;&lt;span class='line'&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;_initDoctrine&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="c1"&gt;// Create the doctrine autoloader and remove it from the spl autoload stack (it adds itself)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="k"&gt;require_once&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Doctrine/Common/ClassLoader.php&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="nv"&gt;$doctrineAutoloader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;\Doctrine\Common\ClassLoader&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;loadClass&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="nb"&gt;spl_autoload_unregister&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$doctrineAutoloader&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="c1"&gt;// Fetch the global Zend Autoloader&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="nv"&gt;$autoloader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Zend_Loader_Autoloader&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;getInstance&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="c1"&gt;// Push the doctrine autoloader to load for the Doctrine\ namespace&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="nv"&gt;$autoloader&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;pushAutoloader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$doctrineAutoloader&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Doctrine\\&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;We can use all of Doctrine&amp;#8217;s classes anywhere else in our code.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='php'&gt;&lt;span class='line'&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nx"&gt;Doctrine\ORM&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;$manager&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;EntityManager&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;driver&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;pdo_sqlite&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;path&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;:memory:/&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;I still have a lot to learn and the documentation on 2.0 is a little sparse as yet, but this is a start.&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/DeprecatedBehaviour/~4/kLccxBlwWeI" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://blog.tekerson.com/2009/09/08/bootstrapping-the-doctrine2-autoloader-in-zend-framework/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Dependency Injection Container Resource in Zend Framework]]></title>
    <link href="http://feedproxy.google.com/~r/DeprecatedBehaviour/~3/v4gedJKuyNE/" />
    <updated>2009-07-06T13:00:51+10:00</updated>
    <id>http://blog.tekerson.com/2009/07/06/dependency-injection-container-resource-in-zend-framework</id>
    <content type="html">&lt;p&gt;A good dependency injection container is a godsend when it comes to managing the dependency tree of even a moderately complex domain model. As such, it comes as no surprise there has been much discussion about them of late in the PHP and Zend Framework communities.&lt;/p&gt;

&lt;p&gt;Based on the &lt;a href="http://github.com/beberlei/yadif/tree/master"&gt;Yadif&lt;/a&gt; and Benjamin Eberlei&amp;#8217;s recent look at &lt;a href="http://www.whitewashing.de/blog/articles/117"&gt;Using a Dependency Injection Container with Zend_Application&lt;/a&gt;, where he replaces Zend_Applications default container instance (A Zend_Registry instance) with a Yadif_Container, I have created a Zend_Application_Resource to allow configuration based injection of dependencies into the container via the normal ZF configuration file (application.ini)&lt;/p&gt;

&lt;p&gt;The container resource copies any already instantiated objects from the old container into the new one, then replaces the default container.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;span class='line-number'&gt;13&lt;/span&gt;
&lt;span class='line-number'&gt;14&lt;/span&gt;
&lt;span class='line-number'&gt;15&lt;/span&gt;
&lt;span class='line-number'&gt;16&lt;/span&gt;
&lt;span class='line-number'&gt;17&lt;/span&gt;
&lt;span class='line-number'&gt;18&lt;/span&gt;
&lt;span class='line-number'&gt;19&lt;/span&gt;
&lt;span class='line-number'&gt;20&lt;/span&gt;
&lt;span class='line-number'&gt;21&lt;/span&gt;
&lt;span class='line-number'&gt;22&lt;/span&gt;
&lt;span class='line-number'&gt;23&lt;/span&gt;
&lt;span class='line-number'&gt;24&lt;/span&gt;
&lt;span class='line-number'&gt;25&lt;/span&gt;
&lt;span class='line-number'&gt;26&lt;/span&gt;
&lt;span class='line-number'&gt;27&lt;/span&gt;
&lt;span class='line-number'&gt;28&lt;/span&gt;
&lt;span class='line-number'&gt;29&lt;/span&gt;
&lt;span class='line-number'&gt;30&lt;/span&gt;
&lt;span class='line-number'&gt;31&lt;/span&gt;
&lt;span class='line-number'&gt;32&lt;/span&gt;
&lt;span class='line-number'&gt;33&lt;/span&gt;
&lt;span class='line-number'&gt;34&lt;/span&gt;
&lt;span class='line-number'&gt;35&lt;/span&gt;
&lt;span class='line-number'&gt;36&lt;/span&gt;
&lt;span class='line-number'&gt;37&lt;/span&gt;
&lt;span class='line-number'&gt;38&lt;/span&gt;
&lt;span class='line-number'&gt;39&lt;/span&gt;
&lt;span class='line-number'&gt;40&lt;/span&gt;
&lt;span class='line-number'&gt;41&lt;/span&gt;
&lt;span class='line-number'&gt;42&lt;/span&gt;
&lt;span class='line-number'&gt;43&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='php'&gt;&lt;span class='line'&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Tek_Application_Resource_Container&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Zend_Application_Resource_ResourceAbstract&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nv"&gt;$_container&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getContainer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;null&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;_container&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;            &lt;span class="nv"&gt;$options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;getOptions&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;            &lt;span class="nv"&gt;$container&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;_getBootstrap&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;getContainer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nv"&gt;$container&lt;/span&gt; &lt;span class="nx"&gt;instanceof&lt;/span&gt; &lt;span class="nx"&gt;Yadif_Container&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;                &lt;span class="nv"&gt;$config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;isset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$options&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;options&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Zend_Config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$options&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;options&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;                &lt;span class="nv"&gt;$container&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Yadif_Container&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nv"&gt;$config&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;                &lt;span class="c1"&gt;// import instances from the existing (Zend_Registry) container&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;                &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;_getBootstrap&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;getContainer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$key&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$instance&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;                    &lt;span class="nv"&gt;$container&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;__set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$instance&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;                &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;            &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;            &lt;span class="nv"&gt;$container&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;addComponents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$options&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;objects&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;            &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;_container&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$container&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;_container&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;getContainer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;_getBootstrap&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;setContainer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;_container&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;_container&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;_getBootstrap&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="nv"&gt;$app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;getBootstrap&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;getApplication&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$app&lt;/span&gt; &lt;span class="nx"&gt;instanceof&lt;/span&gt; &lt;span class="nx"&gt;Zend_Application&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;getBootstrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;I&amp;#8217;ve also created a simple action helper to allow easy grabbing of resources from the action controllers. Both reside in &lt;a href="http://github.com/tekerson/Tek/tree/master"&gt;my extensions repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To use the container resource you will need to add the prefix and path to the bootstrappers plugin loader:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;span class='line-number'&gt;13&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='php'&gt;&lt;span class='line'&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Bootstrap&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Zend_Application_Bootstrap_Bootstrap&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;_initPlugins&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;       &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;getPluginLoader&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;addPrefixPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;           &lt;span class="s1"&gt;&amp;#39;Tek_Application_Resource&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;           &lt;span class="s1"&gt;&amp;#39;Tek/Application/Resource&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;       &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Then you can add the resources and their dependencies via the normal configuration system. This means adding lines like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;resources.container.objects.Log.class = "Zend_Log"
resources.container.objects.Log.arguments.0 = "Log_Writer"

resources.container.objects.Log_Writer.class = "Zend_Log_Writer_Stream"
resources.container.objects.Log_Writer.arguments.0 = "%Log_Writer.stream%"

resources.container.options.Log_Writer.stream = APPLICATION_PATH "/../log/application.log"
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;There are 2 resources defined here, the &amp;#8220;Log&amp;#8221; and the &amp;#8220;Log_Writer&amp;#8221;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Log is an instance of Zend_Log and takes a Log_Writer resource as the first (and only) argument to its constructor.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The Log_Writer resource is an instance of Zend_Log_Writer_Stream and takes a scalar as its only argument. The scalar value is defined in the container option specified.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;Now, the controller can write a log like this.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='php'&gt;&lt;span class='line'&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;$logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;getInvokeArg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;bootstrap&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;getResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Log&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c1"&gt;// or, with the helper&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;$logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;_helper&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Log&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;$logger&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;A log message&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Zend_Log&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;NOTICE&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;While this is a simple example, it can be really beneficial when working with, for example, a service layer. The service you need might depend on another service, both of which may depend on an Authorization service. All the services depend on their data mappers (which themselves depends on a database connection) and their entity factories, etc.
Instantiating a dependency tree like this for every object you need can lead to duplicate and hard to modify code. Dependency injection coupled with a good container can provide highly versatile code whose behaviour can be drastically changed by only modifying a configuration file.&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/DeprecatedBehaviour/~4/v4gedJKuyNE" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://blog.tekerson.com/2009/07/06/dependency-injection-container-resource-in-zend-framework/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Building a Modular Application in Zend Framework - Part 2]]></title>
    <link href="http://feedproxy.google.com/~r/DeprecatedBehaviour/~3/-l3mvNLt2o0/" />
    <updated>2009-06-28T00:43:35+10:00</updated>
    <id>http://blog.tekerson.com/2009/06/28/building-a-modular-application-in-zend-framework-part-2</id>
    <content type="html">&lt;p&gt;Welcome to part two of the series exploring the modular application structure in Zend Framework. With the basic application set up in &lt;a href="http://blog.tekerson.com/2009/06/17/building-a-modular-application-in-zend-framework-part-1/"&gt;part one&lt;/a&gt;, we can get down to actually creating our first module. We&amp;#8217;re going to refactor the &lt;a href="http://framework.zend.com/docs/quickstart/"&gt;official quickstarts&lt;/a&gt; guestbook. This will let us focus on the modular structure without getting bogged down in business logic.&lt;/p&gt;

&lt;p&gt;Note, there are still some bugs in Zend_Tool that prevent this working as it should, I will note the bugs and their fixes as we encounter them.&lt;/p&gt;

&lt;h2&gt;Create the module&lt;/h2&gt;

&lt;p&gt;From the base path of our application (/WORKING/PATH/aza from the last article), we can issue the command to the Zend_Tool CLI to create our guestbook module.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;zf create module guestbook
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then, create the index controller within the guestbook module.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;zf create controller index 1 guestbook
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &amp;#8220;1&amp;#8221; argument tells Zend_Tool that we want to automatically create an index action within the new controller. We can get a help listing like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;zf create controller ?
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Once the new module and controller is created we need to tell the application that we are using modules. We do this by adding two lines to the configs/application.ini. The first activates the modules resource. The second configures the front controller, telling it where the modules are located. These lines should be added to the end of the production section of the .ini file.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;resources.modules = ""
resources.frontController.moduleDirectory = APPLICATION_PATH "/modules"
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To check our module is working, we can navigate to our guestbook at http://aza/guestbook and we should see the default view for the index action.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://framework.zend.com/issues/browse/ZF-7121"&gt;Bug&lt;/a&gt;: Zend_Tool doesn&amp;#8217;t prefix the controller names within the module name. The guestbook index controller class IndexController needs to be changed to Guestbook_IndexController.
&lt;a href="http://framework.zend.com/issues/browse/ZF-6908"&gt;Bug&lt;/a&gt;: The default view for the controller is the same as the main page, it shouldn&amp;#8217;t be but we don&amp;#8217;t really care, we&amp;#8217;re going to replace it anyway.&lt;/p&gt;

&lt;h2&gt;Create module bootstrap&lt;/h2&gt;

&lt;p&gt;In the same way that the Bootstrap.php set up the environment for our main application (also known as the default module) each module has its own Bootstrap.php that adds anything additional that each module needs. Zend_Tool doesn&amp;#8217;t create this bootstrap by default, so we need to create application/modules/guestbook/Bootstrap.php and it should contain.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='php'&gt;&lt;span class='line'&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Guestbook_Bootstrap&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Zend_Application_Module_Bootstrap&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;By creating this file, the application will automatically perform module bootstrap tasks such as adding autoloaders for the default resources; including models, forms and services. Any other module specific bootstrapping tasks can be added as _init*() functions. In our case, we don&amp;#8217;t need any further bootstrapping.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Important note&lt;/strong&gt;: &lt;strong&gt;&lt;em&gt;All&lt;/em&gt; bootstrap functions&lt;/strong&gt; for &lt;strong&gt;every module&lt;/strong&gt; are run for &lt;strong&gt;every request&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The bootstrap process occurs &lt;em&gt;before&lt;/em&gt; routing and dispatch, so during bootstrap there is no way to know which module/controller/action is being requested. Therefore, any setup that should be done only if a particular module is requested should be done in plugins, &lt;em&gt;not&lt;/em&gt; bootstrap.&lt;/p&gt;

&lt;h2&gt;Getting Quickstart&lt;/h2&gt;

&lt;p&gt;Now we have the module skeleton in place, lets start porting the guestbook code to our module. This turns out to be fairly easy; the majority of the changes involve prefixing class names with the module name.&lt;/p&gt;

&lt;p&gt;To make life easy, start by acquiring a copy of the completed &lt;a href="http://framework.zend.com/docs/quickstart"&gt;quickstart application&lt;/a&gt; (it&amp;#8217;s on the right hand side in zip or tar.gz form).&lt;/p&gt;

&lt;h2&gt;Importing Quickstart&lt;/h2&gt;

&lt;p&gt;Once you have downloaded and extracted the files into a temporary folder, we can start copying in the files we need.&lt;/p&gt;

&lt;p&gt;We need to copy the GuestbookController from the Quickstart (making it the IndexController) and all of the Quickstart models, views and forms to the appropriate places within our module.&lt;/p&gt;

&lt;p&gt;From (Quickstart)To (Aza)&lt;/p&gt;

&lt;p&gt;application/controllers/GuestbookController.php&lt;/p&gt;

&lt;p&gt;application/modules/guestbook/controllers/IndexController.php&lt;/p&gt;

&lt;p&gt;application/models/*
application/modules/guestbook/models/&lt;/p&gt;

&lt;p&gt;application/views/scripts/guestbook/*
application/modules/guestbook/views/scripts/index/&lt;/p&gt;

&lt;p&gt;application/forms/*
application/modules/guestbook/forms/&lt;/p&gt;

&lt;p&gt;The controller and the views will require overwriting the existing files.&lt;/p&gt;

&lt;h2&gt;Porting Quickstart&lt;/h2&gt;

&lt;p&gt;Now we have the files in the right place, we need to update the files to be modular.&lt;/p&gt;

&lt;p&gt;We&amp;#8217;ll start with the easiest one, the form. It is simple because it is already prefixed for the Default module, all we need to do it change the prefix to Guestbook_. So the class in application/modules/guestbook/forms/Guestbook.php changes from Default_Form_Guestbook to Guestbook_Form_Guestbook.&lt;/p&gt;

&lt;p&gt;Now the models. There are many more changes here but they are just as simple because the models (like the form) are already prefixed with &amp;#8220;Default&lt;em&gt;&amp;#8221;, but the classes also contain references to each other, so we need to change more than just the class names. A simple search and replace of &amp;#8220;Default&lt;/em&gt;&amp;#8221; with &amp;#8220;Guestbook_&amp;#8221; in the application/modules/guestbook/models/ directory is all we need.&lt;/p&gt;

&lt;p&gt;The controller is a little trickier because it isn&amp;#8217;t already prefixed (controllers in the default module aren&amp;#8217;t), but it&amp;#8217;s still not too hard. The name of the class in application/modules/guestbook/controllers/IndexController.php just needs to be changed from GuestbookController to Guestbook_IndexController, as it has changed from the guestbook controller within default module (no prefix) to the index controller within the guestbook module. We also need to update the references to the models and forms, the same search and replace as we used in the models will suffice.&lt;/p&gt;

&lt;p&gt;Finally, we get to the view. In our index view (application/modules/guestbook/views/scripts/index/index.phtml) we need to update the parameters passed to the url helper to reference our controller. Adding the module, and changing the controller leaves the first link looking like this:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='html'&gt;&lt;span class='line'&gt;&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;lt;?php echo $this-&amp;gt;url(&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="s"&gt;    array(&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="s"&gt;        &amp;#39;module&amp;#39;    =&amp;gt; &amp;#39;guestbook&amp;#39;,&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="s"&gt;        &amp;#39;controller&amp;#39; =&amp;gt; &amp;#39;index&amp;#39;,&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="s"&gt;        &amp;#39;action&amp;#39;     =&amp;gt; &amp;#39;sign&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="s"&gt;    ), &lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="s"&gt;    &amp;#39;default&amp;#39;, &lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="s"&gt;    true) ?&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Sign Our Guestbook&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Done!&lt;/p&gt;

&lt;h2&gt;Connect the database&lt;/h2&gt;

&lt;p&gt;I&amp;#8217;ll leave the actual creation of the database to you. It is he same as the Quickstart and this post is already particularly long. You will need to create the database, and add the configuration to the application.ini.&lt;/p&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;We have just ported the Quickstart guestbook application to a Zend Framework Module. Modularizing applications allows for easier code reuse across applications. Hopefully modules will become standardized to the point that there will be a repository of modules that can be added to your application and providing drop in functionality.&lt;/p&gt;

&lt;h2&gt;Download&lt;/h2&gt;

&lt;p&gt;For those who had trouble following along, I&amp;#8217;ve made the entire application (including database) available via my &lt;a href="http://github.com/tekerson/A-Zend-Application/tree/master"&gt;github repository&lt;/a&gt;.&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/DeprecatedBehaviour/~4/-l3mvNLt2o0" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://blog.tekerson.com/2009/06/28/building-a-modular-application-in-zend-framework-part-2/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Building a Modular Application in Zend Framework - Part 1]]></title>
    <link href="http://feedproxy.google.com/~r/DeprecatedBehaviour/~3/wNLLBdLWrzI/" />
    <updated>2009-06-17T19:45:29+10:00</updated>
    <id>http://blog.tekerson.com/2009/06/17/building-a-modular-application-in-zend-framework-part-1</id>
    <content type="html">&lt;p&gt;This is part one of a series exploring modular application development in Zend Framework. In this entry we&amp;#8217;ll look at downloading and installing Zend Framework, especially Zend_Tool, on a Linux environment. We&amp;#8217;ll start from the beginning so that future posts can build on a known environment. Throughout this post, the code snippets are copy/paste ready, so following along should be easy, just start in a new working directory.&lt;/p&gt;

&lt;h2&gt;Install Zend Framework&lt;/h2&gt;

&lt;p&gt;The first step is to actually get ZF, so start by downloading the package (about 40MB in total) into our working directory and extracting it.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;wget http://framework.zend.com/releases/ZendFramework-1.8.4/ZendFramework-1.8.4.tar.gz
tar zxf ZendFramework-1.8.4.tar.gz
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We&amp;#8217;ll then create a symlink to provide an easy upgrade path (extract the new version and move the symlink), and an easier to remember directory name.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;ln -s ZendFramework-1.8.4 ZendFramework
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Install Zend_Tool&lt;/h2&gt;

&lt;p&gt;Creating an alias allows command &amp;#8220;zf&amp;#8221; to always point to the Zend_Tool shell script, so we can use the command line tool from wherever we need it.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;alias zf=`pwd`/ZendFramework/bin/zf.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now the installation is complete, we should be able to check what version of the framework we have just installed.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;zf show version
# Zend Framework Version: 1.8.4
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If this works, we&amp;#8217;re ready to start creating our project. The documentation provides some alternate methods of &lt;a href="http://framework.zend.com/manual/en/zend.tool.framework.clitool.html#zend.tool.framework.clitool.setup-general"&gt;setting up Zend_Tool&lt;/a&gt;, including setting it up in a windows environment.&lt;/p&gt;

&lt;h2&gt;Create the project&lt;/h2&gt;

&lt;p&gt;Once Zend_Tool is working, we can begin creating our project. For the exercise, we&amp;#8217;ll call our project &amp;#8220;aza&amp;#8221; (A Zend Application). Using Zend_Tool, we create the basic structure for the project.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;zf create project aza
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This should produce a project structure that looks like this&lt;/p&gt;

&lt;p&gt;[caption id=&amp;#8221;attachment_131&amp;#8221; align=&amp;#8221;alignnone&amp;#8221; width=&amp;#8221;324&amp;#8221; caption=&amp;#8221;Directory Listing of new project&amp;#8221;]&lt;img src="http://blog.tekerson.com/wp-content/uploads/2009/06/screen.jpg" alt="Directory Listing of new project" /&gt;[/caption]&lt;/p&gt;

&lt;h2&gt;Setup the web server&lt;/h2&gt;

&lt;p&gt;Finally, we can tell the Apache2 web server about our application by adding a VirtualHost to the server configuration. You will need to replace &amp;#8220;/WORKING/PATH/&amp;#8221; with the absolute path to the directory in which you are working (run pwd if you&amp;#8217;re not sure).&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;VirtualHost *:80&amp;gt;
    ServerName aza
    DocumentRoot /WORKING/PATH/aza/public
    &amp;lt;Directory /WORKING/PATH/aza/public&amp;gt;
        php_value include_path "/WORKING/PATH/ZendFramework/library"
        php_value magic_quotes_gpc 0
        php_value short_open_tag "on"
        DirectoryIndex index.php
        AllowOverride All
        Order allow,deny
        Allow from all
    &amp;lt;/Directory&amp;gt;
&amp;lt;/VirtualHost&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Don&amp;#8217;t forget to restart the web server to enable the site.&lt;/p&gt;

&lt;h2&gt;Test our page!&lt;/h2&gt;

&lt;p&gt;We should now be able to navigate to our site and be warmly welcomed to our new Zend Framework application!
We&amp;#8217;ll stop here for now. In the next post, we&amp;#8217;ll start looking at creating our first module.&lt;/p&gt;

&lt;h2&gt;Updates&lt;/h2&gt;

&lt;p&gt;2009-06-26
Updated for ZF Version 1.8.4&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/DeprecatedBehaviour/~4/wNLLBdLWrzI" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://blog.tekerson.com/2009/06/17/building-a-modular-application-in-zend-framework-part-1/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Re-sequence a column in MySQL]]></title>
    <link href="http://feedproxy.google.com/~r/DeprecatedBehaviour/~3/o1Yr2jtqhxw/" />
    <updated>2009-05-26T23:13:24+10:00</updated>
    <id>http://blog.tekerson.com/2009/05/26/re-sequence-a-column-in-mysql</id>
    <content type="html">&lt;p&gt;When you have an &amp;#8220;position&amp;#8221; column in a table, to allow the user to select the order of elements in the table or as an optimization for pagination. They always seem to get out of sequence at some point&amp;#8211;ending up with gaps in the sequence.
This is something I run into not quiet often enough to remember how to do it, yet often enough to to be frustrating. So here is an easy solution to re-sequence the position column in a table, maintaining the current order, just closing any gaps.&lt;/p&gt;

&lt;p&gt;SET @pos := 0;
UPDATE Example SET position = @pos := @pos + 1 ORDER BY position&lt;/p&gt;

&lt;p&gt;It simply initializes a variable (@pos) to 0, then for each row (updates are done in sequence) increments the variable and assigns it to the position column. The ORDER BY clause ensures the current ordering is maintained. WHERE clauses can also be added as required.&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/DeprecatedBehaviour/~4/o1Yr2jtqhxw" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://blog.tekerson.com/2009/05/26/re-sequence-a-column-in-mysql/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Following hashtags on Twitter]]></title>
    <link href="http://feedproxy.google.com/~r/DeprecatedBehaviour/~3/FmiG6u5dO_k/" />
    <updated>2009-03-17T00:24:59+10:00</updated>
    <id>http://blog.tekerson.com/2009/03/17/following-hashtags-on-twitter</id>
    <content type="html">&lt;p&gt;The &lt;a href="http://hashtags.org"&gt;hashtags&lt;/a&gt; service allows you to see some interesting information, such as popular tags and a graph of a particular tags usage over time. It also offers the ability to follow a tag by providing an RSS feed, but I don&amp;#8217;t believe it can provide a single feed of multiple tags. While I was at the PHP Quebec conference I was looking for an easy way to follow all the tweets with the various hashtags in use (there was some disagreement as to the &amp;#8220;correct&amp;#8221; tag).&lt;/p&gt;

&lt;p&gt;I found that this can be done using twitter&amp;#8217;s own search function, simply put all the tags into the &amp;#8220;Any of these words&amp;#8221; box on the &lt;a href="http://search.twitter.com/advanced"&gt;twitter advanced search interface&lt;/a&gt; and run the search. On the results screen, subscribe to the URL for the &amp;#8220;Feed for this query&amp;#8221; (at the top right of the page) and put it into your favourite feed reader, set the refresh rate to every few minutes (you can probably set it lower if your software allows, but do your really need it?) and watch the conversation.&lt;/p&gt;

&lt;p&gt;This allowed me to keep up with chatter at the conference, even from people I don&amp;#8217;t usually follow.&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/DeprecatedBehaviour/~4/FmiG6u5dO_k" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://blog.tekerson.com/2009/03/17/following-hashtags-on-twitter/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[PHP Quebec Wrap-up from a Conference Newb]]></title>
    <link href="http://feedproxy.google.com/~r/DeprecatedBehaviour/~3/Sf9uqT9f2XU/" />
    <updated>2009-03-11T21:02:09+10:00</updated>
    <id>http://blog.tekerson.com/2009/03/11/php-quebec-wrap-up-from-a-conference-newb</id>
    <content type="html">&lt;p&gt;As I am in Canada for only 3 more weeks, and we don&amp;#8217;t get too many PHP conferences in Brisbane, I took the opportunity to attended my first ever PHP conference. I thought I would share my thoughts, and maybe those more experienced can help me do it &amp;#8220;better&amp;#8221; next time.&lt;/p&gt;

&lt;p&gt;After flying across the country we checked into the hotel, the Hilton Bonaventure in Montreal. The front desk apparently didn&amp;#8217;t know we were there for the conference because we didn&amp;#8217;t &amp;#8220;book with the others&amp;#8221;. I&amp;#8217;m not sure what that means, or what difference it would have made? The hotel offered free wireless in the foyer and conference halls, but not in the rooms. Luckily, we were close enough to the foyer to access their wireless from our room (once I sorted out some driver issues on my laptop).&lt;/p&gt;

&lt;h2&gt;Day 1&lt;/h2&gt;

&lt;p&gt;After missing most of the openning keynote on the first day in favour of eating (I didn&amp;#8217;t know breakfast would be available) I jumped into the sessions. Starting with &lt;a href="http://conf.phpquebec.com/en/conferencier#matthew_weier_ophinney"&gt;Matthew Weier O&amp;#8217;Phinney&amp;#8217;s&lt;/a&gt; &lt;a href="http://conf.phpquebec.com/en/session#practical_zend_framework_jutsu_with_dojo"&gt;Practical Zend Framework Jutsu with Dojo&lt;/a&gt;, which provided a practical overview to an area of the Zend Framework I have been planning on investigating, but haven&amp;#8217;t yet got round to. This was followed up by &lt;a href="http://conf.phpquebec.com/en/conferencier#john_coggeshall"&gt;John Coggeshall&amp;#8217;s&lt;/a&gt; explaining their process of &lt;a href="http://conf.phpquebec.com/en/session#building_ria_application_in_php"&gt;Building RIA Application in PHP&lt;/a&gt;. This wasn&amp;#8217;t a talk I intended to attend (Sara Goleman&amp;#8217;s talk was scheduled for this time, but was unable to attend due to illness) but it was interesting to see the differences in building a PHP application without a HTML front end.&lt;a href="http://conf.phpquebec.com/en/conferencier#john_coggeshall"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After lunch, &lt;a href="http://conf.phpquebec.com/en/conferencier#derick_rethans"&gt;Derick Rethan&amp;#8217;s&lt;/a&gt; looked into search and indexing. &lt;a href="http://conf.phpquebec.com/en/session#of_haystacks_and_needles"&gt;Of Haystacks and Needles&lt;/a&gt;, introduced MySQL full text, Selenium and Solr. While I have used Selenium, Solr seems like a useful step up for systems with higher requirements. The afternoon sessions were &lt;a href="http://conf.phpquebec.com/en/session#a_tour_of_mysql_high_availability"&gt;A tour of MySQL High Availability&lt;/a&gt; by &lt;a href="http://conf.phpquebec.com/en/conferencier#morgan_tocker"&gt;Morgan Tocker&lt;/a&gt;, which talked about the difference between scaling for performance and scaling for HA, and techniques for the latter, for me there wasn&amp;#8217;t much I hadn&amp;#8217;t used before, but some of the monitoring tools warrant further research. &lt;a href="http://conf.phpquebec.com/en/session#stupid_browser_tricks"&gt;Stupid Browser Tricks&lt;/a&gt; by &lt;a href="http://conf.phpquebec.com/en/conferencier#sean_coates"&gt;Sean Coates&lt;/a&gt;, was in a similar boat. It was a good introduction to some useful browser side tools (Firebug, YSlow! and Selenium IDE) but I had hoped for a deeper look into Selenium. Isn&amp;#8217;t everyone using firebug by now? FirePHP is a nice addition though.&lt;/p&gt;

&lt;h2&gt;Day 2&lt;/h2&gt;

&lt;p&gt;Day 2 started with a quick breakfast (I&amp;#8217;m a fast learner ;)), then the &lt;a href="http://conf.phpquebec.com/en/session#php_code_review"&gt;PHP Code Review Part #1&lt;/a&gt;, with &lt;a href="http://conf.phpquebec.com/en/conferencier#sebastian_bergmann"&gt;Sebastian Bergmann&lt;/a&gt; and &lt;a href="http://conf.phpquebec.com/en/conferencier#stefan_priebsch"&gt;Stefan Priebsch&lt;/a&gt; delving into some not particularly pretty examples of code from well known PHP applications such as Wordpress. It&amp;#8217;s reassuring to know other people write and release bad code too :) I didn&amp;#8217;t attend Part #2 of the session, where they took code samples from the audience and critiqued them. Instead I opted to drop in on &lt;a href="http://conf.phpquebec.com/en/conferencier#chris_hartjes"&gt;Chris Hartjes&lt;/a&gt; expaining why &lt;a href="http://conf.phpquebec.com/en/session#deployment_is_not_a_4_letter_word"&gt;Deployment Is Not A 4 Letter Word&lt;/a&gt; and that with some planning and appropriate tools, in your absence even the sysadmin should be able to deploy your application with confidence.&lt;/p&gt;

&lt;p&gt;The pre-lunch keynote was &lt;a href="http://conf.phpquebec.com/en/conferencier#john_coggeshall"&gt;John Coggeshall&lt;/a&gt; again discussing RIA in &lt;a href="http://conf.phpquebec.com/en/session#beyond_the_browser"&gt;Beyond the Browser&lt;/a&gt;. Is the browser dead? Not yet, but it certainly has some growing competition. After a break, I listened to &lt;a href="http://conf.phpquebec.com/en/conferencier#ilia_alshanetsky"&gt;Ilia Alshanetsky&lt;/a&gt; talk about &lt;a href="http://conf.phpquebec.com/en/session#premature_optimization_mistakes"&gt;Premature Optimization Mistakes&lt;/a&gt;, focusing on optimising the server stack itself before delving into application level optimisation. Arguing it usually provides more results without the risk of breaking the application. &lt;a href="http://conf.phpquebec.com/en/session#php_for_the_enterprise"&gt;PHP for the Enterprise&lt;/a&gt; then examined how PHP has reached a level where it is suitable for projects that were once considered the realm of &amp;#8220;real&amp;#8221; programming languages. Most of the talk discussed more technical details of scaling PHP to an enterprise level, such as database buffer sizes, performance monitoring and caching at various levels.&lt;/p&gt;

&lt;p&gt;The day ended with the career fair which saw a number of, primarily local, employers (including the armed forces?) set up booths and discuss their work and employment with the potential candidates at the conference. While I wasn&amp;#8217;t actively seeking employment, I did have a chat with some of the representatives. Given the location of the conference, it wasn&amp;#8217;t too big a surprise that the majority were bilingual and in some cases French only offices.&lt;/p&gt;

&lt;h2&gt;Day 3&lt;/h2&gt;

&lt;p&gt;My final day of the conference started with &lt;a href="http://conf.phpquebec.com/en/conferencier#owen_byrne"&gt;Owen Byrne&lt;/a&gt; discussing &lt;a href="http://conf.phpquebec.com/en/session#growing_a_development_team_while_building_a_huge_app_at_500_miles/hour"&gt;Growing a Development Team While Building a Huge App at 500 miles/hour&lt;/a&gt;; which I attended, hoping to garner an insight into building a team and managing agile development on a large project. While the project was an interesting one, Owen seemed to be more interested in giving out t-shirts and I didn&amp;#8217;t feel we got very deep into the whole process. Being a fairly heavy user and fan of Zend Framework, I joined &lt;a href="http://conf.phpquebec.com/en/conferencier#matthew_weier_ophinney"&gt;Matthew Weier O&amp;#8217;Phinney&lt;/a&gt; in his search for some of &lt;a href="http://conf.phpquebec.com/en/session#zf"&gt;Zend Framework&amp;#8217;s Little Known Gems&lt;/a&gt;. The talk was targeted at using the components in isolation and I discovered a number of components that may come in handy in future projects, with or without the MVC stack.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://conf.phpquebec.com/en/conferencier#morgan_tocker"&gt;Morgan Tocker&lt;/a&gt; then talked further about MySQL, this time focusing on performance as opposed to high availability. There were a few points about the inner working of the InnoDB storage engine that got my attention, including some builds available from Percona we may need to look at.&lt;/p&gt;

&lt;p&gt;The round-table &lt;a href="http://conf.phpquebec.com/en/session#framework"&gt;Framework Comparison&lt;/a&gt;, featuring &lt;a href="http://conf.phpquebec.com/en/conferencier#fabien_potencier"&gt;Fabien Potencier&lt;/a&gt; (Symfony) &lt;a href="http://conf.phpquebec.com/en/conferencier#derick_rethans"&gt;Derick Rethans&lt;/a&gt; (ezComponents) and &lt;a href="http://conf.phpquebec.com/en/conferencier#matthew_weier_ophinney"&gt;Matthew Weier O&amp;#8217;Phinney&lt;/a&gt; (Zend Framework) seemed to indicate that all 3 frameworks solve much the same problem, they even went as far as agreeing you should use components from the other frameworks when your primary framework doesn&amp;#8217;t include one. Much different to the &amp;#8220;my framework is better&amp;#8221; &amp;#8220;discussions&amp;#8221; we too often see.&lt;/p&gt;

&lt;p&gt;Finally, &lt;a href="http://conf.phpquebec.com/en/conferencier#chris_shiflett"&gt;Chris Shiflett&lt;/a&gt; addressed &lt;a href="http://conf.phpquebec.com/en/session#security-centered_design__dont_just_plan_for_security_design_for_it"&gt;Security-Centered Design: Don&amp;#8217;t Just Plan for Security; Design For It&lt;/a&gt; provided an alternative look at some interesting security topics. Instead of focusing on technical details, he primarly focused on security from a user perspective as &amp;#8220;user perception is as important as reality&amp;#8221;. Giving examples of various recent attacks on high profile sites that, while not actually the fault of the site, would be perceived as such by most users. He also put forward ideas about using &amp;#8220;ambient signifiers&amp;#8221; to assist in the fight against phishing, and how the normal (request-reload) web model can mean important information is missed due to &amp;#8220;change blindness&amp;#8221; including a live demonstration. He suggesting AJAX might be a suitable solution in this case (as long as it&amp;#8217;s still accessible of course).&lt;/p&gt;

&lt;h2&gt;Conclusions&lt;/h2&gt;

&lt;p&gt;All-in-all the conference was a great experience, the hotel was really nice (especially compared to some of the hostels where I usually slum on my travels) and the talks were wide ranging and generally well presented.&lt;/p&gt;

&lt;p&gt;Some of the material I found too &amp;#8220;introductory&amp;#8221;, but I think that may be because I primarily attended sessions on topics I am familiar with hoping to learn more, whereas using the talks as introductions to new topics might have been a better idea. How do people usually select talks?&lt;/p&gt;

&lt;p&gt;I also didn&amp;#8217;t attend much in the way of &amp;#8220;extra-conference&amp;#8221; activities; social events outside of the conference schedule. I am a little disappointed about this, as it would have been good to chat to some members of the community in a less formal setting, so this is something I think I would do much more of next time. And there will be a next time.&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/DeprecatedBehaviour/~4/Sf9uqT9f2XU" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://blog.tekerson.com/2009/03/11/php-quebec-wrap-up-from-a-conference-newb/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Converting a flat array with Parent ID's to a nested Tree]]></title>
    <link href="http://feedproxy.google.com/~r/DeprecatedBehaviour/~3/c1RtmhiVVa0/" />
    <updated>2009-03-03T21:37:32+10:00</updated>
    <id>http://blog.tekerson.com/2009/03/03/converting-a-flat-array-with-parent-ids-to-a-nested-tree</id>
    <content type="html">&lt;p&gt;Storing hierarchical data in a tabular data structure such as a database is not uncommon in many applications (eg. threaded comments on a blog entry, or a navigation menu structure). The &amp;#8220;Adjacency List&amp;#8221; method; probably the most common, involves storing a reference to the parent in each of the children.&lt;/p&gt;

&lt;p&gt;Here is a snippet for converting the rows stored using the adjacency list method into a hierarchical array in PHP. My goal was to do this in 1 pass, without recursion. I ended up using 2 passes, I think 1 pass is achievable if you can guarantee the parent will always be returned before all of its children. But since I couldn&amp;#8217;t, the first pass is to change the id of the row to be the key of the array.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;span class='line-number'&gt;13&lt;/span&gt;
&lt;span class='line-number'&gt;14&lt;/span&gt;
&lt;span class='line-number'&gt;15&lt;/span&gt;
&lt;span class='line-number'&gt;16&lt;/span&gt;
&lt;span class='line-number'&gt;17&lt;/span&gt;
&lt;span class='line-number'&gt;18&lt;/span&gt;
&lt;span class='line-number'&gt;19&lt;/span&gt;
&lt;span class='line-number'&gt;20&lt;/span&gt;
&lt;span class='line-number'&gt;21&lt;/span&gt;
&lt;span class='line-number'&gt;22&lt;/span&gt;
&lt;span class='line-number'&gt;23&lt;/span&gt;
&lt;span class='line-number'&gt;24&lt;/span&gt;
&lt;span class='line-number'&gt;25&lt;/span&gt;
&lt;span class='line-number'&gt;26&lt;/span&gt;
&lt;span class='line-number'&gt;27&lt;/span&gt;
&lt;span class='line-number'&gt;28&lt;/span&gt;
&lt;span class='line-number'&gt;29&lt;/span&gt;
&lt;span class='line-number'&gt;30&lt;/span&gt;
&lt;span class='line-number'&gt;31&lt;/span&gt;
&lt;span class='line-number'&gt;32&lt;/span&gt;
&lt;span class='line-number'&gt;33&lt;/span&gt;
&lt;span class='line-number'&gt;34&lt;/span&gt;
&lt;span class='line-number'&gt;35&lt;/span&gt;
&lt;span class='line-number'&gt;36&lt;/span&gt;
&lt;span class='line-number'&gt;37&lt;/span&gt;
&lt;span class='line-number'&gt;38&lt;/span&gt;
&lt;span class='line-number'&gt;39&lt;/span&gt;
&lt;span class='line-number'&gt;40&lt;/span&gt;
&lt;span class='line-number'&gt;41&lt;/span&gt;
&lt;span class='line-number'&gt;42&lt;/span&gt;
&lt;span class='line-number'&gt;43&lt;/span&gt;
&lt;span class='line-number'&gt;44&lt;/span&gt;
&lt;span class='line-number'&gt;45&lt;/span&gt;
&lt;span class='line-number'&gt;46&lt;/span&gt;
&lt;span class='line-number'&gt;47&lt;/span&gt;
&lt;span class='line-number'&gt;48&lt;/span&gt;
&lt;span class='line-number'&gt;49&lt;/span&gt;
&lt;span class='line-number'&gt;50&lt;/span&gt;
&lt;span class='line-number'&gt;51&lt;/span&gt;
&lt;span class='line-number'&gt;52&lt;/span&gt;
&lt;span class='line-number'&gt;53&lt;/span&gt;
&lt;span class='line-number'&gt;54&lt;/span&gt;
&lt;span class='line-number'&gt;55&lt;/span&gt;
&lt;span class='line-number'&gt;56&lt;/span&gt;
&lt;span class='line-number'&gt;57&lt;/span&gt;
&lt;span class='line-number'&gt;58&lt;/span&gt;
&lt;span class='line-number'&gt;59&lt;/span&gt;
&lt;span class='line-number'&gt;60&lt;/span&gt;
&lt;span class='line-number'&gt;61&lt;/span&gt;
&lt;span class='line-number'&gt;62&lt;/span&gt;
&lt;span class='line-number'&gt;63&lt;/span&gt;
&lt;span class='line-number'&gt;64&lt;/span&gt;
&lt;span class='line-number'&gt;65&lt;/span&gt;
&lt;span class='line-number'&gt;66&lt;/span&gt;
&lt;span class='line-number'&gt;67&lt;/span&gt;
&lt;span class='line-number'&gt;68&lt;/span&gt;
&lt;span class='line-number'&gt;69&lt;/span&gt;
&lt;span class='line-number'&gt;70&lt;/span&gt;
&lt;span class='line-number'&gt;71&lt;/span&gt;
&lt;span class='line-number'&gt;72&lt;/span&gt;
&lt;span class='line-number'&gt;73&lt;/span&gt;
&lt;span class='line-number'&gt;74&lt;/span&gt;
&lt;span class='line-number'&gt;75&lt;/span&gt;
&lt;span class='line-number'&gt;76&lt;/span&gt;
&lt;span class='line-number'&gt;77&lt;/span&gt;
&lt;span class='line-number'&gt;78&lt;/span&gt;
&lt;span class='line-number'&gt;79&lt;/span&gt;
&lt;span class='line-number'&gt;80&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='php'&gt;&lt;span class='line'&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;convertToTree&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$flat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$idField&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;id&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;                        &lt;span class="nv"&gt;$parentIdField&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;parentId&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;                        &lt;span class="nv"&gt;$childNodesField&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;childNodes&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="nv"&gt;$indexed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;array&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="c1"&gt;// first pass - get the array indexed by the primary id  &lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$flat&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$row&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="nv"&gt;$indexed&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$idField&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$row&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="nv"&gt;$indexed&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$idField&lt;/span&gt;&lt;span class="p"&gt;]][&lt;/span&gt;&lt;span class="nv"&gt;$childNodesField&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;array&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="c1"&gt;//second pass  &lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="nv"&gt;$root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$indexed&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$id&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$row&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="nv"&gt;$indexed&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$parentIdField&lt;/span&gt;&lt;span class="p"&gt;]][&lt;/span&gt;&lt;span class="nv"&gt;$childNodesField&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;$indexed&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nv"&gt;$row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$parentIdField&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;            &lt;span class="nv"&gt;$root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$root&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$indexed&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$root&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c1"&gt;// Usage:&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;$rows&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="k"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="s1"&gt;&amp;#39;id&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="s1"&gt;&amp;#39;parentId&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="s1"&gt;&amp;#39;name&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Menu&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="k"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="s1"&gt;&amp;#39;id&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="s1"&gt;&amp;#39;parentId&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="s1"&gt;&amp;#39;name&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Item 1-1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="k"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="s1"&gt;&amp;#39;id&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="s1"&gt;&amp;#39;parentId&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="s1"&gt;&amp;#39;name&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Item 2-1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="k"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="s1"&gt;&amp;#39;id&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="s1"&gt;&amp;#39;parentId&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="s1"&gt;&amp;#39;name&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Item 1-2&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nx"&gt;convertToTree&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$rows&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c1"&gt;// Produces:&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;array&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="s1"&gt;&amp;#39;id&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="s1"&gt;&amp;#39;parentId&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="s1"&gt;&amp;#39;name&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Menu&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="s1"&gt;&amp;#39;childNodes&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;            &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;                &lt;span class="s1"&gt;&amp;#39;id&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;                &lt;span class="s1"&gt;&amp;#39;parentId&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;                &lt;span class="s1"&gt;&amp;#39;name&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Item 1-1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;                &lt;span class="s1"&gt;&amp;#39;childNodes&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;array&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;                    &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;array&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;                        &lt;span class="s1"&gt;&amp;#39;id&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;                        &lt;span class="s1"&gt;&amp;#39;parentId&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;                        &lt;span class="s1"&gt;&amp;#39;name&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Item 1-2&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;                        &lt;span class="s1"&gt;&amp;#39;childNodes&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;array&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;                        &lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;                    &lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;                &lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;            &lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;            &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;  &lt;span class="k"&gt;array&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;                &lt;span class="s1"&gt;&amp;#39;id&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;                &lt;span class="s1"&gt;&amp;#39;parentId&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;                &lt;span class="s1"&gt;&amp;#39;name&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Item 2-1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;                &lt;span class="s1"&gt;&amp;#39;childNodes&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;array&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;                &lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;            &lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/DeprecatedBehaviour/~4/c1RtmhiVVa0" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://blog.tekerson.com/2009/03/03/converting-a-flat-array-with-parent-ids-to-a-nested-tree/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Environment specific bootstrapping for Zend Framework ]]></title>
    <link href="http://feedproxy.google.com/~r/DeprecatedBehaviour/~3/Apx6iBXDJwA/" />
    <updated>2009-02-13T19:40:05+10:00</updated>
    <id>http://blog.tekerson.com/2009/02/13/environment-specific-bootstrapping-for-zend-framework</id>
    <content type="html">&lt;p&gt;When you build an application, it is often deployed to a number of servers each with a different set of configurations. The development and production servers, with different debug, logging, and database details is an obvious example. Many approaches I have seen to dealing with this, including Anis uddin Ahmad&amp;#8217;s &lt;a href="http://www.ajaxray.com/blog/2009/02/03/advanced-bootstrapping-configure-your-zend-framework-application-for-multiple-host/"&gt;post that inspired this one&lt;/a&gt;, involve determining the domain the application is running on, and loading a pre-determined configuration for that host.&lt;/p&gt;

&lt;p&gt;There are 2 downfalls to that solution from my point of view;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Each new environment involves editing the source of the application&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If the application involves command line components, there is no way to determine the domain, requiring a special case&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;My solution may look familiar if you have ever looked at &lt;a href="http://www.djangoproject.com/"&gt;python&amp;#8217;s django&lt;/a&gt;. It involves using environment variables, which can be set through the web server, or on the command line - even in crontab. Basically, I set an environment variable specifying the location of the configuration file to load into the application. I actually allow a list of configuration files,so you can have a &amp;#8220;base&amp;#8221; and only override specific configuration as required per location.&lt;/p&gt;

&lt;p&gt;To add and environment variable in apache, you use the mod_env module&amp;#8217;s &lt;a href="http://httpd.apache.org/docs/1.3/mod/mod_env.html#setenv"&gt;SetEnv directive&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;SetEnv APPLICATION_CONFIG /path/to/config/basic.php:/path/to/config/development.php&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;on the command line, you can use export.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;export APPLICATION_CONFIG=/path/to/config/basic.php:/path/to/config/development.php&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;and very similarly in crontab (above the code that requires it)&lt;/p&gt;

&lt;p&gt;&lt;code&gt;APPLICATION_CONFIG=/path/to/config/basic.php:/path/to/config/development.php&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;To read the configuration files, from php we can simple get the environment variable with &lt;a href="http://php.net/getenv"&gt;getenv()&lt;/a&gt;, then merge each configuration into the applications configuration;&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='php'&gt;&lt;span class='line'&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;$configFiles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;APPLICATION_CONFIG&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;$configArray&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;explode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PATH_SEPARATOR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$configFiles&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;$config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Zend_Config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$configArray&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$newConfig&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;$config&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Zend_Config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;require&lt;/span&gt; &lt;span class="nv"&gt;$newConfig&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;$config&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;setReadOnly&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;In this example I am using simple PHP files to store the configuration arrays, you could also use any other format &lt;a href="http://framework.zend.com/manual/en/zend.config.html"&gt;Zend_Config&lt;/a&gt; can read. You could also use a simple array and &lt;a href="http://php.net/array_merge"&gt;array_merge()&lt;/a&gt; instead on Zend_Config if you are not using the framework.&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/DeprecatedBehaviour/~4/Apx6iBXDJwA" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://blog.tekerson.com/2009/02/13/environment-specific-bootstrapping-for-zend-framework/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Data Mapper Pattern in PHP]]></title>
    <link href="http://feedproxy.google.com/~r/DeprecatedBehaviour/~3/Ug2OKYt1DRg/" />
    <updated>2008-12-17T18:58:14+10:00</updated>
    <id>http://blog.tekerson.com/2008/12/17/data-mapper-pattern-in-php</id>
    <content type="html">&lt;p&gt;I have been trying to get together a post on the &lt;a href="http://martinfowler.com/eaaCatalog/dataMapper.html"&gt;Data Mapper&lt;/a&gt; pattern since I started experimenting with it in a personal project. It seems to me to be a fantastic answer to the decoupling of in-memory data objects and the data store. I still don&amp;#8217;t have all the answers, but Rob Allen&amp;#8217;s recent post &lt;a href="http://akrabat.com/2008/12/13/on-models-in-a-zend-framework-application/"&gt;On models in a Zend Framework application&lt;/a&gt;, and the associated discussion provoked me to publish some of what I do have.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Warning&lt;/em&gt;: This post will be quite long and is very code heavy, but I hope it illustrates some of my current thoughts.&lt;/p&gt;

&lt;p&gt;Anyway, lets get down to it.&lt;/p&gt;

&lt;p&gt;I will be showing 4 classes. Two (2) Abstract &amp;#8220;library&amp;#8221; classes, and 2 examples of their use;&lt;/p&gt;

&lt;p&gt;And now, the code. Instead of breaking the code into little pieces, I&amp;#8217;ll add inline comments to explain what&amp;#8217;s going on.&lt;/p&gt;

&lt;h2&gt;Classes&lt;/h2&gt;

&lt;h3&gt;Library Classes&lt;/h3&gt;

&lt;h4&gt;MapperAbstract&lt;/h4&gt;

&lt;p&gt;MapperAbstract is the base class for mappers. It defines a standard interface for all mappers.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;span class='line-number'&gt;13&lt;/span&gt;
&lt;span class='line-number'&gt;14&lt;/span&gt;
&lt;span class='line-number'&gt;15&lt;/span&gt;
&lt;span class='line-number'&gt;16&lt;/span&gt;
&lt;span class='line-number'&gt;17&lt;/span&gt;
&lt;span class='line-number'&gt;18&lt;/span&gt;
&lt;span class='line-number'&gt;19&lt;/span&gt;
&lt;span class='line-number'&gt;20&lt;/span&gt;
&lt;span class='line-number'&gt;21&lt;/span&gt;
&lt;span class='line-number'&gt;22&lt;/span&gt;
&lt;span class='line-number'&gt;23&lt;/span&gt;
&lt;span class='line-number'&gt;24&lt;/span&gt;
&lt;span class='line-number'&gt;25&lt;/span&gt;
&lt;span class='line-number'&gt;26&lt;/span&gt;
&lt;span class='line-number'&gt;27&lt;/span&gt;
&lt;span class='line-number'&gt;28&lt;/span&gt;
&lt;span class='line-number'&gt;29&lt;/span&gt;
&lt;span class='line-number'&gt;30&lt;/span&gt;
&lt;span class='line-number'&gt;31&lt;/span&gt;
&lt;span class='line-number'&gt;32&lt;/span&gt;
&lt;span class='line-number'&gt;33&lt;/span&gt;
&lt;span class='line-number'&gt;34&lt;/span&gt;
&lt;span class='line-number'&gt;35&lt;/span&gt;
&lt;span class='line-number'&gt;36&lt;/span&gt;
&lt;span class='line-number'&gt;37&lt;/span&gt;
&lt;span class='line-number'&gt;38&lt;/span&gt;
&lt;span class='line-number'&gt;39&lt;/span&gt;
&lt;span class='line-number'&gt;40&lt;/span&gt;
&lt;span class='line-number'&gt;41&lt;/span&gt;
&lt;span class='line-number'&gt;42&lt;/span&gt;
&lt;span class='line-number'&gt;43&lt;/span&gt;
&lt;span class='line-number'&gt;44&lt;/span&gt;
&lt;span class='line-number'&gt;45&lt;/span&gt;
&lt;span class='line-number'&gt;46&lt;/span&gt;
&lt;span class='line-number'&gt;47&lt;/span&gt;
&lt;span class='line-number'&gt;48&lt;/span&gt;
&lt;span class='line-number'&gt;49&lt;/span&gt;
&lt;span class='line-number'&gt;50&lt;/span&gt;
&lt;span class='line-number'&gt;51&lt;/span&gt;
&lt;span class='line-number'&gt;52&lt;/span&gt;
&lt;span class='line-number'&gt;53&lt;/span&gt;
&lt;span class='line-number'&gt;54&lt;/span&gt;
&lt;span class='line-number'&gt;55&lt;/span&gt;
&lt;span class='line-number'&gt;56&lt;/span&gt;
&lt;span class='line-number'&gt;57&lt;/span&gt;
&lt;span class='line-number'&gt;58&lt;/span&gt;
&lt;span class='line-number'&gt;59&lt;/span&gt;
&lt;span class='line-number'&gt;60&lt;/span&gt;
&lt;span class='line-number'&gt;61&lt;/span&gt;
&lt;span class='line-number'&gt;62&lt;/span&gt;
&lt;span class='line-number'&gt;63&lt;/span&gt;
&lt;span class='line-number'&gt;64&lt;/span&gt;
&lt;span class='line-number'&gt;65&lt;/span&gt;
&lt;span class='line-number'&gt;66&lt;/span&gt;
&lt;span class='line-number'&gt;67&lt;/span&gt;
&lt;span class='line-number'&gt;68&lt;/span&gt;
&lt;span class='line-number'&gt;69&lt;/span&gt;
&lt;span class='line-number'&gt;70&lt;/span&gt;
&lt;span class='line-number'&gt;71&lt;/span&gt;
&lt;span class='line-number'&gt;72&lt;/span&gt;
&lt;span class='line-number'&gt;73&lt;/span&gt;
&lt;span class='line-number'&gt;74&lt;/span&gt;
&lt;span class='line-number'&gt;75&lt;/span&gt;
&lt;span class='line-number'&gt;76&lt;/span&gt;
&lt;span class='line-number'&gt;77&lt;/span&gt;
&lt;span class='line-number'&gt;78&lt;/span&gt;
&lt;span class='line-number'&gt;79&lt;/span&gt;
&lt;span class='line-number'&gt;80&lt;/span&gt;
&lt;span class='line-number'&gt;81&lt;/span&gt;
&lt;span class='line-number'&gt;82&lt;/span&gt;
&lt;span class='line-number'&gt;83&lt;/span&gt;
&lt;span class='line-number'&gt;84&lt;/span&gt;
&lt;span class='line-number'&gt;85&lt;/span&gt;
&lt;span class='line-number'&gt;86&lt;/span&gt;
&lt;span class='line-number'&gt;87&lt;/span&gt;
&lt;span class='line-number'&gt;88&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='php'&gt;&lt;span class='line'&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MapperAbstract&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="sd"&gt;/**&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * Create a new instance of the DomainObject that this&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * mapper is responsible for. Optionally populating it&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * from a data array.&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     *&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * @param array $data&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * @return DomainObjectAbstract&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     */&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="nv"&gt;$obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;_create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;            &lt;span class="nv"&gt;$obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;populate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$obj&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="sd"&gt;/**&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * Save the DomainObject&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * &lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * Store the DomainObject in persistent storage. Either insert&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * or update the store as required.&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     *&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * @param DomainObjectAbstract $obj&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     */&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;DomainObjectAbstract&lt;/span&gt; &lt;span class="nv"&gt;$obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;is_null&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$obj&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;getId&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;            &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;_insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$obj&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;            &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;_update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$obj&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="sd"&gt;/**&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * Delete the DomainObject&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * &lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * Delete the DomainObject from persistent storage.&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     *&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * @param DomainObjectAbstract $obj&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     */&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;DomainObjectAbstract&lt;/span&gt; &lt;span class="nv"&gt;$obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;_delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$obj&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="sd"&gt;/**&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * Populate the DomainObject with the values&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * from the data array.&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * &lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * To be implemented by the concrete mapper class&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     *&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * @param DomainObjectAbstract $obj&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * @param array $data&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * @return DomainObjectAbstract&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     */&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;populate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;DomainObjectAbstract&lt;/span&gt; &lt;span class="nv"&gt;$obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="sd"&gt;/**&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * Create a new instance of a DomainObject&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * &lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * @return DomainObjectAbstract&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     */&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;_create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="sd"&gt;/**&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * Insert the DomainObject to persistent storage &lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     *&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * @param DomainObjectAbstract $obj&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     */&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;_insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;DomainObjectAbstract&lt;/span&gt; &lt;span class="nv"&gt;$obj&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="sd"&gt;/**&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * Update the DomainObject in persistent storage &lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     *&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * @param DomainObjectAbstract $obj&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     */&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;_update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;DomainObjectAbstract&lt;/span&gt; &lt;span class="nv"&gt;$obj&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="sd"&gt;/**&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * Delete the DomainObject from peristent Storage&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     *&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * @param DomainObjectAbstract $obj&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     */&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;_delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;DomainObjectAbstract&lt;/span&gt; &lt;span class="nv"&gt;$obj&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h4&gt;DomainObjectAbstract&lt;/h4&gt;

&lt;p&gt;A basic class describing an object that is part of the &lt;a href="http://martinfowler.com/eaaCatalog/domainModel.html"&gt;Domain Model&lt;/a&gt;. This model assumes that all DomainObjects have an integer as the primary key, but it would be a trivial change to make it a GUID for example. It also ensures the ID is immutable.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;span class='line-number'&gt;13&lt;/span&gt;
&lt;span class='line-number'&gt;14&lt;/span&gt;
&lt;span class='line-number'&gt;15&lt;/span&gt;
&lt;span class='line-number'&gt;16&lt;/span&gt;
&lt;span class='line-number'&gt;17&lt;/span&gt;
&lt;span class='line-number'&gt;18&lt;/span&gt;
&lt;span class='line-number'&gt;19&lt;/span&gt;
&lt;span class='line-number'&gt;20&lt;/span&gt;
&lt;span class='line-number'&gt;21&lt;/span&gt;
&lt;span class='line-number'&gt;22&lt;/span&gt;
&lt;span class='line-number'&gt;23&lt;/span&gt;
&lt;span class='line-number'&gt;24&lt;/span&gt;
&lt;span class='line-number'&gt;25&lt;/span&gt;
&lt;span class='line-number'&gt;26&lt;/span&gt;
&lt;span class='line-number'&gt;27&lt;/span&gt;
&lt;span class='line-number'&gt;28&lt;/span&gt;
&lt;span class='line-number'&gt;29&lt;/span&gt;
&lt;span class='line-number'&gt;30&lt;/span&gt;
&lt;span class='line-number'&gt;31&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='php'&gt;&lt;span class='line'&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DomainObjectAbstract&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nv"&gt;$_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="sd"&gt;/**&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * Get the ID of this object (unique to the&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * object type)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     *&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * @return int&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     */&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getId&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;_id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="sd"&gt;/**&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * Set the id for this object.&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     *&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * @param int $id&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * @return int&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * @throws Exception If the id on the object is already set&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     */&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;setId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;is_null&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;_id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;ID is immutable&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h3&gt;Example Implementation Classes&lt;/h3&gt;

&lt;h4&gt;User&lt;/h4&gt;

&lt;p&gt;A concrete DomainObject describing a user. This is a &lt;strong&gt;very&lt;/strong&gt; barebones example, usually getters/setters would be used to set protected properties.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;span class='line-number'&gt;13&lt;/span&gt;
&lt;span class='line-number'&gt;14&lt;/span&gt;
&lt;span class='line-number'&gt;15&lt;/span&gt;
&lt;span class='line-number'&gt;16&lt;/span&gt;
&lt;span class='line-number'&gt;17&lt;/span&gt;
&lt;span class='line-number'&gt;18&lt;/span&gt;
&lt;span class='line-number'&gt;19&lt;/span&gt;
&lt;span class='line-number'&gt;20&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='php'&gt;&lt;span class='line'&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;DomainObjectAbstract&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nv"&gt;$firstname&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nv"&gt;$lastname&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nv"&gt;$username&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="sd"&gt;/**&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * Get the full name of the User&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * &lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * Demonstrates how other functions can be&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * added to the DomainObject&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     *&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * @return string&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     */&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getName&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;firstname&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39; &amp;#39;&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;lastname&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h4&gt;UserMapper&lt;/h4&gt;

&lt;p&gt;A concrete implementation of a mapper between the User domain object and persistent storage.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;span class='line-number'&gt;13&lt;/span&gt;
&lt;span class='line-number'&gt;14&lt;/span&gt;
&lt;span class='line-number'&gt;15&lt;/span&gt;
&lt;span class='line-number'&gt;16&lt;/span&gt;
&lt;span class='line-number'&gt;17&lt;/span&gt;
&lt;span class='line-number'&gt;18&lt;/span&gt;
&lt;span class='line-number'&gt;19&lt;/span&gt;
&lt;span class='line-number'&gt;20&lt;/span&gt;
&lt;span class='line-number'&gt;21&lt;/span&gt;
&lt;span class='line-number'&gt;22&lt;/span&gt;
&lt;span class='line-number'&gt;23&lt;/span&gt;
&lt;span class='line-number'&gt;24&lt;/span&gt;
&lt;span class='line-number'&gt;25&lt;/span&gt;
&lt;span class='line-number'&gt;26&lt;/span&gt;
&lt;span class='line-number'&gt;27&lt;/span&gt;
&lt;span class='line-number'&gt;28&lt;/span&gt;
&lt;span class='line-number'&gt;29&lt;/span&gt;
&lt;span class='line-number'&gt;30&lt;/span&gt;
&lt;span class='line-number'&gt;31&lt;/span&gt;
&lt;span class='line-number'&gt;32&lt;/span&gt;
&lt;span class='line-number'&gt;33&lt;/span&gt;
&lt;span class='line-number'&gt;34&lt;/span&gt;
&lt;span class='line-number'&gt;35&lt;/span&gt;
&lt;span class='line-number'&gt;36&lt;/span&gt;
&lt;span class='line-number'&gt;37&lt;/span&gt;
&lt;span class='line-number'&gt;38&lt;/span&gt;
&lt;span class='line-number'&gt;39&lt;/span&gt;
&lt;span class='line-number'&gt;40&lt;/span&gt;
&lt;span class='line-number'&gt;41&lt;/span&gt;
&lt;span class='line-number'&gt;42&lt;/span&gt;
&lt;span class='line-number'&gt;43&lt;/span&gt;
&lt;span class='line-number'&gt;44&lt;/span&gt;
&lt;span class='line-number'&gt;45&lt;/span&gt;
&lt;span class='line-number'&gt;46&lt;/span&gt;
&lt;span class='line-number'&gt;47&lt;/span&gt;
&lt;span class='line-number'&gt;48&lt;/span&gt;
&lt;span class='line-number'&gt;49&lt;/span&gt;
&lt;span class='line-number'&gt;50&lt;/span&gt;
&lt;span class='line-number'&gt;51&lt;/span&gt;
&lt;span class='line-number'&gt;52&lt;/span&gt;
&lt;span class='line-number'&gt;53&lt;/span&gt;
&lt;span class='line-number'&gt;54&lt;/span&gt;
&lt;span class='line-number'&gt;55&lt;/span&gt;
&lt;span class='line-number'&gt;56&lt;/span&gt;
&lt;span class='line-number'&gt;57&lt;/span&gt;
&lt;span class='line-number'&gt;58&lt;/span&gt;
&lt;span class='line-number'&gt;59&lt;/span&gt;
&lt;span class='line-number'&gt;60&lt;/span&gt;
&lt;span class='line-number'&gt;61&lt;/span&gt;
&lt;span class='line-number'&gt;62&lt;/span&gt;
&lt;span class='line-number'&gt;63&lt;/span&gt;
&lt;span class='line-number'&gt;64&lt;/span&gt;
&lt;span class='line-number'&gt;65&lt;/span&gt;
&lt;span class='line-number'&gt;66&lt;/span&gt;
&lt;span class='line-number'&gt;67&lt;/span&gt;
&lt;span class='line-number'&gt;68&lt;/span&gt;
&lt;span class='line-number'&gt;69&lt;/span&gt;
&lt;span class='line-number'&gt;70&lt;/span&gt;
&lt;span class='line-number'&gt;71&lt;/span&gt;
&lt;span class='line-number'&gt;72&lt;/span&gt;
&lt;span class='line-number'&gt;73&lt;/span&gt;
&lt;span class='line-number'&gt;74&lt;/span&gt;
&lt;span class='line-number'&gt;75&lt;/span&gt;
&lt;span class='line-number'&gt;76&lt;/span&gt;
&lt;span class='line-number'&gt;77&lt;/span&gt;
&lt;span class='line-number'&gt;78&lt;/span&gt;
&lt;span class='line-number'&gt;79&lt;/span&gt;
&lt;span class='line-number'&gt;80&lt;/span&gt;
&lt;span class='line-number'&gt;81&lt;/span&gt;
&lt;span class='line-number'&gt;82&lt;/span&gt;
&lt;span class='line-number'&gt;83&lt;/span&gt;
&lt;span class='line-number'&gt;84&lt;/span&gt;
&lt;span class='line-number'&gt;85&lt;/span&gt;
&lt;span class='line-number'&gt;86&lt;/span&gt;
&lt;span class='line-number'&gt;87&lt;/span&gt;
&lt;span class='line-number'&gt;88&lt;/span&gt;
&lt;span class='line-number'&gt;89&lt;/span&gt;
&lt;span class='line-number'&gt;90&lt;/span&gt;
&lt;span class='line-number'&gt;91&lt;/span&gt;
&lt;span class='line-number'&gt;92&lt;/span&gt;
&lt;span class='line-number'&gt;93&lt;/span&gt;
&lt;span class='line-number'&gt;94&lt;/span&gt;
&lt;span class='line-number'&gt;95&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='php'&gt;&lt;span class='line'&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserMapper&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;MapperAbstract&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="sd"&gt;/**&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * Fetch a user object by ID&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * &lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * An example skeleton of a &amp;quot;Fetch&amp;quot; function showing&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * how the database data ($dataFromDb) is used to&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * create a new User instance via the create function.&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     *&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * @param string $id&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * @return User&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     */&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;findById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="c1"&gt;// Query database for User with $id&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="nv"&gt;$dataFromDb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;                &lt;span class="s1"&gt;&amp;#39;id&amp;#39;&lt;/span&gt;        &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;                &lt;span class="s1"&gt;&amp;#39;firstname&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Brenton&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;                &lt;span class="s1"&gt;&amp;#39;lastname&amp;#39;&lt;/span&gt;  &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;                &lt;span class="s1"&gt;&amp;#39;username&amp;#39;&lt;/span&gt;  &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Tekerson&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;            &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$dataFromDb&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="sd"&gt;/**&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * Poplate the User (DomainObject) with&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * the data array.&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * &lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * This is a very simple example, but the mapping &lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * can be as complex as required.&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     *&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * @param DomainObjectAbstract $obj&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * @param array $data&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * @return User&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     */&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;populate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;DomainObjectAbstract&lt;/span&gt; &lt;span class="nv"&gt;$obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="nv"&gt;$obj&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;setId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;id&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="nv"&gt;$obj&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;firstname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;firstname&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="nv"&gt;$obj&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;lastname&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;lastname&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="nv"&gt;$obj&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;username&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;username&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$obj&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="sd"&gt;/**&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * Create a new User DomainObject&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     *&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * @return User&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     */&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;_create&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="sd"&gt;/**&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * Insert the DomainObject in persistent storage&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * &lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * This may include connecting to the database&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * and running an insert statement.&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     *&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * @param DomainObjectAbstract $obj&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     */&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;_insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;DomainObjectAbstract&lt;/span&gt; &lt;span class="nv"&gt;$obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="sd"&gt;/**&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * Update the DomainObject in persistent storage&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * &lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * This may include connecting to the database&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * and running an update statement.&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     *&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * @param DomainObjectAbstract $obj&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     */&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;_update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;DomainObjectAbstract&lt;/span&gt; &lt;span class="nv"&gt;$obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="sd"&gt;/**&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * Delete the DomainObject from persistent storage&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * &lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * This may include connecting to the database&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * and running a delete statement.&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     *&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     * @param DomainObjectAbstract $obj&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sd"&gt;     */&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;_delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;DomainObjectAbstract&lt;/span&gt; &lt;span class="nv"&gt;$obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h2&gt;Example&lt;/h2&gt;

&lt;p&gt;Ok, I realize that I&amp;#8217;ve dumped a lot of code and we&amp;#8217;re nearly finished. Now we finally get to see how it all fits together to do something. Here, I am creating a simple example where I fetch a User based on their ID, change the Users name, and store it back to the database.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='php'&gt;&lt;span class='line'&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c1"&gt;// Initialise the Mapper.&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;$userMapper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;UserMapper&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c1"&gt;// Fetch and manipulate the User object&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$userMapper&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;findById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;lastname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Alker&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c1"&gt;// Tell the UserMapper that the User needs to be saved.&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;$userMapper&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Well, I hope everything makes sense. This is a very simplified version of the concepts I have been working on.&lt;/p&gt;

&lt;p&gt;These simple examples could be expanded in may directions. Such as;&lt;/p&gt;

&lt;p&gt;Validation of the DomainObject fields, I haven&amp;#8217;t decided if the validation should be contained in the DomainObject or the Mapper.&lt;/p&gt;

&lt;p&gt;An &lt;a href="http://martinfowler.com/eaaCatalog/identityMap.html"&gt;identity map&lt;/a&gt; to ensure only 1 instance of each DomainObject exists in memory at a time.&lt;/p&gt;

&lt;p&gt;A &lt;a href="http://martinfowler.com/eaaCatalog/unitOfWork.html"&gt;UnitOfWork&lt;/a&gt; to track which objects need saving, deleting and to co-ordinate roll backs on error, or the order of persistence to satisfy foreign key constraints.&lt;/p&gt;

&lt;p&gt;The Mapper could access many data stores; RDBMSs, Session/Cookie data or web services to name a few. Remember, the Mapper decouples the DomainObject completely from the persistent storage&lt;/p&gt;

&lt;p&gt;Anyway, I hope this provides a fairly simple concrete example that you can build upon to create a more complete solution that you can then share with the rest of us.&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/DeprecatedBehaviour/~4/Ug2OKYt1DRg" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://blog.tekerson.com/2008/12/17/data-mapper-pattern-in-php/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Telecommute Experience (Part 2)]]></title>
    <link href="http://feedproxy.google.com/~r/DeprecatedBehaviour/~3/aTVXQmI4B_0/" />
    <updated>2008-12-16T18:34:01+10:00</updated>
    <id>http://blog.tekerson.com/2008/12/16/telecommute-experience-part-2</id>
    <content type="html">&lt;p&gt;I have been telecommuting for a bit over a month now, and things have settled quite well.&lt;/p&gt;

&lt;p&gt;We have set up an office, away from the entertainment area (except the foosball table, that&amp;#8217;s in the office :)). This has been good to keep some separation between those trying to get work done and the rest of the household population.&lt;/p&gt;

&lt;p&gt;With the time difference, office hours work well. An 8 hour stint from 1pm to 9pm (Canada) is the same as 7am to 3pm (Australia). Giving plenty of time in the morning to enjoy the snow, while still allowing ample real-time communication with the office during business hours, and even leaving some time after the work day to relax.&lt;/p&gt;

&lt;p&gt;The work itself hasn&amp;#8217;t changed much. A good issue tracker makes things much easier (We use &lt;a href="http://eventum.mysql.org/"&gt;MySQL&amp;#8217;s Eventum&lt;/a&gt;) because everyone can easily see a current list of priorities and who is doing what, which is always important but even more so without real-time contact.&lt;/p&gt;

&lt;p&gt;A good local development environment has also been invaluable, being able to develop and test completely without a connection to the world ensures I can still be productive even when the Internet is on the fritz. Using virtual machines I have set up individual environments for each project. &lt;a href="http://git.or.cz/"&gt;Git&lt;/a&gt; (via git-svn) for version control allows me to work; branching, committing, merging and reverting all locally.&lt;/p&gt;

&lt;p&gt;Communication has primarily been via instant messenger, which was already the case in the office anyway, so no real transition there. Skype is also great if you need voice communication (I generally don&amp;#8217;t).&lt;/p&gt;

&lt;p&gt;Using these tools, the transition has been smooth and painless. We have even successfully deployed a major project since I have been here. So far, so good.&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/DeprecatedBehaviour/~4/aTVXQmI4B_0" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://blog.tekerson.com/2008/12/16/telecommute-experience-part-2/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Telecommute Experience (Part 1)]]></title>
    <link href="http://feedproxy.google.com/~r/DeprecatedBehaviour/~3/sCCvtEdbRNk/" />
    <updated>2008-11-24T23:27:59+10:00</updated>
    <id>http://blog.tekerson.com/2008/11/24/telecommute-experience-part-1</id>
    <content type="html">&lt;p&gt;I&amp;#8217;ve just started telecommuting, and not wanting to take it slowly, I&amp;#8217;ve jumped straight into an international arrangement; living in Canada and working in Brisbane, Australia. This is my story&amp;#8230;&lt;/p&gt;

&lt;p&gt;After almost 3 years with my current employer, I decided I needed to get out of the office. Not that there is anything particularly wrong with the office, it&amp;#8217;s just not the most exciting environment and I was getting pretty over it.&lt;/p&gt;

&lt;p&gt;It just so happened that a number of my friends were in a similar situation, and a plan was hatched to move ourselves to Canada for 6 months. Once an approximate timetable was established, we approached our respective employers. After explaining the plan to make the move and maintain our current employment, for the most part we met little resistance; this was a little surprising to me.&lt;/p&gt;

&lt;p&gt;So the approximate plans were filled with some more details, and off we went.&lt;/p&gt;

&lt;p&gt;To Be Continued&amp;#8230;&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/DeprecatedBehaviour/~4/sCCvtEdbRNk" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://blog.tekerson.com/2008/11/24/telecommute-experience-part-1/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Basic branching with git]]></title>
    <link href="http://feedproxy.google.com/~r/DeprecatedBehaviour/~3/g8vQIIRQV8s/" />
    <updated>2008-09-05T22:48:22+10:00</updated>
    <id>http://blog.tekerson.com/2008/09/05/basic-branching-with-git</id>
    <content type="html">&lt;p&gt;With 3 long-running tasks concurrently on my plate, I finally got around to learning branching in &lt;a href="http://git.or.cz/"&gt;git&lt;/a&gt;, and it&amp;#8217;s &lt;strong&gt;easy!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Until this week, I had managed to get by without learning to branch. I have looked previously but got a little lost. I often temporarily stored my work using &amp;#8221;&lt;a href="http://www.kernel.org/pub/software/scm/git/docs/git-stash.html"&gt;git-stash&lt;/a&gt;&amp;#8221; to work on multiple things at once, but this is very limiting.&lt;/p&gt;

&lt;p&gt;So, Here we go. My basic workflow now look like this.&lt;/p&gt;

&lt;p&gt;Create a new branch (based on the HEAD of your current branch), and automatically switch to it:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;code&amp;gt;&amp;lt;a href="http://www.kernel.org/pub/software/scm/git/docs/git-checkout.html" title="git-checkout manual page"&amp;gt;git checkout&amp;lt;/a&amp;gt; -b my_branch&amp;lt;/code&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then you can work within this branch as you always would.&lt;/p&gt;

&lt;p&gt;Work, work, work&amp;#8230;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;code&amp;gt;&amp;lt;a&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;a href="http://www.kernel.org/pub/software/scm/git/docs/git-add.html" title="git-add manual page"&amp;gt;git add&amp;lt;/a&amp;gt; files_i_have_edited.txt
&amp;lt;a href="http://www.kernel.org/pub/software/scm/git/docs/git-commit.html" title="git-commit manual page"&amp;gt;git commit&amp;lt;/a&amp;gt; -m 'My changes'&amp;lt;/code&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Repeating this step until the task is complete. Then, to get the changes back into the master branch. Switch to it&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;code&amp;gt;&amp;lt;a href="http://www.kernel.org/pub/software/scm/git/docs/git-checkout.html" title="git-checkout manual page"&amp;gt;git checkout&amp;lt;/a&amp;gt; master&amp;lt;/code&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And pull the changes from the branch&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;code&amp;gt;&amp;lt;a href="http://www.kernel.org/pub/software/scm/git/docs/git-pull.html" title="git-pull manual page"&amp;gt;git pull&amp;lt;/a&amp;gt; . my_branch&amp;lt;/code&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Easy. No need to remember revision numbers where you branched, or which changed have already been merged. You can of course switch back to the branch and continue work with&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;code&amp;gt;&amp;lt;a href="http://www.kernel.org/pub/software/scm/git/docs/git-checkout.html" title="git-checkout manual page"&amp;gt;git checkout&amp;lt;/a&amp;gt; my_branch&amp;lt;/code&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;this &amp;#8220;edit, commit, pull&amp;#8221; cycle can continue until the task is complete. Then, once you&amp;#8217;re satisfied you can delete the branch with&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;code&amp;gt;&amp;lt;a href="http://www.kernel.org/pub/software/scm/git/docs/git-branch.html" title="git-branch manual page"&amp;gt;git branch&amp;lt;/a&amp;gt; -d my_branch&amp;lt;/code&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It&amp;#8217;s still in the history of course, but no need to keep old branches around.&lt;/p&gt;

&lt;p&gt;Hope that makes things clear to anyone else who was confused as I was by some of the overly complicated explanation of branching in git.&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/DeprecatedBehaviour/~4/g8vQIIRQV8s" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://blog.tekerson.com/2008/09/05/basic-branching-with-git/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[New VPS Hosting]]></title>
    <link href="http://feedproxy.google.com/~r/DeprecatedBehaviour/~3/aORSekdOfm4/" />
    <updated>2008-08-12T07:38:16+10:00</updated>
    <id>http://blog.tekerson.com/2008/08/12/new-vps-hosting</id>
    <content type="html">&lt;p&gt;If you&amp;#8217;re reading this then I have successfully migrated to my new VPS hosting on &lt;a href="https://manage.slicehost.com/customers/new?referrer=1470153180"&gt;Slicehost&lt;/a&gt;.&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/DeprecatedBehaviour/~4/aORSekdOfm4" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://blog.tekerson.com/2008/08/12/new-vps-hosting/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[trim() Validation]]></title>
    <link href="http://feedproxy.google.com/~r/DeprecatedBehaviour/~3/MfGDg88XflI/" />
    <updated>2008-07-15T23:11:18+10:00</updated>
    <id>http://blog.tekerson.com/2008/07/15/trim-validation</id>
    <content type="html">&lt;p&gt;While writing a fairly standard sign-up/log-in system, I got to the point of validating the password to make sure it only contained acceptable characters. Now for me this would usually mean a regular expression. But, since this system wasn&amp;#8217;t for me I decided to make the &amp;#8220;valid characters&amp;#8221; configurable, and generally the people configuring it won&amp;#8217;t be able to write a regular expression.&lt;/p&gt;

&lt;p&gt;My solution is to use &lt;a href="http://php.net/trim"&gt;php&amp;#8217;s trim()&lt;/a&gt; (or more specifically &lt;a href="http://php.net/rtrim"&gt;rtrim()&lt;/a&gt;, but it doesn&amp;#8217;t really matter) by passing the users input as the first argument, and the string of valid characters as the second; I should get an empty string in return. So the test, only allowing lowercase letters, becomes:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='php'&gt;&lt;span class='line'&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nb"&gt;rtrim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;abcdefghijklmnopqrstuvwxyz&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Simple! I don&amp;#8217;t know how it compares speed wise with other methods, but it seems simple and effective and I can&amp;#8217;t imagine it&amp;#8217;s terribly slow unless your strings get larger.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;m also not sure how it would handle multi-byte characters. But I don&amp;#8217;t &lt;strong&gt;think&lt;/strong&gt; it would be a problem if it doesn&amp;#8217;t. Anyone got any insight?&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/DeprecatedBehaviour/~4/MfGDg88XflI" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://blog.tekerson.com/2008/07/15/trim-validation/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[An Attempt at Restricted Auto-Login]]></title>
    <link href="http://feedproxy.google.com/~r/DeprecatedBehaviour/~3/k_N_93y2lRc/" />
    <updated>2008-07-05T02:33:18+10:00</updated>
    <id>http://blog.tekerson.com/2008/07/05/an-attempt-at-restricted-auto-login</id>
    <content type="html">&lt;p&gt;The system I have been building is a direct marketing system (don&amp;#8217;t hate me, it&amp;#8217;s opt-in) and to be compliant with their ethics policy it requires &amp;#8220;2 click unsubscribe&amp;#8221; functionality from all its email campaigns; 1 click on the link in the email, and 1 click on a big &amp;#8220;Don&amp;#8217;t Ever Send Me Email Again&amp;#8221; button. So people actually have an option to opt out at any time, as any good (and I use that word in the relative sense) email marketing system should.&lt;/p&gt;

&lt;p&gt;The problem this poses for me though, is how can I let a member unsubscribe without authenticating themselves? Authentication would take more than 2 clicks! The obvious solution is to not require authentication by simply adding the members identifier (email address, user name, database id, whatever can identify them uniquely) to the link. So I would have a URL something like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;http://example.com/member/unsubscribe?member=1234
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And simply make all the options on that page act on the member identified by the identifier. Great! Until a malicious netizen comes along, seeing the scheme decides to systematically unsubscribe all my members. This would be achieved easily by guessing the identifiers, made even easier because they&amp;#8217;re sequential, and clicking the unsubscribe button.&lt;/p&gt;

&lt;p&gt;The initial solution is to use some other &amp;#8220;key&amp;#8221; in the link, one that is not so easy to guess. So a key was added, giving the url a form like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;http://example.com/member/unsubscribe?member=1234&amp;amp;key=SECRETKEY
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Were SECRETKEY is a key they is generated randomly when the user signs up and stored with their account details. Using this, the system would allow a user to log in simply by clicking the link, they could then unsubscribe.&lt;/p&gt;

&lt;p&gt;The problem being, of course, that by simply logging the user into their account anyone who has the link has full access to the account without needing to know any more information. So they could then read (and change) email addresses, passwords etc. Not ideal.&lt;/p&gt;

&lt;p&gt;My solution has been to take the key a step further, and limit it to only the intended page. In this case the unsubscribe page. So my new url looks like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;http://example.com/member/unsubscribe?token=1234:HASH
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I&amp;#8217;ve removed the member variable and combined it into a delimited token. This was mainly because I thought it looked a little nicer, it would function just as well as a separate variable. The real change is in the HASH. The new hash still uses the SECRETKEY that was used in the previous iteration, except it is now combined with the url that I want to give them access to, and an added salt so all tokens can be invalidated if required. In PHP, this looks something like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;code&amp;gt;$allowedUrl = '/member/unsubscribe';
$hash = md5($salt . $allowedUrl . ':' . $secretKey);
$token = $id . ':' . $hash;
&amp;lt;/code&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;On the page, to allow access, the token is decomposed, the member&amp;#8217;s identifier extracted, and their key retrieved. Their key is then used in the same process to generate a hash for the URL they are requesting. If the hashes match, they have access. To make it a little more user friendly, the allowed URL is added to their session, so they still have access to the page even if they lose the token from the URL. If they hit any other page with the restricted URL in their session they are logged out and sent back to re-authenticate.&lt;/p&gt;

&lt;p&gt;One shortfall that I am aware of, and that was pointed out in a discussion on #phpc, is the members secret keys should ideally be rotated, so it can only be used once. This would mean that stealing a link would at worst allow one login, and only to one page. This may be implemented if it doesn&amp;#8217;t impact too much on usability (that classic trade-off, security vs. convenience).&lt;/p&gt;

&lt;p&gt;Now, I am not a security expert and as such don&amp;#8217;t recommend anyone take my advice (is this good enough for a disclaimer), but apart from the one caveat mentioned, I think this solution meets the requirements without forfeiting too much in security. Any comments or advice on the technique are, as always, appreciated.&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/DeprecatedBehaviour/~4/k_N_93y2lRc" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://blog.tekerson.com/2008/07/05/an-attempt-at-restricted-auto-login/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[My Web 2.0 World]]></title>
    <link href="http://feedproxy.google.com/~r/DeprecatedBehaviour/~3/6R785e70kzc/" />
    <updated>2008-05-31T02:41:40+10:00</updated>
    <id>http://blog.tekerson.com/2008/05/31/my-web-2-world</id>
    <content type="html">&lt;p&gt;The last month or so I&amp;#8217;ve been trying to actually get into the whole &amp;#8220;Web 2.0&amp;#8221; (I don&amp;#8217;t like the term by the way) world. I know it&amp;#8217;s old news, and it&amp;#8217;s not like it&amp;#8217;s new to me either. I just recently thought about all the web applications that seem to be so popular that I have dormant accounts on, the main ones are;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="http://www.facebook.com/profile.php?id=611142997"&gt;Facebook&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="http://twitter.com/tekerson"&gt;Twitter&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="http://flickr.com/photos/26075837@N02/"&gt;Flickr&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="http://del.icio.us/tekerson"&gt;del.icio.us&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Facebook, well, that&amp;#8217;s taken MySpace&amp;#8217;s place as the social network I only passively interact with. The other three are of more interest to me, so I&amp;#8217;ve decided to try and use them for something useful.&lt;/p&gt;

&lt;p&gt;Flickr is a fairly easy one, I have a large collection of digitized photographs spanning a few years which are for the most part sorted/tagged thanks to &lt;a href="http://f-spot.org/Main_Page"&gt;F-Spot&lt;/a&gt; which has the ability to sync with many popular image hosting sites including Flickr and &lt;a href="http://picasaweb.google.com/Brenton.Alker/"&gt;Google&amp;#8217;s Picasaweb&lt;/a&gt;. So I am gradually building the on-line collection, I initially intended to just dump the lot on there (if only as a backup) but then realised that there are a few too many GB for that.&lt;/p&gt;

&lt;p&gt;Del.icio.us I get, but as someone who has never been a big collector of bookmarks, I don&amp;#8217;t find too useful. My bookmarks in my browser have always been a mess, mainly because they are all just temporary. Any site I visit on a regular basis for any extended period of time, I know the address for (or at least know a good google query to find it). But, in the spirit of my trying to &amp;#8220;giving it a go&amp;#8221; I installed the &lt;a href="http://del.icio.us/help/firefox/extension"&gt;firefox extension&lt;/a&gt; and added my &amp;#8220;recent bookmarks&amp;#8221; to this page using the &lt;a href="http://rick.jinlabs.com/code/delicious"&gt;wordpress plugin&lt;/a&gt; (over there on the right somewhere). I must say I&amp;#8217;m using it more, but still not a great deal.&lt;/p&gt;

&lt;p&gt;Twitter is an oddity to me, it seems incredibly popular; in spite of it&amp;#8217;s apparent unreliability. To me it seems to sit somewhere between a very slow IRC and a short message mailing list. I think the only advantage I can see is that it can work mobile, though I&amp;#8217;ve not had much luck keeping that working for more than a day or two. Most other people who have complained about &amp;#8220;Not Getting It&amp;#8221; when it comes to Twitter seem to be told to install a desktop client, as it is much more conducive to regular use than the website. So, I diligently installed &lt;a href="http://funkatron.com/spaz"&gt;Spaz&lt;/a&gt;, an &lt;a href="http://www.adobe.com/products/air/"&gt;Adobe Air&lt;/a&gt; based client, which means I now get little popups telling me when someone &amp;#8220;tweets&amp;#8221;. That makes it more convenient, so far it hasn&amp;#8217;t made it more interesting.&lt;/p&gt;

&lt;p&gt;Although all the tools are very cool, maybe this &amp;#8220;Social Web&amp;#8221; thing just isn&amp;#8217;t for me. Then again, maybe it&amp;#8217;s this whole &amp;#8220;Social&amp;#8221; thing that just doesn&amp;#8217;t work for me ;)&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/DeprecatedBehaviour/~4/6R785e70kzc" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://blog.tekerson.com/2008/05/31/my-web-2-world/</feedburner:origLink></entry>
  
</feed>
