<?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[PapayaSoft - Phuket web development]]></title>
  
  <link href="http://www.papayasoft.com/" />
  <updated>2013-06-14T14:15:06+07:00</updated>
  <id>http://www.papayasoft.com/</id>
  <author>
    <name><![CDATA[David Weinraub]]></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/papayasoft" /><feedburner:info uri="papayasoft" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry>
    <title type="html"><![CDATA[Goodbye, Wordpress. Hello, Octopress.]]></title>
    <link href="http://feedproxy.google.com/~r/papayasoft/~3/x216-WHmlkQ/" />
    <updated>2013-06-09T21:26:00+07:00</updated>
    <id>http://www.papayasoft.com/2013/06/09/goodbye-wordpress-hello-octopress</id>
    <content type="html">&lt;p&gt;Finally made the move from Wordpress to &lt;a href="http://octopress.org"&gt;Octopress&lt;/a&gt;.&lt;/p&gt;

&lt;!-- more --&gt;


&lt;h2&gt;Why leave Wordpress?&lt;/h2&gt;

&lt;p&gt;I&amp;rsquo;m finding it hard to identify specifically what was so unsatisfying about Wordpress.&lt;/p&gt;

&lt;p&gt;Maybe it was fighting through a GUI. Maybe it was dealing with so many upgrades to WP core and to plugins. Maybe it was having the blog content reside in a database rather than in a Git repo.&lt;/p&gt;

&lt;p&gt;Ultimately, I just found myself with a feeling of dread every time I had to plunge back into Wordpress to tweak something or even just to write a fairly text-ish post.&lt;/p&gt;

&lt;p&gt;The net result was that I hardly blogged at all.&lt;/p&gt;

&lt;h2&gt;Why Octopress?&lt;/h2&gt;

&lt;p&gt;I&amp;rsquo;d been looking at &lt;a href="http://jekyllrb.com/"&gt;Jekyll&lt;/a&gt; for a long time, since a lot of the cool kids seem to be using it.&lt;/p&gt;

&lt;p&gt;More objectively, Jekyll would offer me the following benefits:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Write posts in markdown.&lt;/li&gt;
&lt;li&gt;No more GUI.&lt;/li&gt;
&lt;li&gt;No more DB.&lt;/li&gt;
&lt;li&gt;Content is more easily managed in a Git repo.&lt;/li&gt;
&lt;li&gt;Static site loads fast and deploys easily.&lt;/li&gt;
&lt;li&gt;Learn some new stuff.&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;But I really couldn&amp;rsquo;t get my head all the way around how it all works.&lt;/p&gt;

&lt;p&gt;Then someone &amp;ndash; I really can&amp;rsquo;t remember who. Seriously. If it was you and you know who you are, please remind me so I can credit you &amp;ndash; pointed me to Octopress which I view as a Jekyll wrapper. That wrapping and the accompanying docs closed the gap enough so I could &lt;em&gt;get it&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The bottom line was that it just seems easier to manage the blog using the familiar tools that I use every day: SublimeText, Git, and a few CLI commands.&lt;/p&gt;

&lt;h2&gt;How?&lt;/h2&gt;

&lt;p&gt;Overall, the &lt;a href="http://octopress.org/docs/"&gt;Octopress docs&lt;/a&gt; are quite good and pretty clearly describe the steps.&lt;/p&gt;

&lt;p&gt;But since a migration from WP involves a few more considerations than just starting a new blog, there are a few additional steps. The post &lt;a href="http://jason.pureconcepts.net/2013/01/migrating-wordpress-octopress/"&gt;Migrating from Wordpress to Octopress&lt;/a&gt; from Jason McCreary was very helpful.&lt;/p&gt;

&lt;p&gt;For reference, my host OS is Ubuntu 12.04.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Setup Ruby environment.&lt;/strong&gt; I used &lt;a href="https://rvm.io/%E2%80%8E"&gt;rvm&lt;/a&gt; to get the required v1.9.3. Fought with a bit of &lt;code&gt;~/.bash_profile&lt;/code&gt; stuff, but emerged victorious.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Git ready to rumble.&lt;/strong&gt; After doing the core install according to the Octopress docs, including a &lt;code&gt;git clone&lt;/code&gt; of the Octopress repo, I blasted my &lt;code&gt;.git&lt;/code&gt; folder since I don&amp;rsquo;t want the entire Octopress history as my blog history. Then I did a &lt;code&gt;git init&lt;/code&gt; to start with a fresh repo, did &lt;code&gt;git remote add origin&lt;/code&gt; pointing to my own remote Bitbucket repo. Then &lt;code&gt;git add&lt;/code&gt;, &lt;code&gt;git commit&lt;/code&gt;, and &lt;code&gt;git push origin&lt;/code&gt; to get me up and running.&lt;/p&gt;

&lt;p&gt;I did add the main Octopress repo as a remote called &lt;code&gt;upstream&lt;/code&gt; in the suspicion that it will allow me to pull upgrades from them, but I confess that I haven&amp;rsquo;t yet fully thought through all that. Perhaps a future post can describe that process.&lt;/p&gt;

&lt;p&gt;Note that all of this Git stuff in not strictly necessary to use Octopress. But being able to manage my blog primarily with Git was one of my primary goals.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Export posts, pages, and blog metadata.&lt;/strong&gt; The &lt;a href="https://github.com/benbalter/wordpress-to-jekyll-exporter"&gt;Export To Jekyll plugin&lt;/a&gt; recommended by Jason made it a piece of cake. Once I had that data, I just had to drop it all (except the &lt;code&gt;_config.yml&lt;/code&gt; file) into the Octopress &lt;code&gt;source&lt;/code&gt; directory. I transferred the values from the exported &lt;code&gt;_config.yml&lt;/code&gt; into the main Octopress &lt;code&gt;_config.yml&lt;/code&gt; and discarded the export version.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Export comments.&lt;/strong&gt; Per the &lt;a href="http://help.disqus.com/customer/portal/articles/466255-exporting-comments-from-wordpress-to-disqus"&gt;Wordpress export page on the Disqus site&lt;/a&gt;, I just exported the entire site to WXR format (&lt;code&gt;WP &amp;gt; Admin &amp;gt; Tools &amp;gt; Export&lt;/code&gt;]) and then imported the WXR file into my Disqus account. It took a few hours for Disqus to chew through it all &amp;ndash; even though it was pretty small &amp;ndash; but it&amp;rsquo;s not like I had any shortage of other things to do. ;&amp;ndash;)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Setup permalinks.&lt;/strong&gt; In order for Disqus to associate the imported comments to your Octopress posts, the Octopress urls and for all posts and pages need to the same as they were on the WP site . In &lt;code&gt;_config.yml&lt;/code&gt;, set the permalink structure to match what you had in WP.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Generate&lt;/strong&gt; your shiny new static blog using &lt;code&gt;rake generate&lt;/code&gt;. View your blog home page at &lt;code&gt;public/index.html&lt;/code&gt;. I setup a local virtual host called &lt;code&gt;papayasoft.local&lt;/code&gt; mapped to the &lt;code&gt;public&lt;/code&gt; folder.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Tweak.&lt;/strong&gt; Enabled/configured plugins. Found/corrected errors in old posts. Added a few custom &lt;code&gt;asides&lt;/code&gt; and just generally figured how stuff works.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Deploy.&lt;/strong&gt; I deployed using &lt;code&gt;rsync&lt;/code&gt;. The &lt;a href="http://octopress.org/docs/deploying/"&gt;Octopress deployment docs&lt;/a&gt; were right on.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;The result is the creature at which you are right now gazing &amp;ndash; admiringly or otherwise.&lt;/p&gt;

&lt;h2&gt;TODO&lt;/h2&gt;

&lt;p&gt;Still a bunch of stuff to do including:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Get a better theme. There&amp;rsquo;s nothing inherently wrong with the default theme. It&amp;rsquo;s just that by virtue of being the default, it&amp;rsquo;s pretty common. It&amp;rsquo;s also a little plain. I&amp;rsquo;d like to find something with at least a splash of color, like &lt;a href="http://www.ducea.com/2012/11/12/disqus-comments-not-visible-in-octopress/"&gt;this one&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Replace a missing page or two.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Most of all, start blogging again!&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;img src="http://feeds.feedburner.com/~r/papayasoft/~4/x216-WHmlkQ" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.papayasoft.com/2013/06/09/goodbye-wordpress-hello-octopress/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Debugging a web-app in a Vagrant-provisioned VirtualBox VM using Netbeans]]></title>
    <link href="http://feedproxy.google.com/~r/papayasoft/~3/xCp3ku_8i1Y/" />
    <updated>2013-02-25T00:00:00+07:00</updated>
    <id>http://www.papayasoft.com/2013/02/25/debugging-vagrant-virtualbox-vm-netbeans</id>
    <content type="html">&lt;p&gt;&lt;a href="http://www.diamondwebservices.com/"&gt;Our team&lt;/a&gt; has begun to use &lt;a href="http://www.vagrantup.com/"&gt;Vagrant&lt;/a&gt; to provision controlled virtual machine environments for all our development. It&amp;#8217;s a cool concept, but I was left without the ability to use my Netbeans debugger. It took a little fiddling around to get it right, but I didn&amp;#8217;t think about blogging about it until:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://twitter.com/jakemcgraw"&gt;Jake McGraw&lt;/a&gt; wisely &lt;a href="https://twitter.com/jakemcgraw/status/303180771567472640"&gt;suggested it&lt;/a&gt; on Twitter.&lt;/li&gt;
&lt;li&gt;I realized that I had re-provisioned my virtual machine (VM) and was maddeningly unable to reproduce what I had done.&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;So, as much as I hope this will be a help to others, getting it down someplace is as much an act of self-interest as it is altruism.&lt;/p&gt;

&lt;!-- more --&gt;


&lt;p&gt;In the end, the &lt;a href="http://xdebug.org/docs/remote"&gt;XDebug remote debugging docs&lt;/a&gt; really did say it all, but it took some time to wrap my head around it all.&lt;/p&gt;

&lt;h2&gt;TL:DR&lt;/h2&gt;

&lt;p&gt;Just dropping the results here for quick reference. At a later date, I hope to fill out with a discussion of what I think is going on and why it works.&lt;/p&gt;

&lt;p&gt;IP of my Host (as it appears to Guest): 10.0.2.2&lt;/p&gt;

&lt;p&gt;Port-forwarding: 4003 on Host mapped to 80 on Guest&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In XDebug config on Guest:&lt;/strong&gt;&lt;/p&gt;

&lt;pre class="brush: plain"&gt;xdebug.remote_enable  = 1
xdebug.remote_host    = 10.0.2.2
xdebug.remote_port    = 9000
xdebug.remote_handler = dbgp
xdebug.remote_mode    = req
&lt;/pre&gt;


&lt;p&gt;&lt;strong&gt;In Netbeans (on Host):&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Under &lt;code&gt;Tools &amp;gt; Options &amp;gt; PHP &amp;gt; Debugging&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Debugger Port:&lt;/strong&gt; 9000&lt;br/&gt;
&lt;strong&gt;Session ID:&lt;/strong&gt; netbeans-xdebug&lt;/p&gt;

&lt;p&gt;Under &lt;code&gt;Project Properties &amp;gt; Run Configuration&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Run as:&lt;/strong&gt; Local Web Site (running on local web server)&lt;br/&gt;
&lt;strong&gt;Project URL:&lt;/strong&gt; &lt;a href="http://localhost:4003/"&gt;http://localhost:4003/&lt;/a&gt;
&lt;strong&gt;Index file:&lt;/strong&gt; public/index.php&lt;/p&gt;

&lt;p&gt;Note that the &amp;#8220;Index file&amp;#8221; value it wants is an actual file path relative to project root, *not* a URL *relative to vhost doc-root. If Netbeans can&amp;#8217;t find the file, it will continually prompt you, making you want to toss the whole thing off a high building. Well, YMMV.&lt;/p&gt;

&lt;p&gt;Under &lt;code&gt;Project Properties &amp;gt; Run Configuration &amp;gt; Advanced&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Debug URL:&lt;/strong&gt; Do Not Open Web Browser&lt;br/&gt;
&lt;strong&gt;Path Mapping&lt;/strong&gt;:&lt;br/&gt;
&lt;strong&gt;Server Path:&lt;/strong&gt; /vagrant/ (path to project in Guest)&lt;br/&gt;
&lt;strong&gt;Project Path:&lt;/strong&gt; /path/to/project/in/host/&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Then to debug:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In Netbeans (on Host):&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;Debug &amp;gt; Debug Project &amp;lt;my-project&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Set a breakpoint&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;To trigger debugging for an HTTP request (from Host)&lt;/p&gt;

&lt;pre class="brush: plain"&gt;http://localhost:4003/desired/app/url?XDEBUG_SESSION_START=netbeans-xdebug

&lt;/pre&gt;


&lt;p&gt;To trigger debugging for an HTTP request (from Guest)&lt;/p&gt;

&lt;pre class="brush: plain"&gt;http://localhost:80/desired/app/url?XDEBUG_SESSION_START=netbeans-xdebug

&lt;/pre&gt;


&lt;p&gt;To trigger debugging for a command-line operation (from Guest):&lt;/p&gt;

&lt;pre class="brush: plain"&gt;$ export XDEBUG_CONFIG="idekey=netbeans-xdebug"
$ my-command-line-operation
&lt;/pre&gt;


&lt;p&gt;Aaaah, got my debugger back.&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/papayasoft/~4/xCp3ku_8i1Y" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.papayasoft.com/2013/02/25/debugging-vagrant-virtualbox-vm-netbeans/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Accessing Zend Framework application resources and config options in module bootstraps]]></title>
    <link href="http://feedproxy.google.com/~r/papayasoft/~3/Wb5GN0se66g/" />
    <updated>2012-04-30T00:00:00+07:00</updated>
    <id>http://www.papayasoft.com/2012/04/30/accessing-zend-framework-application-resources-module-bootstraps</id>
    <content type="html">&lt;p&gt;A quick post to document something I tripped over today. As usual, mostly for my own benefit since there is a decent chance that I&amp;#8217;ll completely forget it the next time I need it.&lt;/p&gt;

&lt;p&gt;I had a Zend Framework 1.11 app using &lt;code&gt;Zend_Application&lt;/code&gt; and its bootstrap process. The application had several modules. So, in &lt;code&gt;application/configs/application.ini&lt;/code&gt;:&lt;/p&gt;

&lt;pre class="brush:text"&gt;resources.modules.front = "front"
resources.modules.auth  = "auth"
resources.modules.admin = "admin"
&lt;/pre&gt;


&lt;p&gt;And each module bootstrap class extended &lt;code&gt;Zend_Application_Module_Bootstrap&lt;/code&gt;. For example, the bootstrap class for the module named &amp;#8220;front&amp;#8221; looked like:&lt;/p&gt;

&lt;pre class="brush:php"&gt;class Front_Bootstrap extends Zend_Application_Module_Bootstrap
{
    protected function _initSomething()
    {
        // init something
    }
}
&lt;/pre&gt;


&lt;p&gt;And there were some app-level application resources &amp;#8211; like cachemanager, for example &amp;#8211; that were defined in the usual way:&lt;/p&gt;

&lt;pre class="brush:plain"&gt;resources.cachemanager.feed.frontend.name = Core
resources.cachemanager.feed.frontend.options.lifetime = 21600
resources.cachemanager.feed.frontend.options.automatic_serialization = true
resources.cachemanager.feed.backend.name = File
resources.cachemanager.feed.backend.options.cache_dir = APPLICATION_PATH "/../data/cache"
&lt;/pre&gt;


&lt;p&gt;All straightforward and working fine, as it has on many previous occasions.&lt;/p&gt;

&lt;p&gt;In my module bootstraps, I was registering some front-controller plugins that needed to access those bootstrapped application resources and config data (the cachemanager resource and a feed url, respectively) that were all specified at app-level. So, I tried to access them in the module-level bootstrap using:&lt;/p&gt;

&lt;pre class="brush:php"&gt;class Front_Bootstrap extends Zend_Application_Module_Bootstrap
{
    protected function _initSomething()
    {
        // get some options, used later
        $options = $this-&gt;getOptions();

        // use built-in dependency tracking
        $this-&gt;bootstrap('cachemanager');

        // get the bootstrapped resource
        $cachemanager = $this-&gt;getResource('cachemanager');

        // do more, with the options and the cachemanager
    }
}
&lt;/pre&gt;


&lt;p&gt;Result: The variable &lt;code&gt;$options&lt;/code&gt; was merely an empty array and the app would die when trying to access the cachemanager resource.&lt;/p&gt;

&lt;p&gt;Apparently since we configured/instantiated all these at the app-level (!), I need to access them through the app-level (!) bootstrap which I can get using &lt;code&gt;$this-&amp;gt;getApplication()&lt;/code&gt;. So the correct code is:&lt;/p&gt;

&lt;pre class="brush:php"&gt;class Front_Bootstrap extends Zend_Application_Module_Bootstrap
{
    protected function _initSomething()
    {
         // get the application-level bootstrap first
         $application = $this-&gt;getApplication();

        // get some options, used later
        $options = $application-&gt;getOptions();

        // use built-in dependency management
        $application-&gt;bootstrap('cachemanager');

        // get the bootstrapped resource
        $cachemanager = $application-&gt;getResource('cachemanager');

        // do more, with the options and the cachemanager
    }
}
&lt;/pre&gt;


&lt;p&gt;In hindsight, and with all the explicit references I have made to the adjective &amp;#8216;app-level&amp;#8221;, it&amp;#8217;s all pretty obvious. I will note that &lt;code&gt;getApplication()&lt;/code&gt; does not return the &lt;code&gt;Zend_Application&lt;/code&gt; instance (as the name kind-of implies), but rather the app-level &lt;em&gt;bootstrap&lt;/em&gt;. As potentially misleading as the method name may be, I suppose it makes sense since the app-level bootstrap instance is usually more directly useful than the application instance.&lt;/p&gt;

&lt;p&gt;With any luck, I&amp;#8217;ll remember it next time. Until then, hope this helps someone else.&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/papayasoft/~4/Wb5GN0se66g" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.papayasoft.com/2012/04/30/accessing-zend-framework-application-resources-module-bootstraps/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Zend Framework 2: Concepts, Flexibility, Complexity]]></title>
    <link href="http://feedproxy.google.com/~r/papayasoft/~3/Eo7uBsYO8MM/" />
    <updated>2012-04-17T00:00:00+07:00</updated>
    <id>http://www.papayasoft.com/2012/04/17/zend-framework-2-concepts-flexibility-complexity</id>
    <content type="html">&lt;p&gt;As I try to get my own head around the ongoing development of &lt;a href="http://framework.zend.com/zf2" title="Zend Framework 2 (ZF2)"&gt;Zend Framework 2 (ZF2)&lt;/a&gt; and as I see other beginner/intermediate developers &lt;a href="http://stackoverflow.com/q/10182000/131824"&gt;ask similar questions&lt;/a&gt;, I thought it would be useful &amp;#8211; to me at least &amp;#8211; to articulate some thoughts about how I understand ZF2 and some general concepts that could be helpful to understanding the framework. Hopefully, they will be helpful for newbies (and a few not-so-newbies) as well.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;tl;dr:&lt;/strong&gt; There is a lot of complexity in ZF2 that enables maximum flexibiltiy. I suspect that at some point in the future, much of this complexity can be wrapped in an easy-consumption layer that masks it for those common use-cases that do not require that flexibility.&lt;/p&gt;

&lt;!-- more --&gt;


&lt;p&gt;Generally, I see the following as some of the core ZF2 ideas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MVC and dispatch cycle&lt;/li&gt;
&lt;li&gt;Dependency Injection (DI)&lt;/li&gt;
&lt;li&gt;Events&lt;/li&gt;
&lt;li&gt;Modules as first-class citizens&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;MVC and the dispatch cycle&lt;/h2&gt;

&lt;p&gt;To use ZF2 as more than a component library &amp;#8211; which is a perfectly valid use case &amp;#8211; it is necessary to understand the general notion of MVC and the request dispatch cycle. An HTTP request comes to the web-server; internal objects representing a router, the request, the response, a dispatcher are created; the request is routed to a module/controller/action; data is populated into views which then populate the response; the response is then sent back to the client. Gotta know your MVC.&lt;/p&gt;

&lt;h2&gt;Dependency Injection (DI)&lt;/h2&gt;

&lt;p&gt;There are many resources on dependency injection &amp;#8211; including a &lt;a href="http://www.papayasoft.com/2011/06/26/dependency-injection/" title="What is dependency injection?"&gt;previous blog post&lt;/a&gt; &amp;#8211; but the upshot is that if an object (the consumer) needs another object (the dependency) to do its job, then it is more flexible to pass the dependency to the consumer, rather than have the consumer instantiate it itself. This decoupling eases unit testing of the consumer, allowing you to provide a mock dependency that you know functions as expected.&lt;/p&gt;

&lt;p&gt;ZF2 has a DI component that is used heavily in the framework code and in many of the current sample apps.&lt;/p&gt;

&lt;h2&gt;Events&lt;/h2&gt;

&lt;p&gt;Events and Aspect Oriented Programing provide a flexible way to hook external/cross-cutting processing into a line of execution flow. As a request is processed, various events can be broadcast to listeners that perform some processing.&lt;/p&gt;

&lt;p&gt;Examples usually cited are logging and caching. Any object that needs to do logging and caching would need to compose objects for that functionality. Since this can result in boilerplate code being repeated all over the place, or in extended class inheritance trees as we attempt to put all this into a base class. An alternative is to simply compose a single &amp;#8220;event manager&amp;#8221; that knows how to route events and event-specific information to those listeners, who then take action.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://packages.zendframework.com/docs/latest/manual/en/zend.event-manager.html"&gt;ZF2&amp;#8242;s EventManager&lt;/a&gt; is also used in the dispatch cycle to expose various stages in that cycle to other components that wish to act at that point.&lt;/p&gt;

&lt;p&gt;Much of what you see in the current batch of ZF2 sample apps involves specifying listeners to these events.&lt;/p&gt;

&lt;h2&gt;Modules as first-class citizens&lt;/h2&gt;

&lt;p&gt;Although ZF1 had a notion of modules, they did not act as &amp;#8220;drop-in&amp;#8221; buckets/bundles of functionality. ZF2 raises the profile of modules so that they can more easily contain their own autoloading, config, routes, views, public web assets, etc. Further, module-specific config can be overriden at the application-level, something which is necessary to make a module truly flexible enough to drop-in, configure, and use.&lt;/p&gt;

&lt;h2&gt;Summary&lt;/h2&gt;

&lt;p&gt;Much of the complexity that is currently exposed in ZF2 is intended to make app development more flexible. I suspect that as time goes on &amp;#8211; hopefully even before the actual post-beta release &amp;#8211; much of this complexity will be wrappable in an easy set of simple-use-case consumer containers that mask the complexity if you don&amp;#8217;t require all the flexibility.&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/papayasoft/~4/Eo7uBsYO8MM" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.papayasoft.com/2012/04/17/zend-framework-2-concepts-flexibility-complexity/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Custom frontends for Zend_Cache]]></title>
    <link href="http://feedproxy.google.com/~r/papayasoft/~3/gGDS2UF9TNY/" />
    <updated>2011-12-10T00:00:00+07:00</updated>
    <id>http://www.papayasoft.com/2011/12/10/custom-frontends-zend-cache</id>
    <content type="html">&lt;p&gt;As we all know, server-side caching is a useful technique for optimizing the performance of web apps. Whenever some expensive operation is called for &amp;#8211; a db query, a remote web service call, etc &amp;#8211; caching the results of the operation means that the next time you need them, you can get them relatively cheaply from the cache.&lt;/p&gt;

&lt;h3&gt;Zend_Cache: A basic usage example&lt;/h3&gt;

&lt;p&gt;Zend Framework contains a &lt;code&gt;Zend_Cache&lt;/code&gt; component that supports a variety of frontends and backends. Typical usage for filesystem-based caching is something like the following:&lt;/p&gt;

&lt;pre class="brush:php"&gt;// create the cache object
$frontend = array(
    'lifetime' =&gt; 86400, // seconds
    'automatic_serialization' =&gt; true,
);
$backend = array(
    'cache_dir' =&gt; '/path/to/your/cache',
);
$cache = Zend_Cache::factory('Core', 'File', $frontend, $backend);

// now use the cache object
$cacheId = 'someCacheId';
$data = $cache-&gt;load($cacheId);
if (false == $data){
    $data = someExpensiveOperation();
    $cache-&gt;save($data, $cacheId);
}
&lt;/pre&gt;


&lt;p&gt;In practice, I tend to put the cache creation portion into a factory/container class of some kind, while the usage/consumption is often in a repository or service class. But for clarity, it is shown all in line, as if it were in a controller.&lt;/p&gt;

&lt;p&gt;The first time you run through this code, the data will not have been saved in cache (a cache miss, as they say), so you will be forced to incur the cost of the &lt;code&gt;someExpensiveOperation()&lt;/code&gt; call. But the next time you run through it &amp;#8211; assuming the cache has not expired beyond its lifetime &amp;#8211; then you will register a cache hit and bypass the expensive operation.&lt;/p&gt;

&lt;p&gt;All cool.&lt;/p&gt;

&lt;h3&gt;Yeah, but&amp;#8230;&lt;/h3&gt;

&lt;p&gt;But there is one thing that has always bugged me about this typical flow: generating the &lt;code&gt;$cacheId&lt;/code&gt;. For example, if &lt;code&gt;someExpensiveOperation()&lt;/code&gt; is a db call to fetch an article, then the &lt;code&gt;$cacheId&lt;/code&gt; will probably employ the id or slug of the article:&lt;/p&gt;

&lt;pre class="brush:php"&gt;// $slug is the slug of the article, something like 'my-cool-article'
$cacheId = 'article_byslug_' . str_replace('-', '_', $slug);  // Zend_Cache does not like cache id's with hyphens
&lt;/pre&gt;


&lt;p&gt;Generating a cache id strikes me as part of the internal details of the &amp;#8220;caching process&amp;#8221;. As such, it seems to me like the knowledge of how to do that should be embedded inside the caching object itself. It&amp;#8217;s his business to know how to load data from cache, save data to cache, and remove data from cache. Connecting an id to that data should be part of his job. So, why should I have to construct cache id&amp;#8217;s for him?&lt;/p&gt;

&lt;p&gt;Even further, why am I seeing cache id&amp;#8217;s at all? Couldn&amp;#8217;t the cache object simply offer me an interface with methods like:&lt;/p&gt;

&lt;pre class="brush:php"&gt;public function loadArticlebySlug($slug);
public function saveArticle($article);
public function removeArticleBySlug($slug);

&lt;/pre&gt;


&lt;p&gt;Isn&amp;#8217;t there some easy way to make this happen?&lt;/p&gt;

&lt;h3&gt;Custom cache frontends to the rescue!&lt;/h3&gt;

&lt;p&gt;It turns out that &lt;code&gt;Zend_Cache::factory()&lt;/code&gt; actually does allow me to create custom frontends that implement whatever interface I want. I can define my interface:&lt;/p&gt;

&lt;pre class="brush:php"&gt;interface Project_Cache_Frontend_ArticleInterface
{
    public function loadArticlebySlug($slug);
    public function saveArticle($article);
    public function removeArticleBySlug($slug);
}
&lt;/pre&gt;


&lt;p&gt;Then implement in a class extending &lt;code&gt;Zend_Cache_Core&lt;/code&gt;:&lt;/p&gt;

&lt;pre class="brush:php"&gt;class Project_Cache_Frontend_Article extends Zend_Cache_Core implements Project_Cache_Frontend_ArticleInterface
{
    public function loadArticleBySlug($slug)
    {
        return $this-&gt;load($this-&gt;getCacheIdBySlug($slug));
    }
    
    public function saveArticle($article)
    {
        return $this-&gt;save($article, $this-&gt;getCacheIdBySlug($article-&gt;slug));
    }
    
    public function removeArticleBySlug($slug)
    {
        return $this-&gt;remove($this-&gt;getCacheIdBySlug($slug));
    }
    
    protected function getCacheIdBySlug($slug)
    {
        return 'article_byslug_' . str_replace('-', '_', $slug);
    }
}
&lt;/pre&gt;


&lt;p&gt;Note the protected method &lt;code&gt;getCacheIdBySlug($slug)&lt;/code&gt;. All the knowledge of how to create cache id&amp;#8217;s is wrapped up in the cache object. It just exposes a functional interface that describes &lt;em&gt;what&lt;/em&gt; you want to do, not &lt;em&gt;how&lt;/em&gt; you want it done.&lt;/p&gt;

&lt;p&gt;Now, tell the &lt;code&gt;Zend_Cache::factory()&lt;/code&gt; method to use my custom frontend:&lt;/p&gt;

&lt;pre class="brush:php"&gt;// frontend and backend options as before
$frontend = array(
    'lifetime' =&gt; 86400, // seconds
    'automatic_serialization' =&gt; true,
);
$backend = array(
    'cache_dir' =&gt; '/path/to/your/cache',
);
$cache = Zend_Cache::factory('Project_Cache_Frontend_Article', 'File', $frontend, $backend, true, false, true);
&lt;/pre&gt;


&lt;p&gt;Note that we are specifying the complete name of our implementing cache class, as well as three boolean values.&lt;/p&gt;

&lt;p&gt;The first boolean value &amp;#8211; &lt;code&gt;true&lt;/code&gt; in this case &amp;#8211; tells the factory that we are using a custom frontend.&lt;/p&gt;

&lt;p&gt;The second boolean value &amp;#8211; &lt;code&gt;false&lt;/code&gt; in this case &amp;#8211; tells the factory that we are not using a custom backend.&lt;/p&gt;

&lt;p&gt;The third boolean value &amp;#8211; &lt;code&gt;true&lt;/code&gt; in this case &amp;#8211; tells the factory to use autoloading to instantiate the frontend and backend objects.&lt;/p&gt;

&lt;p&gt;Fully constructed by the factory with the custom frontend, cache usage is cleaner:&lt;/p&gt;

&lt;pre class="brush:php"&gt;$article = $cache-&gt;loadArticleBySlug($slug);
if (false === $article){
    $article = someExpensiveOperationToGetArticleBySlug($slug);
    $cache-&gt;saveArticle($article);
}
&lt;/pre&gt;


&lt;p&gt;No cache id&amp;#8217;s, no mixing of concerns.&lt;/p&gt;

&lt;p&gt;Maybe it&amp;#8217;s a whole lot of work just to tuck away some cache id generation. But I confess that it feels better to me.&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/papayasoft/~4/gGDS2UF9TNY" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.papayasoft.com/2011/12/10/custom-frontends-zend-cache/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[The PHP Community. My Community.]]></title>
    <link href="http://feedproxy.google.com/~r/papayasoft/~3/z0MdUBchfcw/" />
    <updated>2011-09-09T00:00:00+07:00</updated>
    <id>http://www.papayasoft.com/2011/09/09/php-community</id>
    <content type="html">&lt;p&gt;I am a PHP developer. I use PHP for nearly all my server-side development. Much of my learning of design patterns and general best practices and has taken place within a PHP context.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;ve been doing web development with PHP for a lot of years. During the past three years, I have plunged into new tools and methodologies &amp;#8211; frameworks, MVC, source-control, modeling, layered app architecture, dependency-injection, unit-testing, automated build/deploy, schema migration, API design. It has been &amp;#8211; and continues to be &amp;#8211; a huge climb. I often feel like a n00b, the new kid in school who just moved from a foreign land and doesn&amp;#8217;t even speak the language, braced to get teased in the playground during recess by the Cool Kids.&lt;/p&gt;

&lt;p&gt;But you know what? The Cool Kids &amp;#8211; the more experienced PHP developers &amp;#8211; turned out to be, well, cool.&lt;/p&gt;

&lt;p&gt;Whether it&amp;#8217;s an independent developer based on the other side of the world starting his own project on Github, or the founder of a US-based local PHP user group, or an advisory member to several developer conferences, or even the project leads of various popular open-source projects, they have all been uniformly supportive of what I do know and amazingly tolerant of what I don&amp;#8217;t know. These near-total strangers have invited me to local meetups, encouraged me to start my own user-groups and local meetups, have patiently and generously contributed their time to answering my &amp;#8211; often naive &amp;#8211; questions and pointing me to relevant resources.&lt;/p&gt;

&lt;p&gt;The expertise that they have shared with me has proven invaluable in improving my skills. Even more notable is their warm humanity, their sharp-witted good humor, and their almost universal encouragement that moves me to ever deeper community engagement.&lt;/p&gt;

&lt;p&gt;Upshot: This virtual community, this real community, the PHP community, rocks. It just flat out rocks.&lt;/p&gt;

&lt;p&gt;The PHP community. My community.&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/papayasoft/~4/z0MdUBchfcw" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.papayasoft.com/2011/09/09/php-community/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[What is dependency injection?]]></title>
    <link href="http://feedproxy.google.com/~r/papayasoft/~3/MLtgSnwjuCM/" />
    <updated>2011-06-26T00:00:00+07:00</updated>
    <id>http://www.papayasoft.com/2011/06/26/dependency-injection</id>
    <content type="html">&lt;p&gt;For quite some time, I have been working on getting my head around best practices for structuring my web applications. One of the strongest messages that has come through is to use dependency injection to facilitate unit testing.&lt;/p&gt;

&lt;p&gt;As many others have noted, dependency injection is a very simple concept. If one thing (the &amp;#8220;consumer&amp;#8221;) depends upon something else (the &amp;#8220;dependency&amp;#8221;) to do its work, then the consumer should be given the dependency. The consumer should depend upon an agreed set of functionality that the dependency performs, but it should not care how the dependency actually gets the job done.&lt;/p&gt;

&lt;h3&gt;An easy example&lt;/h3&gt;

&lt;p&gt;A radio receives transmissions and plays sounds through its speakers. Nothing special there. But it needs a power source to function. The power source&amp;#8217;s adapter has to fit into the hole on back of the radio. And there has to be some compatibility of voltages and currents and all that electrical magic. The radio is the consumer and the power source is the dependency. You can&amp;#8217;t run the radio without the power source.&lt;/p&gt;

&lt;p&gt;Note that, in principle, the power source could be a pack of AA batteries. Or it could be a solar cell. Or it could be a collection of gerbils running on flywheels. As long as it outputs the right voltage and current and the plug fits into the hole, then all is cool. The radio is not concerned by the power source implementation as long it lives up to what we expect a power source to do (i.e., its interface).&lt;/p&gt;

&lt;h3&gt;How about some code?&lt;/h3&gt;

&lt;p&gt;Using our radio and power source example, we could imagine PHP objects and interfaces as follows:&lt;/p&gt;

&lt;pre class="brush: php"&gt;interface PowerSourceInterface 
{   
    public function getPower($numberOfPowerUnits);
}

class PowerSourceGerbils implements PowerSourceInterface
{
    protected $_gerbils;
    
    public function __construct($gerbils)
    {
        $this-&gt;_gerbils = $gerbils;
    }
    
    pubic function getPower($numberOfPowerUnits)
    {
        // Make the gerbils run like hell on the flywheel
        // to generate the requested amount of power.
    }
}

class Radio 
{
    protected $_powerSource;
    
    public function __construct(PowerSourceInterface $powerSource)
    {
        $this-&gt;_powerSource = $powerSource;
    }
    
    public function play()
    {
        // Call upon $this-&gt;_powerSource-&gt;getPower()
        // Feed that power into the various electrical 
        // components of the radio and push the sound
        // out through the speakers.
    }
}

&lt;/pre&gt;


&lt;p&gt;The idea is that by clearly defining the responsibilities, we can create independent object that fulfill those responsibilities. Even better, by defining interfaces, we can set up a contract for what a particular consumer expects his dependencies to be able to do for him.&lt;/p&gt;

&lt;h3&gt;So, who cares? Unit testing cares.&lt;/h3&gt;

&lt;p&gt;Suppose you are a company that makes radios. You hire the best radio engineers and work out all the details for what makes a radio great. Maybe you have amazing noise-reduction algorithms that filter out static. Maybe your radios have balance and equalizer controls to allow the user to tweak the sound he gets out of your box. Maybe your radios are super efficient so that they pull less power from the power source, allowing them to play longer before recharge. Or maybe you simply put them in colorful plastic shells featuring photos of some random pop star.&lt;/p&gt;

&lt;p&gt;The point is that your expertise is in the areas highlighted above. You make no representation to be experts in power generation; you are a power &lt;em&gt;consumer&lt;/em&gt;. The quality of &lt;em&gt;your&lt;/em&gt; work can only be fairly judged when the power source functions properly. Hey, man, if the power source tanks, then all bets are off, right?&lt;/p&gt;

&lt;p&gt;So as part of your manufacturing process, you do a whole bunch of unit-testing on your radios using a &amp;#8220;mock&amp;#8221; power source, a power source that definitely functions correctly. This approach &amp;#8211; explicitly defining and passing dependencies, combined with supplying mock dependencies during unit testing &amp;#8211; clearly defines responsibilities and allows you to focus on fulfilling yours without worrying that the problem lies in someone else&amp;#8217;s area of responsibility.&lt;/p&gt;

&lt;h3&gt;What&amp;#8217;s the downside?&lt;/h3&gt;

&lt;p&gt;Well, creating objects is now a bit of a pain the neck. Consider what is required now just to play a radio.&lt;/p&gt;

&lt;pre class="brush: php"&gt;$gerbils = new GerbilCollection();  // guess we need a Gerbil class and a GerbilCollection class, too
$powerSource = new PowerSourceGerbils($gerbils);
$radio = new Radio($powerSource);
$radio-&gt;play();
&lt;/pre&gt;


&lt;p&gt;So, every time I want to play a radio, I need to construct a power source (which might have its own dependencies, like the gerbils in this case), feed that power source into the radio, and then hit the play button.&lt;/p&gt;

&lt;p&gt;I gotta do all these steps just to play a freaking radio? Can&amp;#8217;t I do the radio setup once &amp;#8211; create and plug in the power source &amp;#8211; and then when I want to listen to some music, all I have to do is hit play?&lt;/p&gt;

&lt;p&gt;I will address this in the next post: Poor Man&amp;#8217;s Dependency Injection using Zend Framework.&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/papayasoft/~4/MLtgSnwjuCM" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.papayasoft.com/2011/06/26/dependency-injection/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Unit testing for placeholder-based view-helpers in Zend Framework]]></title>
    <link href="http://feedproxy.google.com/~r/papayasoft/~3/vL1jxNPDs4I/" />
    <updated>2011-03-12T00:00:00+07:00</updated>
    <id>http://www.papayasoft.com/2011/03/12/unit-testing-zend-framework-placeholder-view-helpers</id>
    <content type="html">&lt;p&gt;Just got bitten by an interesting little issue.&lt;/p&gt;

&lt;p&gt;I have a &lt;a href="http://framework.zend.com/"&gt;Zend Framework&lt;/a&gt; view-helper that I use to add a CSS class to an HTML &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; tag. Usage in a view-script is:&lt;/p&gt;

&lt;pre class="brush:php"&gt;$this-&gt;bodyTag()-&gt;addClass('someclass');
&lt;/pre&gt;


&lt;p&gt;Then in a layout, I&amp;#8217;d output it using:&lt;/p&gt;

&lt;pre class="brush:php"&gt;&amp;lt;?= $this-&gt;bodyTag() ?&amp;gt;
&lt;/pre&gt;


&lt;p&gt;The class itself is very simple:&lt;/p&gt;

&lt;pre class="brush:php"&gt;/**
 * A body tag
 *
 * @author David Weinraub &amp;lt;david@papayasoft.com&amp;gt;
 */
class PapayaSoft_Zend_View_Helper_BodyTag extends Zend_View_Helper_Placeholder_Container_Standalone
{
    public function bodyTag()
    {
        return $this;
    }

    public function toString()
    {
        $tag = array();
        $tag[] = '&amp;lt;body';

        $storage = $this-&gt;getContainer();

        if (count($storage) &gt; 0){
            $classes = array();
            foreach ($storage as $class){
                $classes[] = $class;
            }
            $tag[] = sprintf(' class="%s"', implode(' ', $classes));
        }
        $tag[] = '&amp;gt;';
        return implode('', $tag);
    }

    public function addClass($class)
    {
        $this-&gt;getContainer()-&gt;append($class);
        return $this;
    }
}

&lt;/pre&gt;


&lt;p&gt;I&amp;#8217;ve begun moving this kind of stuff out into my own library, which I will manage in its own project under source control. I can then import it into multiple projects, just as I would with the libs for &lt;a href="http://framework.zend.com/"&gt;Zend&lt;/a&gt; or &lt;a href="http://www.doctrine-project.org/"&gt;Doctrine&lt;/a&gt; or &lt;a href="http://htmlpurifier.org/"&gt;HTML Purifier&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Consequently, it&amp;#8217;s now time &amp;#8211; actually long past-due &amp;#8211; to really get into the discipline of unit-testing. A simple class like this seems a decent place to start.&lt;/p&gt;

&lt;p&gt;Unit-tests for the BodyTag class looked something like this:&lt;/p&gt;

&lt;pre class="brush:php"&gt;/**
 * Test BodyTag class
 *
 * @group Zend_View_Helper
 * @author David Weinraub &amp;lt;david@papayasoft.com&amp;gt;
 */
class PapayaSoft_Zend_View_Helper_BodyTagTest extends PHPUnit_Framework_TestCase
{
    /**
     * @var PapayaSoft_Zend_View_Helper_BodyTag
     */
    private $_bodyTag;

    public function setUp()
    {
        $this-&gt;_bodyTag = new PapayaSoft_Zend_View_Helper_BodyTag();
    }

    public function tearDown()
    {
        unset($this-&gt;_bodyTag);
    }

    public function testRenderOnNoAddedClasses()
    {
        $this-&gt;assertEquals('&amp;lt;body&amp;gt;', (string) $this-&gt;_bodyTag);
    }

    public function testRenderOnSingleAddedClass()
    {
        $this-&gt;_bodyTag-&gt;addClass('myclass');
        $this-&gt;assertEquals('&amp;lt;body class="myclass"&amp;gt;', (string) $this-&gt;_bodyTag);
    }
    
    public function testRenderOnMultipleAddedClasses()
    {
        $this-&gt;_bodyTag = new PapayaSoft_Zend_View_Helper_BodyTag();
        $this-&gt;_bodyTag-&gt;addClass('someclass')-&gt;addClass('anotherclass');
        $this-&gt;assertEquals('&amp;lt;body class="someclass anotherclass"&amp;lt;', (string) $this-&gt;_bodyTag);
    }
}

&lt;/pre&gt;


&lt;p&gt;Pretty straightforward. Or so I thought.&lt;/p&gt;

&lt;p&gt;The last test failed, reporting the following:&lt;/p&gt;

&lt;pre class="brush:php"&gt;BodyTagTest::testRenderOnMultipleAddedClasses()
Failed asserting that two strings are equal.
--- Expected
+++ Actual
@@ @@
-&amp;lt;body class="someclass anotherclass"&amp;gt;
+&amp;lt;body class="myclass someclass anotherclass"&amp;gt;
&lt;/pre&gt;




&lt;div style="text-align:left;"&gt;
  It seemed as if result of running the penultimate method &lt;code&gt;testRenderOnSingleAddedClass()&lt;/code&gt; was still in effect when &lt;code&gt;testRenderOnMultipleAddedClasses()&lt;/code&gt; started. When the &lt;code&gt;testRenderOnSingleAddedClass()&lt;/code&gt; method is removed, the &lt;code&gt;testRenderOnMultipleAddedClasses()&lt;/code&gt; passes.
&lt;/div&gt;


&lt;p&gt;What&amp;#8217;s going on here? The whole point of &lt;code&gt;tearDown()&lt;/code&gt; and &lt;code&gt;setUp()&lt;/code&gt; is to reset the test environment to a clean state, in this case by unsetting and re-instantiating the &lt;code&gt;$_bodyTag&lt;/code&gt; member variable.&lt;/p&gt;

&lt;p&gt;Well, the whole key here turns out to be state of the system. It&amp;#8217;s not sufficient to simply reset the object in the member variable if it has made other changes to the state of the system. Sort of like selling the cow that crapped in your living room, but forgetting to clean up the mess he made. And that&amp;#8217;s actually what appears to be happening.&lt;/p&gt;

&lt;p&gt;The framework&amp;#8217;s own unit test for &lt;code&gt;Zend_View_Helper_HeadTitle&lt;/code&gt;, another &lt;code&gt;Zend_View_Helper_Placeholder_Container_Standalone&lt;/code&gt;-extended class, offers some hint of this. The &lt;code&gt;setUp()&lt;/code&gt; method is as follows:&lt;/p&gt;

&lt;pre class="brush:php"&gt;/**
     * Sets up the fixture, for example, open a network connection.
     * This method is called before a test is executed.
     *
     * @return void
     */
    public function setUp()
    {
        $regKey = Zend_View_Helper_Placeholder_Registry::REGISTRY_KEY;
        if (Zend_Registry::isRegistered($regKey)) {
            $registry = Zend_Registry::getInstance();
            unset($registry[$regKey]);
        }
        $this-&gt;basePath = dirname(__FILE__) . '/_files/modules';
        $this-&gt;helper = new Zend_View_Helper_HeadTitle();
    }
&lt;/pre&gt;


&lt;p&gt;So there is some &lt;/code&gt;Zend_Registry&lt;/code&gt; stuff in there that needs to be cleared, as well. Adding the registry-clearing code from the ZF unit-test into my own solved the problem.&lt;/p&gt;

&lt;p&gt;Live and learn.&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/papayasoft/~4/vL1jxNPDs4I" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.papayasoft.com/2011/03/12/unit-testing-zend-framework-placeholder-view-helpers/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[CRISP-y goodness: tracking Phuket internet speeds]]></title>
    <link href="http://feedproxy.google.com/~r/papayasoft/~3/1w71FDeQhQE/" />
    <updated>2010-12-27T00:00:00+07:00</updated>
    <id>http://www.papayasoft.com/2010/12/27/crispy-goodness-2</id>
    <content type="html">&lt;p&gt;I am pleased to report that we have launched the new version of &lt;a href="http://ww.khunwoody.com/phuket-internet-speed/"&gt;CRISP &amp;#8211; Customers Reporting Internet Speeds in Phuket&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For some years, well-known computer columnist and baker &lt;a href="http://twitter.com/phuketpc"&gt;Woody Leonhard&lt;/a&gt; (see AskWoody.com for his opinions on &lt;a href="http://www.askwoody.com/"&gt;Windows patches&lt;/a&gt; or his columns in the &lt;a href="http://windowssecrets.com/search?q=woody"&gt;Windows Secrets Newsletter&lt;/a&gt;, or his various &lt;a href="http://www.amazon.com/s/ref=nb_sb_noss?url=search-alias%3Dstripbooks&amp;amp;#038;field-keywords=windows+dummies+woody&amp;amp;#038;x=0&amp;amp;#038;y=0"&gt;Windows for Dummies books&lt;/a&gt;, not to mention his &lt;a href="http://thephuketbakery.com/"&gt;bakery business&lt;/a&gt; and his &lt;a href="http://www.phuketinternetcafe.com/"&gt;Phuket Sandwich Shoppes&lt;/a&gt;) has led a group of Phuket internet users in running speed tests on their internet connections and storing this data in an app developed and hosted by &lt;a href="http://www.psp-online.com/"&gt;Henry Habermacher&lt;/a&gt;. The data was freely available as a CSV download to anyone who wanted to perform their own analysis on it.&lt;/p&gt;

&lt;p&gt;Woody&amp;#8217;s prime motivations were to provide Phuket internet users with real usage data on which to base their ISP choices and to clearly demonstrate the significant discrepancy between speeds advertised by ISP&amp;#8217;s in Phuket and those that are actually delivered.&lt;/p&gt;

&lt;p&gt;As of this writing, the db has over 15,000 speed reports dating back to 2008.&lt;/p&gt;

&lt;p&gt;Henry was unable to host it going forward, so we needed to move it to a new home. But rather than simply migrate, we decided to do a rewrite in PHP and I got the call. Using a design by &lt;a href="http://tessellations.org/contact.htm"&gt;Seth Bareiss&lt;/a&gt;, my re-implementation is built on &lt;a href="http://framework.zend.com/"&gt;Zend Framework&lt;/a&gt; and the &lt;a href=""http://www.doctrine-project.org/"&gt;Doctrine 1&lt;/a&gt; ORM. Relative to the previous version, it features some enhanced searching and user management, including registration and profile management.&lt;/p&gt;

&lt;p&gt;If you are a Phuket-based internet user, come on over, &lt;a href="http://www.khunwoody.com/phuket-internet-speed/user/register"&gt;register&lt;/a&gt;, and start contributing to the tracking effort.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.khunwoody.com/phuket-internet-speed/"&gt;http://www.khunwoody.com/phuket-internet-speed/&lt;/a&gt;&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/papayasoft/~4/1w71FDeQhQE" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.papayasoft.com/2010/12/27/crispy-goodness-2/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Greeting]]></title>
    <link href="http://feedproxy.google.com/~r/papayasoft/~3/8pJuK3mCiXY/" />
    <updated>2010-12-25T00:00:00+07:00</updated>
    <id>http://www.papayasoft.com/2010/12/25/greeting</id>
    <content type="html">&lt;pre class="brush: php"&gt;$papayasoft-&gt;wishesYou(array(
    new Christmas('merry'),
    new Year(array('happy', 'healthy', 'prosperous')),
));
$this-&gt;assert($papayasoft-&gt;isGeek());

&lt;/pre&gt;

&lt;img src="http://feeds.feedburner.com/~r/papayasoft/~4/8pJuK3mCiXY" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.papayasoft.com/2010/12/25/greeting/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Zend Framework default routing for hyphenated and camelCase URL&#8217;s]]></title>
    <link href="http://feedproxy.google.com/~r/papayasoft/~3/SayaUjChlBU/" />
    <updated>2010-12-22T00:00:00+07:00</updated>
    <id>http://www.papayasoft.com/2010/12/22/zend-framework-routing-hyphen-camelcase</id>
    <content type="html">&lt;p&gt;Using the default routing in Zend Framework (v1.x), I always forget how certain URL patterns map to action and view-script names. So just a quick post, mostly for myself, to record them here.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;URL:&lt;/strong&gt; mycontroller/test-me&lt;br/&gt;
&lt;strong&gt;Controller&lt;/strong&gt;: mycontroller&lt;br/&gt;
&lt;strong&gt;Action:&lt;/strong&gt; testMe&lt;br/&gt;
&lt;strong&gt;Script:&lt;/strong&gt; test-me.phtml&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;URL:&lt;/strong&gt; mycontroller/testMe&lt;br/&gt;
&lt;strong&gt;Controller:&lt;/strong&gt; mycontroller&lt;br/&gt;
&lt;strong&gt;Action:&lt;/strong&gt; testme&lt;br/&gt;
&lt;strong&gt;Script:&lt;/strong&gt; test-me.phtml&lt;/p&gt;

&lt;p&gt;That&amp;#8217;s it!&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/papayasoft/~4/SayaUjChlBU" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.papayasoft.com/2010/12/22/zend-framework-routing-hyphen-camelcase/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Naming conventions for database tables and fields]]></title>
    <link href="http://feedproxy.google.com/~r/papayasoft/~3/aeABNNliB8g/" />
    <updated>2010-12-09T00:00:00+07:00</updated>
    <id>http://www.papayasoft.com/2010/12/09/database-naming-convention</id>
    <content type="html">&lt;p&gt;&lt;a href="http://twitter.com/JeremyKendall"&gt;@JeremyKendall&lt;/a&gt; recently asked a &lt;a href="http://twitter.com/#!/JeremyKendall/status/12619603062554624"&gt;great question&lt;/a&gt; on Twitter:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;Do you have a DB naming convention? camelCase? under_scores? Singular or plural table names? I can never settle on anything.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;He got some great answers. Since I will certainly need to reference these opinions at some later date &amp;#8211; and Twitter will not keep the history forever &amp;#8211; I am recording them here.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://twitter.com/konrness"&gt;@konrness&lt;/a&gt;&lt;br/&gt;
I find it&amp;#8217;s easier to follow my PHP code&amp;#8217;s naming convention, so: camelCase for table names and columns. Under_score for DBs. Oh yeah, I usually do plural table names.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://twitter.com/stuardo_str"&gt;@stuardo_str&lt;/a&gt;&lt;br/&gt;
namespaced_under_scored&lt;/p&gt;

&lt;p&gt;&lt;a href="http://twitter.com/cancehgarcia"&gt;@cancehgarcia&lt;/a&gt;&lt;br/&gt;
i once read that &amp;#8220;best practice&amp;#8221; is singular and underscores. but as long as you&amp;#8217;re consistent in the db, you should be good.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://twitter.com/cryptographite"&gt;@cryptographite&lt;/a&gt;&lt;br/&gt;
CamelCase (ucfirst) for tables, and pre_desc for columns. User.u_id, UserProperties.up_value&amp;#8230; It&amp;#8217;s not perfect but it works&lt;/p&gt;

&lt;p&gt;&lt;a href="http://twitter.com/calevans"&gt;@calevans&lt;/a&gt;&lt;br/&gt;
single table names, camleCase attributes and PK is always id&lt;/p&gt;

&lt;p&gt;&lt;a href="http://twitter.com/maphpia"&gt;@maphpia&lt;/a&gt;&lt;br/&gt;
namespaced_underscore_name, singular, and &amp;#8216;id&amp;#8217; as PK&lt;/p&gt;

&lt;p&gt;&lt;a href="http://twitter.com/guice"&gt;@guice&lt;/a&gt;&lt;br/&gt;
for us; id is always tablename_id to avoid name conflicts between joins. We use underscore (oracle). Singular names.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://twitter.com/akrabat"&gt;@akrabat&lt;/a&gt;&lt;br/&gt;
Plural table names; lowercase, underscore separated field names; PK is always id.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://twitter.com/avalanche123"&gt;@avalanche123&lt;/a&gt;&lt;br/&gt;
lowercase underscore plural table names, id is the PK, &lt;singular table name&gt;_id is the FK to table name&lt;/p&gt;

&lt;p&gt;&lt;a href="http://twitter.com/h"&gt;@h&lt;/a&gt; (which is an awesome Twitter handle)&lt;br/&gt;
Singular Table names, first char upper case. Allows you to create models that match exactly.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://twitter.com/tommygeorge"&gt;@tommygeorge&lt;/a&gt;&lt;br/&gt;
Depends on the project, but I hate camelcase, and if I&amp;#8217;m doing models/objects, I generally do plurals for table names.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://twitter.com/brodrigu"&gt;@brodrigu&lt;/a&gt;&lt;br/&gt;
plural under_scores ftw!&lt;/p&gt;

&lt;p&gt;I actually &lt;a href="http://twitter.com/#!/papayasoft/statuses/12714163465887744"&gt;chimed in&lt;/a&gt; with my own support for @avalanche123&amp;#8242;s suggestion: lowercase underscore plural table names, id is the PK, &lt;singular table name&gt;_id is the FK to table name. Semantically, I find this compelling since you end up with SQL queries of like &amp;#8220;SELECT * FROM users&amp;#8221; which reads better to my eye than &amp;#8220;SELECT * FROM user&amp;#8221;.&lt;/p&gt;

&lt;p&gt;The only downside to this is that dealing with irregular plurals can sometimes be a pain. Consider a table containing properties. As noted above, I prefer the semantics that follow from calling that table &amp;#8220;properties&amp;#8221;. But a convention for a FK into that table &amp;#8220;&amp;lt;singular_table_name&gt;_id&amp;#8221; would yield a field named &amp;#8220;property_id&amp;#8221;. The disconnect between the singular and plural can sometimes be problematic. Sure, there are Inflector classes (&lt;a href="http://www.phpclasses.org/browse/file/12343.html"&gt;like this one&lt;/a&gt;) that know enough about English pluralization rules and their exceptions to do the mapping, but it&amp;#8217;s one more hassle. So there are times when I bite the bullet, abandon the superior semantics, and simply hold my nose and go with singular table names.&lt;/p&gt;

&lt;p&gt;What are your preferences and rationale?&lt;/p&gt;

&lt;p&gt;Cheers!&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/papayasoft/~4/aeABNNliB8g" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.papayasoft.com/2010/12/09/database-naming-convention/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[International Business Association of Phuket (IBAP) &#8211; New features]]></title>
    <link href="http://feedproxy.google.com/~r/papayasoft/~3/Wv4j4LS-R7w/" />
    <updated>2010-10-02T00:00:00+07:00</updated>
    <id>http://www.papayasoft.com/2010/10/02/international-business-association-phuket-ibap-features</id>
    <content type="html">&lt;p&gt;Recently implemented new login and the member-only features for the &lt;a href="http://ibap-phuket.org/"&gt;International Business Association of Phuket (IBAP)&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Check it out: &lt;a href="http://ibap-phuket.org/"&gt;http://ibap-phuket.org/&lt;/a&gt;&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/papayasoft/~4/Wv4j4LS-R7w" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.papayasoft.com/2010/10/02/international-business-association-phuket-ibap-features/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Siam Real Estate &#8211; Redesigned]]></title>
    <link href="http://feedproxy.google.com/~r/papayasoft/~3/NBwGg_0ZYpo/" />
    <updated>2010-08-25T00:00:00+07:00</updated>
    <id>http://www.papayasoft.com/2010/08/25/siam-real-estate-redesigned</id>
    <content type="html">&lt;p&gt;Just completed a redesign for Siam Real Estate, specializing in &lt;a href="http://www.siamrealestate.com/"&gt;Phuket villa rentals&lt;/a&gt; and property sales.&lt;/p&gt;

&lt;p&gt;The graphic design &amp;#8211; including much of the markup and CSS &amp;#8211; was done by &lt;a href="http://www.bluedzine.com/"&gt;Blue D.Zine&lt;/a&gt; here in Phuket.&lt;/p&gt;

&lt;p&gt;Much of the front-end has been redeveloped, including new property-renderers. New features include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Improved site navigation&lt;/li&gt;
&lt;li&gt;Map-based criteria selection for property searching&lt;/li&gt;
&lt;li&gt;Google maps for property locations&lt;/li&gt;
&lt;li&gt;Owner self-add of properties&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Also included are many performance optimizations and code-refactoring, both on the server-side and on the client-side.&lt;/p&gt;

&lt;p&gt;Check out the complete site at: &lt;a href="http://www.siamrealestate.com/"&gt;http://www.siamrealestate.com/&lt;/a&gt;&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/papayasoft/~4/NBwGg_0ZYpo" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.papayasoft.com/2010/08/25/siam-real-estate-redesigned/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Gotcha &#8211; SQL count() query with LIMIT clause]]></title>
    <link href="http://feedproxy.google.com/~r/papayasoft/~3/DSnSIYDZLAo/" />
    <updated>2010-08-17T00:00:00+07:00</updated>
    <id>http://www.papayasoft.com/2010/08/17/gotcha-sql-count-query-limit</id>
    <content type="html">&lt;p&gt;Bumped into an interesting feature today. Well, whether it&amp;#8217;s a feature or a gotcha appears to be in the eye of the beholder. And, I&amp;#8217;ll tell ya, for this particular beholder, it was a gotcha.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;ve got some code that builds a SQL query from a variable set of parameters. Most parameters are involved with building a dynamic WHERE clause. Other parameters are for pagination, setting a LIMIT clause on the query that eventually gets built. Another parameter is whether to make the query a COUNT() query or whether to actually pull rows from the db.&lt;/p&gt;

&lt;p&gt;In the case where I build a COUNT() query, I was carelessly allowing a zero-based LIMIT clause &amp;#8211; something like LIMIT 0,10 &amp;#8211; to be appended to the query. No sweat, I figured, since I really only need the single-row containing the count I am requesting.&lt;/p&gt;

&lt;p&gt;However, it turns out that this LIMIT was actually be applied *before* the COUNT()-ing, not after. So, my COUNT() was completely wrong, often returning 0.&lt;/p&gt;

&lt;p&gt;There&amp;#8217;s an hour of my life &amp;#8211; spent in furious frustration &amp;#8211; that I&amp;#8217;ll never get back.&lt;/p&gt;

&lt;p&gt;Onward!&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/papayasoft/~4/DSnSIYDZLAo" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.papayasoft.com/2010/08/17/gotcha-sql-count-query-limit/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Martin Gardner and me]]></title>
    <link href="http://feedproxy.google.com/~r/papayasoft/~3/YS9K--lPDTU/" />
    <updated>2010-05-28T00:00:00+07:00</updated>
    <id>http://www.papayasoft.com/2010/05/28/martin-gardner</id>
    <content type="html">&lt;p&gt;&lt;img src="http://www.papayasoft.com/wp-content/uploads/2010/05/martin_gardnerjpeg-300x209.jpg" alt="martin_gardnerjpeg" title="martin_gardnerjpeg" width="300" height="209" class="alignleft size-medium wp-image-303" /&gt;&lt;/p&gt;

&lt;p&gt;I just read on &lt;a href="http://www.askwoody.com/2010/martin-gardner-rip/"&gt;AskWoody.com&lt;/a&gt; that Martin Gardner, the longtime author of the &lt;em&gt;Scientific American&lt;/em&gt; column &amp;#8220;Mathematical Games&amp;#8221;, has died at the age of 95.&lt;/p&gt;

&lt;p&gt;I am a bit surprised at how it is affecting me.&lt;/p&gt;

&lt;p&gt;As a kid, I loved his column. I took pride in solving the puzzles. The activity taught me focus and concentration. It taught me problem solving. It taught me to think.&lt;/p&gt;

&lt;p&gt;But most of all, it gave me my first exposure to the notions of logical incompleteness and unequal infinities.&lt;/p&gt;

&lt;p&gt;With the naivety of youth, I believed that the universe was black and white. Statements were either true or false, and essentially all knowledge (using a sufficiently large book) could be expressed in language.&lt;/p&gt;

&lt;p&gt;Further, infinity was infinity. the biggest thing there is. Nothing bigger than that, despite the common schoolyard escalation of taunts:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;&amp;#8220;You have cooties.&amp;#8221;&lt;/p&gt;

&lt;p&gt;&amp;#8220;Well, you have cooties plus one.&amp;#8221;&lt;/p&gt;

&lt;p&gt;&amp;#8220;You have cooties plus two.&amp;#8221;&lt;/p&gt;

&lt;p&gt;&amp;#8220;Oh, yeah? You have cooties times one hundred&amp;#8221;, cleverly upping the stakes by switching from simple addition to the more powerful multiplication.&lt;/p&gt;

&lt;p&gt;&amp;#8220;Well, you have cooties times infinity!&amp;#8221;&lt;/p&gt;

&lt;p&gt;&amp;#8220;Oh yeah? You have cooties times infinity-plus-one.&amp;#8221;&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;&amp;#8230; and so on.&lt;/p&gt;

&lt;p&gt;Still, infinity came to connote &amp;#8211; at least to me &amp;#8211; a sense of maximality, the sum totality of everything, of the universe. Of The Universe.&lt;/p&gt;

&lt;p&gt;Martin Gardner&amp;#8217;s column exposed me to &lt;a href="http://en.wikipedia.org/wiki/G%C3%B6del%27s_incompleteness_theorem"&gt;Gödel&amp;#8217;s Incompleteness Theorem&lt;/a&gt; and &lt;a href="http://www.absoluteastronomy.com/topics/Cantor%27s_theorem"&gt;Cantor&amp;#8217;s Theorem&lt;/a&gt; about cardinalities.&lt;/p&gt;

&lt;p&gt;Gödel&amp;#8217;s Incompleteness Theorem states that no consistent system of axioms whose theorems can be listed by an &amp;#8220;effective procedure&amp;#8221; (essentially, a computer program) is capable of proving all facts about the natural numbers. For any such system, there will always be statements about the natural numbers that are true, but that are unprovable within the system.&lt;/p&gt;

&lt;p&gt;This has profound implications for reductionist attempts &amp;#8211; to which I was inherently attracted in my youth &amp;#8211; to reduce all knowledge to a set of indisputable, logically consistent axioms and deduction mechanisms. Essentially, if you depend upon axiomatic logic and consistency, you are limited in what you can prove. There exist statements that are expressible within the given system, but whose truth or falsity are not provable using only the tools of the system.&lt;/p&gt;

&lt;p&gt;This result undermines language as the sole medium of defining knowledge, since language will always produce statements that are outside the reach of provable truth or falsity. It casts doubt on the binary notion of truth, opening up the mathematical discipline of fuzzy logic.&lt;/p&gt;

&lt;p&gt;It even strikes closer to home for me, contradicting something my father explicitly told me when I was a child, one of his core beliefs: &amp;#8220;If you can&amp;#8217;t describe what you know, then you do not know it.&amp;#8221;&lt;/p&gt;

&lt;p&gt;&lt;img src="http://www.papayasoft.com/wp-content/uploads/2010/05/429px-diagonal_argument_2svg-300x297.png" alt="429px-diagonal_argument_2svg" title="429px-diagonal_argument_2svg" width="300" height="297" class="alignright size-medium wp-image-292" /&gt;&lt;/p&gt;

&lt;p&gt;Gödel&amp;#8217;s method of proof was his famous Diagonal Lemma, in which he starts with the logical system, its symbols and its constructs, and then proceeds to build an example of his elusive unprovable statement.&lt;/p&gt;

&lt;p&gt;Using a similar diagonalization technique, Georg Cantor was able to demonstrate that the infinity that represents the natural numbers (1, 2, 3, 4&amp;#8230;) was a &amp;#8220;lesser&amp;#8221; infinity than the infinity representing the real numbers (the numbers that represent measurable distances on a line), the former being a &amp;#8220;countable&amp;#8221; infinity and the latter an &amp;#8220;uncountable&amp;#8221; one. Further, he proved that there are ever-higher, unlimited levels of &amp;#8220;greater&amp;#8221; infinities, all of which are &amp;#8220;uncountable&amp;#8221;.&lt;/p&gt;

&lt;p&gt;All this just blew me away. It fired my imagination. It opened my mind to an extraordinary universe, to universes, to multiverses. It inspired me to embrace the beauty of abstraction. It led me to study mathematics, first as an undergraduate, then as a graduate student, through to my doctorate degree.&lt;/p&gt;

&lt;p&gt;Abstraction, modeling, language, truth, philosophy, knowledge, infinities, alternate possibilities, universes.&lt;/p&gt;

&lt;p&gt;For me, it all started with Martin Gardner. My life would not be the same without the contribution that he made to it. I&amp;#8217;m saddened at the news of his passing, but grateful for the door he opened for me.&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/papayasoft/~4/YS9K--lPDTU" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.papayasoft.com/2010/05/28/martin-gardner/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[What to do about ZodiacFacts and #zf on Twitter?]]></title>
    <link href="http://feedproxy.google.com/~r/papayasoft/~3/tU_TB5k4TTw/" />
    <updated>2010-05-09T00:00:00+07:00</updated>
    <id>http://www.papayasoft.com/2010/05/09/zodiacfacts-zf-twitter-bot</id>
    <content type="html">&lt;p&gt;The Twitter hashtag &lt;a href="http://twitter.com/#search?q=%23zf"&gt;#zf&lt;/a&gt; has been used by the Zend Framework for several years now. The Twitter user &lt;a href="http://twitter.com/ZodiacFacts/"&gt;@ZodiacFacts&lt;/a&gt; began using it some time ago, polluting the #zf stream with all that medieval nonsense. Zend Framework Project Lead &lt;a href="http://twitter.com/weierophinney"&gt;Matthew Weier O&amp;#8217;Phinney&lt;/a&gt; tweeted a reply to @ZodiacFacts politely requesting that he/she refrain from using the hashtag and @ZodiacFacts seems to have politely complied.&lt;/p&gt;

&lt;h3&gt;So, what&amp;#8217;s the problem?&lt;/h3&gt;

&lt;p&gt;As of this writing, @ZodiacFacts has over 170,000 followers &amp;#8211; a lamentable indictment on the state of human rationality. It is no surprise that some of them continue to retweet into the #zf stream.&lt;/p&gt;

&lt;p&gt;There are not many of them, only a few each day. So, it&amp;#8217;s only a minor annoyance. Still, life is filled with enough of minor annoyances that it&amp;#8217;s desirable to remove/minimize them when we can.&lt;/p&gt;

&lt;h3&gt;The solution, perhaps&lt;/h3&gt;

&lt;p&gt;A Twitter Bot could be built that polls Twitter for tweets containing both @ZodiacFacts and #zf and then sends a politely worded reply to the Twitter user requesting that he refrain from using the #zf hashtag.&lt;/p&gt;

&lt;p&gt;I have actually built a class on which such a bot can be based. And I have registered the Twitter account &lt;a href="http://twitter.com/zfisforzend"&gt;@zfisforzend&lt;/a&gt; to function as the sender.&lt;/p&gt;

&lt;p&gt;But since the #zf hashtag should rightly be regarded as a community resource, I don&amp;#8217;t really feel that it is my place to deploy the solution on my own. The &amp;#8220;community&amp;#8221; or even Zend HQ should make the decision about whether to deploy, the phrasing of the message, etc. After all, both of these things affect the public face of the project. Hey, it might even inflame the legions of @ZodiacFact fans to spam the #zf stream, just out of pique.&lt;/p&gt;

&lt;p&gt;So, I am posting my current code so that if one of the project leaders wishes to use it &amp;#8211; or to develop their own, which would no doubt be better than mine &amp;#8211; then they can do so with little effort. I&amp;#8217;d be happy to pass off the ownership of the @zfisforzend Twitter account to whatever community member wants to use it for this purpose.&lt;/p&gt;

&lt;pre class="brush: php"&gt;/**
 * Access Twitter API, do twitter search, then reply
 *
 * @author David Weinraub ( david@papayasoft.com )
 */
class PS_TwitterSearchAndReplyBot
{
    /**
     * @var Zend_Service_Twitter
     */
    protected $_twitter = null;

    /**
     * @var string
     */
    protected $_reply = null;

    /**
     * Path to the file containing the id of the tweet to which we have replied
     *
     * @var string
     */
    protected $_sincePath = null;

    /**
     * @var string
     */
    protected $_userAgent = 'PapayaSoft-SearchAndReplyBot/1.0';

    /**
     * Constructor
     *
     * @param string $username Twitter username for the acct sending replies
     * @param string $password Twitter password for the acct sending replies
     * @param string $query the query we use to find tweets.
     * @param string $reply the text of the reply we wish to send
     * @param string $sincePath path to the file where we save the last replied tweet
     */
    public function __construct($username, $password, $query, $reply, $sincePath)
    {
        if ('' == $username){
            throw new Exception('User is required');
        }

        if ('' == $password){
            throw new Exception('Password is required');
        }

        $this-&gt;_twitter = new Zend_Service_Twitter($username, $password);
        $this-&gt;_twitter-&gt;getHttpClient()-&gt;setHeaders('useragent', $this-&gt;_userAgent);

        if ('' == $query){
            throw new Exception('Query is required');
        }
        $this-&gt;_query = $query;

        if ('' == $reply){
            throw new Exception('Reply is required');
        }
        $this-&gt;_reply = $reply;

        $this-&gt;_sincePath = $sincePath;
    }

    /**
     * Get the matching tweets
     * 
     * @return array the matching tweets
     */
    public function getTweets()
    {
        $service = new Zend_Service_Twitter_Search();
        $service-&gt;getHttpClient()-&gt;setHeaders('useragent', $this-&gt;_userAgent);
        if (null == $sinceId){
            $sinceId = (int) $this-&gt;readSince();
        }
        $params = array(
            'since_id' =&gt; $sinceId,
        );
        return $service-&gt;search($this-&gt;_query, $params);
    }

    /**
     * Send the reply to a matching tweet
     * 
     * @param array $tweet
     * @return void
     */
    public function sendReply($tweet)
    {
        $target = $tweet['from_user'];
        $reply = '@' . $target . ' ' . $this-&gt;_reply;

        $result = $this-&gt;_twitter-&gt;statusUpdate($reply, $tweet['id']);

        if ($result-&gt;isSuccess()){
            $this-&gt;writeSince($tweet['id']);
            return true;
        } else {
            throw new Exception('Failure posting status reply to target');
        }
    }

    /**
     * Save the id of the last tweet to which we have replied
     *
     * @param int $sinceId
     * @return &amp;lt;type&gt;
     */
    public function writeSince($sinceId)
    {
        @$fp = fopen($this-&gt;_sincePath, 'w');

        if (!$fp){
            throw new Exception('Unable to open since-file for writing');
        }
        fwrite($fp, $sinceId);
        fclose($fp);
        return $this;
    }

    /**
     * Get the twitter id of the last tweet to which we have replied
     *
     * @return int
     */
    public function readSince()
    {
        return file_get_contents($this-&gt;_sincePath);
    }

    /**
     * Entry point. Do it all.
     */
    protected function run()
    {
        $tweets = $this-&gt;getTweets();
        foreach ($tweets as $tweet){
            $this-&gt;sendReply($tweet['from_user'], $tweet['id']);
        }
    }
}
&lt;/pre&gt;


&lt;p&gt;Usage would be something along the following:&lt;/p&gt;

&lt;pre class="brush: php"&gt;$bot = new PS_TwitterSearchAndReplyBot(
    'zfisforzend', 
    'thepassword',
    '#zf AND @ZodiacFacts',
    'The ZF hashtag has been used by http://bit.ly/dlRih0 for 2+ years. Please do not use it for ZodiacFacts. Thanks! &lt;img src='http://www.papayasoft.com/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /&gt; ',
    dirname(__FILE__) .'/data/since.dat'
);
$bot-&gt;run();

&lt;/pre&gt;


&lt;p&gt;Then set up a cron job to run this script with some polling frequency.&lt;/p&gt;

&lt;p&gt;Note that the message we send should not contain either of the terms &amp;#8220;#zf&amp;#8221; or &amp;#8220;Zend&amp;#8221; directly. After all, those are search terms we all use in our Twitter clients. The last thing we want is for all these bot-generated replies to further pollute the targeted hashtag stream.&lt;/p&gt;

&lt;p&gt;As you can see, it is general enough to serve as the base for other Twitter Reply bots. I confess that the code is only partially tested, but I think it conveys the idea.&lt;/p&gt;

&lt;p&gt;So, whaddya think?&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/papayasoft/~4/tU_TB5k4TTw" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.papayasoft.com/2010/05/09/zodiacfacts-zf-twitter-bot/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Zend Framework on shared hosting]]></title>
    <link href="http://feedproxy.google.com/~r/papayasoft/~3/t5jFE0bMv34/" />
    <updated>2010-05-08T00:00:00+07:00</updated>
    <id>http://www.papayasoft.com/2010/05/08/zend-framework-shared-hosting</id>
    <content type="html">&lt;p&gt;Zend Framework recommends &amp;#8211; but does not rigidly enforce &amp;#8211; a file structure for your application. Most of the prominent &amp;#8220;getting started&amp;#8221; sample apps &amp;#8211; like the &lt;a href="http://framework.zend.com/manual/en/learning.quickstart.intro.html"&gt;Zend Framework Quickstart&lt;/a&gt;, &lt;a href="http://akrabat.com/zend-framework-tutorial-18/"&gt;Rob Allen&amp;#8217;s Getting Started tutorial&lt;/a&gt;, &lt;a href="http://github.com/harikt/zfbase"&gt;HariKT&amp;#8217;s Base Files skeleton&lt;/a&gt; &amp;#8211; use it:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://www.papayasoft.com/wp-content/uploads/2010/05/akrabat.png" alt="ZF recommended structure" title="ZF recommended structure" width="225" height="319" class="alignleft size-full wp-image-246" /&gt;&lt;/p&gt;

&lt;p&gt;Using this structure usually requires creating a virtual host pointing to this &lt;code&gt;public&lt;/code&gt; folder and then creating the file &lt;code&gt;public/.htaccess&lt;/code&gt; that maps all non-file, non-directory requests to the index.php file. You then get to enjoy all the rich, creamy Zend goodness.&lt;/p&gt;

&lt;p&gt;But sometimes you are stuck with shared hosting and you can&amp;#8217;t always place your other app folders as siblings to your public web root. For example, one prominent web hosting company provides me a web root of the form &lt;code&gt;/usr/www/users/myusername&lt;/code&gt; with a home directory of &lt;code&gt;/usr/home/myusername&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So whaddya gonna do?&lt;/p&gt;

&lt;div style="clear:both; margin-bottom:20px;"&gt;
&lt;/div&gt;


&lt;h3&gt;A Solution &amp;#8211; Push Down and Protect&lt;/h3&gt;

&lt;p&gt;This question has been &lt;a href="http://stackoverflow.com/questions/1115547/zend-framework-on-shared-hosting"&gt;asked&lt;/a&gt; and &lt;a href="http://www.alberton.info/zend_framework_mod_rewrite_shared_hosting.html"&gt;answered&lt;/a&gt; &lt;a href="http://akrabat.com/zend-framework/zend-framework-on-a-shared-host/"&gt;many&lt;/a&gt; &lt;a href="http://www.ttech.it/en/article/2010/03/zend-framework-all-projects-files-on-document-root/"&gt;times&lt;/a&gt;, but most of the solutions use either custom plugins or tricky .htaccess rules. There&amp;#8217;s nothing wrong with those &amp;#8211; and in general, they are proposed by people way smarter than me. So there is an argument for going with the best. As they used to say: &amp;#8220;No one ever got fired for buying IBM.&amp;#8221;&lt;/p&gt;

&lt;p&gt;But there is a simpler way that has worked well for me: depart slightly from the recommended file structure and modify some include paths. I have seen this approach referenced before, in particular by &lt;a href="http://stackoverflow.com/questions/1115547/zend-framework-on-shared-hosting/1115685#1115685"&gt;tharkun on Stackoverflow&lt;/a&gt;, but I had not seen it written out explicitly. So, I offer it here in the hope that other ZF n00bs like me can benefit from it.&lt;/p&gt;

&lt;p&gt;Essentially, I just push all my app folders down into a subfolder of the web root called something like &lt;code&gt;_zf&lt;/code&gt;, web protect that &lt;code&gt;_zf&lt;/code&gt; folder with a &lt;code&gt;Deny from All&lt;/code&gt; in an &lt;code&gt;.htaccess&lt;/code&gt; file for the folder, and change a few paths in the &lt;code&gt;index.php&lt;/code&gt; entry point.&lt;/p&gt;

&lt;p&gt;I presume that the shared hosting offers me a web root folder called &lt;code&gt;public_html&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So, my folder structure looks like this:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://www.papayasoft.com/wp-content/uploads/2010/05/zfshared.png" alt="ZF application structure for shared hosting" title="ZF application structure for shared hosting" width="225" height="498" class="alignleft size-full wp-image-252" /&gt;&lt;/p&gt;

&lt;div style="clear:both;"&gt;
&lt;/div&gt;


&lt;p&gt;I make sure that the file &lt;code&gt;public_html/_zf/.htaccess&lt;/code&gt; prevents any direct web access:&lt;/p&gt;

&lt;pre class="brush: php"&gt;Deny from All
&lt;/pre&gt;


&lt;p&gt;This keeps anyone from viewing any of the non-public app files.&lt;/p&gt;

&lt;p&gt;Then we just modify paths in &lt;code&gt;public_html/index.php&lt;/code&gt; to point to the &lt;code&gt;_zf&lt;/code&gt; folder, as follows:&lt;/p&gt;

&lt;pre class="brush: php"&gt;set_include_path(implode(PATH_SEPARATOR, 
    array(
        dirname(__FILE__)  . DIRECTORY_SEPARATOR . '_zf' . DIRECTORY_SEPARATOR . 'library',
        get_include_path(),
    )
));

// Define path to application directory
defined('APPLICATION_PATH')
    || define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/_zf/application'));

// Everything else is the same as usual. For example, using Zend_Application...

// Define application environment
defined('APPLICATION_ENV')
    || define('APPLICATION_ENV', (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV') : 'production'));

require_once 'Zend/Application.php';  

$application = new Zend_Application(
    APPLICATION_ENV, 
    APPLICATION_PATH . '/configs/application.ini'
);
$application-&gt;bootstrap()-&gt;run();

&lt;/pre&gt;


&lt;p&gt;And that&amp;#8217;s it!&lt;/p&gt;

&lt;p&gt;A purely modular app structure can also be handled in this way. For example, you can simply put your &lt;code&gt;modules&lt;/code&gt; folder inside your &lt;code&gt;application&lt;/code&gt; folder. Since all the logic associated to module routing, module bootstrapping, and module-specific paths already resides within the framework, the setup above still works.&lt;/p&gt;

&lt;h3&gt;The Downside&lt;/h3&gt;

&lt;p&gt;There is an insidious down-side to all this. Best practice dictates keeping all those app folders &amp;#8211; and especially the config files, rich with passwords and the like &amp;#8211; out of the web root. In theory, we have that all handled with the &lt;code&gt;.htaccess Deny&lt;/code&gt; on the &lt;code&gt;_zf&lt;/code&gt; folder. But it&amp;#8217;s a single point of failure. If it fails for some reason &amp;#8211; say, the .htaccess file doesn&amp;#8217;t get deployed &amp;#8211; then we are fully exposed to a wide variety of potential mischief.&lt;/p&gt;

&lt;p&gt;There is some additional obscurity you can obtain by changing the name of the &lt;code&gt;_zf&lt;/code&gt; folder to something (practically) unguessable. I could even imagine a cron job that renames the folder and makes corresponding changes to the &lt;code&gt;index.php&lt;/code&gt; file. But that&amp;#8217;s probably excessive. And, in any case, as we should all well know, relying solely on &lt;a href="http://en.wikipedia.org/wiki/Security_through_obscurity"&gt;security through obscurity&lt;/a&gt; is a poor approach.&lt;/p&gt;

&lt;p&gt;But maybe this approach is useful to get an app off the ground with a customer who is stuck with his shared hosting package. At some point in the future, when the app is sufficiently profitable, maybe you can convince the customer to move to virtual private server hosting, at which point it&amp;#8217;s a small modification to return to the standard ZF-recommend file structure.&lt;/p&gt;

&lt;p&gt;Whaddya think?&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/papayasoft/~4/t5jFE0bMv34" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.papayasoft.com/2010/05/08/zend-framework-shared-hosting/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Debugging PHP &#8211; Netbeans Code Templates for Zend_Debug and FirePHP]]></title>
    <link href="http://feedproxy.google.com/~r/papayasoft/~3/ekdkh_Z4aJY/" />
    <updated>2010-04-29T00:00:00+07:00</updated>
    <id>http://www.papayasoft.com/2010/04/29/netbeans-firephp-zend-debug</id>
    <content type="html">&lt;p&gt;I recently changed my day-to-day PHP IDE to &lt;a href="http://netbeans.org/features/php/index.html"&gt;Netbeans&lt;/a&gt; and it&amp;#8217;s been a pleasure. [Don&amp;rsquo;t ask me what I was using before, too embarrassed to say.]&lt;/p&gt;

&lt;p&gt;&lt;img src="http://www.papayasoft.com/wp-content/uploads/2010/04/idea-lightbulb-med.jpg" alt="idea light bulb" title="idea-lightbulb-med" width="175" height="258" class="alignleft" /&gt;&lt;/p&gt;

&lt;p&gt;In particular, one of Netbeans&amp;#8217; nice features is Code Templates, little snippets of text that you can insert into your document simply by typing a short prefix and then hitting the &lt;code&gt;Tab&lt;/code&gt; key. They are actually smarter than just static snippets in that they can contain variables that are dynamically filled/changed as you edit. Hugely useful. I use them constantly for a variety of tasks, but my most common use of code templates is for debugging.&lt;/p&gt;

&lt;p&gt;One useful debug tool is &lt;a href="http://www.firephp.org/"&gt;FirePHP&lt;/a&gt; in conjunction with &lt;a href="http://getfirebug.com/"&gt;Firebug&lt;/a&gt;, especially for applications using AJAX.&lt;/p&gt;

&lt;p&gt;Several weeks ago, &lt;a href="http://www.jeremykendall.net/"&gt;Jeremy Kendall&lt;/a&gt; (&lt;a href="http://twitter.com/JeremyKendall/"&gt;@JeremyKendall&lt;/a&gt;) helpfully &lt;a href="http://jaybill.com/2007/10/01/the-most-useful-function-you-will-ever-use-in-the-zend-framework/"&gt;pointed me&lt;/a&gt; to &lt;code&gt;Zend_Debug::dump()&lt;/code&gt; which behaves like an enhanced var_dump(). I was actually gratified to see that it resembles one of my own hacks that I have been using for years, though &lt;code&gt;Zend_Debug::dump()&lt;/code&gt; is, not surprisingly, more polished.&lt;/p&gt;

&lt;p&gt;Following on that, &lt;a href="http://www.stahlstift.de/"&gt;Markus&lt;/a&gt; (&lt;a href="http://twitter.com/derstahlstift"&gt;@derstahlstift&lt;/a&gt;) posted a &lt;a href="http://pastebin.com/sZB6RDwm"&gt;Netbeans code template&lt;/a&gt; that uses &lt;code&gt;Zend_Debug::dump()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I admit that they are both cool, but I prefer to identify precisely where I am doing the dump, using PHP&amp;#8217;s &lt;a href="http://php.net/manual/en/language.constants.predefined.php"&gt;magic constants&lt;/a&gt; &lt;code&gt;__FILE__&lt;/code&gt; and &lt;code&gt;__LINE__&lt;/code&gt;. This allows me to easily chase down the dump statements and remove them once the debugging is finished.&lt;/p&gt;

&lt;p&gt;So, here are my own versions, both in the form of Netbeans Code Templates.&lt;/p&gt;

&lt;p&gt;For &lt;code&gt;FirePHP::send()&lt;/code&gt;:&lt;/p&gt;

&lt;pre class="brush: php"&gt;FB::send("${VAR default="variable"} = " . $$${VAR} . ":: ${func default="func"} :: " . __FILE__ . "(" . __LINE__ . ")");
${cursor}
&lt;/pre&gt;


&lt;p&gt;For &lt;code&gt;Zend_Debug::dump()&lt;/code&gt;:&lt;/p&gt;

&lt;pre class="brush: php"&gt;Zend_Debug::dump($$${VARIABLE variableFromNextAssignmentName default="variable"}, "${VARIABLE variableFromNextAssignmentName}", true); 
echo "&lt;p&gt;
  " . __FILE__ . "(" . __LINE__ . ") :: ${function default="function"} :: ${message default="message"}
&lt;/p&gt;";
${selection}${cursor}
&lt;/pre&gt;


&lt;p&gt;Whaddya think? Do you have any tricks/shortcuts that you use for debugging? Let me know.&lt;/p&gt;

&lt;p&gt;Cheers!&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/papayasoft/~4/ekdkh_Z4aJY" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.papayasoft.com/2010/04/29/netbeans-firephp-zend-debug/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Zend Framework View Helper to Lowercase Titles]]></title>
    <link href="http://feedproxy.google.com/~r/papayasoft/~3/0Tzm1Jw91OY/" />
    <updated>2010-03-31T00:00:00+07:00</updated>
    <id>http://www.papayasoft.com/2010/03/31/zend-framework-view-helper-lowercase-titles</id>
    <content type="html">&lt;p&gt;When working on a web app, I often find myself with my local development version open in one browser window with the live version open in another. To allow me quickly distinguish one from the other, I like to tweak the rendering in the development version by converting the title to lower case.&lt;/p&gt;

&lt;p&gt;Since I have recently begun using &lt;a href="http://framework.zend.com/"&gt;Zend Framework&lt;/a&gt; for much of my development, I wrote a little view helper to handle it.&lt;/p&gt;

&lt;pre class="brush: php"&gt;class App_View_Helper_HeadTitle extends Zend_View_Helper_HeadTitle
{
    public function headTitle($title = null, $setType = Zend_View_Helper_Placeholder_Container_Abstract::APPEND)
    {
        if (null !== $title &amp;#038;&amp;#038; APPLICATION_ENV == 'development'){
            $title = strtolower($title);
        }
        return parent::headTitle($title, $setType);
    }
}

&lt;/pre&gt;


&lt;p&gt;To use it, just add the helper path to your bootstrap. For example,you could do it in your &lt;code&gt;config/application.ini&lt;/code&gt; with:&lt;/p&gt;

&lt;pre class="brush: php"&gt;resources.view[] =
resources.view.helpers.App_View_Helper_ = "App/View/Helper"
&lt;/pre&gt;


&lt;p&gt;The calls to &lt;code&gt;$this-&amp;gt;headTitle()&lt;/code&gt; in your view scripts or layout scripts remain unchanged.&lt;/p&gt;

&lt;p&gt;As a side note, a great repository of Zend Framework snippets is at the aptly named site &lt;a href="http://www.zfsnippets.com/"&gt;ZFSnippets.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Do you use any similar tricks or snippets in your development? Let me know via the comments.&lt;/p&gt;

&lt;p&gt;Cheers!&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/papayasoft/~4/0Tzm1Jw91OY" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://www.papayasoft.com/2010/03/31/zend-framework-view-helper-lowercase-titles/</feedburner:origLink></entry>
  
</feed>
