<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/">
  <channel>
    <title>Blog entries tagged dojo :: mwop.net</title>
    <description>Blog entries tagged dojo :: mwop.net</description>
    <pubDate>Mon, 23 Feb 2009 08:17:00 -0600</pubDate>
    <generator>Laminas_Feed_Writer 2 (https://getlaminas.org)</generator>
    <link>https://mwop.net/blog/tag/dojo</link>
    <atom:link rel="self" type="application/rss+xml" href="https://mwop.net/blog/tag/dojo/rss.xml"/>
    <item>
      <title>Recursively Destroying Dojo ContentPanes</title>
      <pubDate>Mon, 23 Feb 2009 08:17:00 -0600</pubDate>
      <link>https://mwop.net/blog/208-Recursively-Destroying-Dojo-ContentPanes.html</link>
      <guid>https://mwop.net/blog/208-Recursively-Destroying-Dojo-ContentPanes.html</guid>
      <author>contact@mwop.net (Matthew Weier O'Phinney)</author>
      <dc:creator>Matthew Weier O'Phinney</dc:creator>
      <content:encoded><![CDATA[<p>I ran into an issue recently with Dojo's ContentPanes. I was using them with a TabContainer, and had made them closable; however, user actions might re-open tabs that pull from the same source. This led to conflicts with dijit IDs that I had to resolve.</p>
<p>Most Dijits have a <code>destroyRecursive()</code> method which should, theoretically, destroy any dijits contained within them. However, for many Dijits, this functionality simply does not work due to how they are implemented; many do not actually have any knowledge of the dijits beneath them.</p>
<p>ContentPanes fall into this latter category. fortunately, it's relatively easy to accomplish, due to Dojo's heavily object oriented nature.</p>


<pre><code class="language-javascript hljs javascript" data-lang="javascript">dojo.provide(\<span class="hljs-string">"custom.ContentPane\");

dojo.require(\"dijit.layout.ContentPane\");

dojo.declare(\"custom.ContentPane\", [dijit.layout.ContentPane], {
    postMixInProperties: function(){
        if (dijit.byId(this.id)) {
            dijit.byId(this.id).destroyRecursive();
        }
    },

    destroyRecursive: function(){
        dojo.forEach(this.getDescendants(), function(widget){
            widget.destroyRecursive();
        });
        this.inherited(arguments);
    }
});
</span></code></pre>
<p>The <code>destroyRecursive()</code> method is not that different from the one in <code>dijit._Widget</code>; the difference is that instead of calling simply <code>destroy()</code> on any discovered widgets, we destroy recursively.</p>
<p>The <code>postMixInProperties</code> method I added due to IE issues I've run into. Basically, even though the ContentPane was being destroyed recursively, for some reason IE was keeping a reference to the original dijit floating around. <code>postMixInProperties()</code> checks to see if the dijit ID is still around, and if so, destroys it recursively. This allows the ContentPane initialization to proceed.</p>


<div class="h-entry">
    <img class="u-photo photo" width="50" src="https://avatars0.githubusercontent.com/u/25943?v=3&u=79dd2ea1d4d8855944715d09ee4c86215027fa80&s=140" alt="matthew">
    <a class="u-url u-uid p-name" href="https://mwop.net/blog/208-Recursively-Destroying-Dojo-ContentPanes.html">Recursively Destroying Dojo ContentPanes</a> was originally
    published <time class="dt-published" datetime="2009-02-23T08:17:00-06:00">23 February 2009</time>
    on <a href="https://mwop.net">https://mwop.net</a> by
    <a rel="author" class="p-author" href="https://mwop.net">Matthew Weier O&#039;Phinney</a>.
</div>
]]></content:encoded>
      <slash:comments>0</slash:comments>
    </item>
    <item>
      <title>Using JSLint</title>
      <pubDate>Fri, 20 Feb 2009 08:11:41 -0600</pubDate>
      <link>https://mwop.net/blog/207-Using-JSLint.html</link>
      <guid>https://mwop.net/blog/207-Using-JSLint.html</guid>
      <author>contact@mwop.net (Matthew Weier O'Phinney)</author>
      <dc:creator>Matthew Weier O'Phinney</dc:creator>
      <content:encoded><![CDATA[<p>I've been doing a fair bit of programming in <a href="http://dojotoolkit.org/">Dojo</a> lately, and have on occasion run into either inconsistent interfaces, or interfaces that simply fail to load in Internet Explorer. Several people have pointed out to me some optimizations to make, but, being a lazy programmer, I often forget to do so.</p>
<p>Fortunately, there's a tool for lazy developers like myself: <a href="http://jslint.com">JSLint</a>. Linters are commonly used in static development languages so that developers can verify that their programs are syntactically correct prior to compilation; they basically ensure that you're not accidentally attempting to compile something that will never compile in the first place. Many dynamic languages also have them; I've had a key bound in vim to run the current file through PHP's linter for many years now. JSLint provides linting capabilities for JavaScript, as well as some code analysis to point you towards some best practices — mainly geared for cross-browser compatability.</p>


<p>JSLint looks, at first, like it needs to be a web-based tool. However, this is not so; there are a number of JavaScript VMs you can utilize. Dojo's source builds, for instance, come with a version of Apache's Rhino, a JS VM written in Java, and JSLint provides a script for use with Rhino.</p>
<p>To get JSLint running on the command line using the Rhino shipped with Dojo, you'll need to download the following file:</p>
<ul>
<li><a href="http://jslint.com/rhino/jslint.js">jslint.js</a></li>
</ul>
<p>Put these files in a directory of your choosing. Then, create a file called <code>jslint</code>, with the following:</p>
<pre><code class="language-bash hljs bash" data-lang="bash"><span class="hljs-meta">#!/bin/sh</span>
<span class="hljs-built_in">exec</span> java \
-jar /path/to/dojo/util/shrinksafe/custom_rhino.jar \
/path/to/jslint.js <span class="hljs-variable">$1</span>
</code></pre>
<p>Note: you'll need to put in the correct paths to your Dojo installation as well as to where you placed the <code>jslint.js</code> file.</p>
<p>Make that file executable, and put it somewhere on your path. Once you do, you can invoke it quite simply:</p>
<pre><code class="language-bash hljs bash" data-lang="bash">$ jslint foo.js
</code></pre>
<p>and get some nice output. Something I will often do is to grab all JS files in a tree using globbing, and then pass them individually to the linter. In zsh, that might look like this:</p>
<pre><code class="language-bash hljs bash" data-lang="bash">$ <span class="hljs-keyword">for</span> f <span class="hljs-keyword">in</span> *.js;<span class="hljs-keyword">do</span> jslint <span class="hljs-variable">$f</span>;<span class="hljs-keyword">done</span>
</code></pre>
<p>I found in most cases, following the advice of the linter eliminated any issues in IE, as well as fixed any inconsistencies I was observing in the UI. Your results may vary, of course — but it's a tremendously useful tool to have in your toolbox if you're a JavaScript developer.</p>


<div class="h-entry">
    <img class="u-photo photo" width="50" src="https://avatars0.githubusercontent.com/u/25943?v=3&u=79dd2ea1d4d8855944715d09ee4c86215027fa80&s=140" alt="matthew">
    <a class="u-url u-uid p-name" href="https://mwop.net/blog/207-Using-JSLint.html">Using JSLint</a> was originally
    published <time class="dt-published" datetime="2009-02-20T08:11:41-06:00">20 February 2009</time>
    on <a href="https://mwop.net">https://mwop.net</a> by
    <a rel="author" class="p-author" href="https://mwop.net">Matthew Weier O&#039;Phinney</a>.
</div>
]]></content:encoded>
      <slash:comments>0</slash:comments>
    </item>
    <item>
      <title>2008: The year in review</title>
      <pubDate>Mon, 05 Jan 2009 02:00:49 -0600</pubDate>
      <link>https://mwop.net/blog/203-2008-The-year-in-review.html</link>
      <guid>https://mwop.net/blog/203-2008-The-year-in-review.html</guid>
      <author>contact@mwop.net (Matthew Weier O'Phinney)</author>
      <dc:creator>Matthew Weier O'Phinney</dc:creator>
      <content:encoded><![CDATA[<p>That time of year again — wrap-up time. Each year, it seems like it's the busiest ever, and I often wonder if it will ever slow down. As usual, I'm restricting myself to primarily professional activities out of respect for the privacy of my family.</p>
<p>The short, executive summary:</p>
<ul>
<li>One trip to Israel</li>
<li>One trip to The Netherlands</li>
<li>One trip to California's Bay Area</li>
<li>One trip to Atlanta, GA</li>
<li>Three minor releases of Zend Framework</li>
<li>Seven webinars, six for zend.com and one for Adobe</li>
<li>Three conferences attended as a speaker, including:
<ul>
<li>One six-hour workshop</li>
<li>One three-hour tutorial (as a co-presenter)</li>
<li>Four regular sessions</li>
<li>Two panel sessions (one scheduled, one for an uncon)</li>
<li>Two uncon sessions (one as a co-presenter)</li>
<li>One foul-mouthed Pecha Kucha talk</li>
</ul>
</li>
<li>Ten Burlington, VT PHP User's Group meetings attended; I spoke at many</li>
<li>One Bug Hunt week organized</li>
<li>Two books reviewed as a technical editor</li>
<li>Six articles for <a href="http://devzone.zend.com/">DevZone</a></li>
<li>50 blog entries (including this one)</li>
</ul>
<p>Read on for the gruesome, month-by-month breakdown.</p>


<h2>January and February</h2>
<p>I started coding <code>Zend_Form</code> in earnest in January, and had a preview ready for testing mid-month. The pace continued into February, as I addressed user feedback and issues, and continued working feverishly towards what would become Zend Framework's 1.5.0 release.</p>
<p>I also answered many questions for and had many discussions with <a href="http://www.calevans.com/">Cal Evans</a> relating to his &quot;Guide to Programming Zend Framework&quot;.</p>
<h2>March</h2>
<p>I gave my first webinar of the year early in March, on the subject of <code>Zend_Form</code>; it was very well attended, but unfortunately there was an issue recording the sound, so the recording was never released. After two more failed attempts at re-recording, we gave up. I apologize to all who have wanted to view it.</p>
<p>While working towards the 1.5.0 release, <a href="http://ralphschindler.com/">Ralph Schindler</a> and I also finished up final touches on <code>Zend_Layout</code> and the various &quot;placeholder&quot; view helper implementations.</p>
<p>On 17 March 2008, we released Zend Framework 1.5, our first minor release following 1.0.0.</p>
<p>I started blogging tips and tricks for 1.5, and also writing articles for <a href="http://devzone.zend.com/">DevZone</a> during March, and had tremendous amounts of feedback. In fact, one blog post, on &quot;Login and Authentication&quot;, is still one of the most trafficked on my blog after 9 months.</p>
<p>I also began what I envisioned as a series of Vim posts, but, alas, it has resulted only in two.</p>
<h2>April</h2>
<p>Following the 1.5 release, I did weekly posts for a month or so covering various features of Zend Framework, including Front Controller plugins, Action Controller helpers, and View helpers. Towards the end of the month, the entire team participated in a Q&amp;A webinar to discuss the 1.5 release.</p>
<h2>May</h2>
<p>At the beginning of the month, I released the last in my series of 1.5 tutorials on <a href="http://devzone.zend.com/">DevZone</a>, covering Form decorators. This has saved me countless hours on IRC and in the mailing lists explaining how this aspect of forms work.</p>
<p>During this month, we also finally announced that Zend Framework would be partnering with <a href="http://dojotoolkit.org/">Dojo</a> to provide an out-of-the-box RIA solution. I began work identifying the various integration points and creating proposals for implementation. I also did a Q&amp;A webinar with the Dojo team outlining the proposed integration.</p>
<p>At the end of the month, the ZF team reorganized the subversion repository to allow for an &quot;Extras&quot; repository, and also to ensure that projects originating in the laboratory or extras and migrating to the standard library retain all history. Even with the big notices we put on the ZF site, articles on DevZone, and posts on various blogs, we still get questions on this seven months later. Let this be a lesson to you: plan your repositories for any contingency as early as you can!</p>
<h2>June</h2>
<p>I started June with a trip to Israel, to visit the Zend offices. I met up with <a href="http://andigutmans.blogspot.com/">Andi</a> in Newark, and we flew from there to Israel several rows apart in coach. One of the best meals I've ever had was after we landed and he invited me to his sister's place for dinner, and we dined on chicken marinated in home-pressed olive oil and fresh herbs, hummus, and pitas baked with fresh oregano. The rest of the week was spent in the office, in endless meetings.</p>
<p>Four days after returning from Israel, I flew to Amsterdam for the <a href="http://www.phpconference.nl">Dutch PHP Conference</a>, to which I'd been invited to speak. My good friend <a href="http://wolerized.com/">Remi</a> took the train up to Amsterdam to meet me the day I flew in, and we walked and walked and walked around the city, until dinnertime. <a href="http://www.leftontheweb.com/">Stefan Koopmanschap</a> then met us for a lovely dinner, and I returned to the hotel to finish screenshots for the six-hour workshop on Zend Framework I was presenting the next day. The entire conference was wonderful, and I met many fantastic people, including <a href="http://www.priebsch.de/">Stefan Priebsch</a>, <a href="http://www.lornajane.net/">Lorna Jane Mitchell</a>, <a href="http://andries.systray.be/">Andries Seutens</a>, and many, many more — plus many familiar faces, such as Sebastian Bergmann, Derek Rethans, Mike Van Dam, Felix de Vliegher, and Marco Tabini.</p>
<p>On my blog, I started raising the question of how we will refer to Abstract classes and Interfaces in PHP 5.3, but I think my arguments went largely unheard and/or misunderstood.</p>
<p>The last half of the month was spent working on both Dojo integration with Zend Framework (a task that turned out fairly easy, in large part due to some wonderful guidance from <a href="http://higginsforpresident.net/">Pete Higgins</a>), and preparing <code>Zend_Test_PHPUnit</code> for inclusion in Zend Framework 1.6.</p>
<h2>July</h2>
<p>I think I'll remember July as the month of the neverending release cycle.</p>
<h2>August</h2>
<p>On 8 August 2008, PHP 4 officially died. I thought about drinking a toast for about 3 seconds, forgot about it, and finished my beer.</p>
<p>The following Monday, we released the second release candidate of Zend Framework 1.6.0.</p>
<p>August, too, became part of the month of the neverending release cycle.</p>
<h2>September</h2>
<p>Finally, on 2 September 2008, we released 1.6.0 into the wild. My contributions included, as noted earlier, Dojo integration, PHPUnit integration, and code assistance on our Captcha solution and file upload support.</p>
<p>The next day, I gave yet another webinar on Zend Framework and Dojo integration, but finally actually had some code samples and working demos to show off, soundly quieting the claims of vaporware. I also started learning about Dojo release builds, under the tutelage of Pete Higgins.</p>
<p>Mid-month saw the fourth annual Zend/PHP Conference, this time in Santa Clara. I was involved in a marathon of seven different sessions over three days. I've rarely been so exhausted, and it's a wonder I remember anything following — but I had a wonderful time with the PHP <em>community</em> following, including <a href="http://www.bombdiggity.net/">Jon Whitcraft</a>, <a href="http://akrabat.com/">Rob Allen</a>, the <a href="http://ibuildings.nl/">ibuildings</a> crew, and more.</p>
<p>I also finally got to meet <a href="http://sklar.com/">David Sklar</a>, to whom I owe the fact of my first public speaking engagement at the first ZendCon.</p>
<p>Following ZendCon, there were announcements that two colleagues at Zend I respect highly were leaving for new opportunities: Mark de Visser left to join Sonatype as its CEO, and Cal Evans left to head ibuildings' new Center for PHP Expertise. I wish them both luck in their new endeavors.</p>
<h2>October</h2>
<p>I helped <a href="http://wadearnold.com/blog/">Wade Arnold</a> complete testing of <code>Zend_Amf</code> as we prepared for the Zend Framework 1.7.0 release, and learned a fair deal about Flex in the process.</p>
<p>During this time, I also completed a technical review of <a href="http://zendframeworkinaction.com">Zend Framework in Action</a>. Rob Allen and Nick Lo had contacted me earlier in the year, but I'd been unable to commit to it. In July, I agreed, only to get sucked into the neverending release cycle. Fortunately, in October I had time to complete the review. The book is very well written and organized, and I can't recommend it highly enough. I was able to give some constructive feedback and have some dialog with Rob that, hopefully, helped clarify a few areas of Zend Framework, and will hopefully help their readers.</p>
<p>For the 1.7 release of Zend Framework, I worked on performance benchmarking, profiling, improvements, and a best practices guide.</p>
<p>Late in the month, I delivered a webinar with Lee Brimelow for Adobe to showcase the upcoming AMF support in Zend Framework.</p>
<h2>November</h2>
<p>The last few days of October and first week of November, I organized a bug hunt week for Zend Framework, culminating in a <a href="http://bughuntday.org/">Bug Hunt Day</a> event held and organized by <a href="http://www.phpbelgium.be/">PHP Belgium</a> and <a href="http://phpgg.nl/">phpGG</a> (The Netherlands). We closed out close to 150 issues over the course of the week and a couple dozen during the Bug Hunt Day, and got many contributors started on the path of professional bug squashing enlightenment.</p>
<p>The second week of November, I flew down to Atlanta, GA, to attend <a href="http://phpworks.mtacon.com/">php|works</a>.. err, php|works/pyworks. First off, a huge thank you to <a href="http://naramore.net/blog/">Elizabeth Naramore</a>, who helped me fairly last minute to make sure I had a room to stay in. While there, I presented my Dojo and Zend Framework talk, but with some updated content. Of course, every presenter's nightmare occurred, and I had to reboot my laptop mid-stream. I surprised myself, and, I think, the attendees by actually being able to continue speaking while we waited for my machine to reboot.</p>
<p>I also presented a <a href="http://en.wikipedia.org/wiki/Pecha_Kucha">Pecha Kucha</a> talk — I re-branded the phrase as &quot;Pikachu&quot; a couple weeks earlier (a reference to the iconic character in <a href="http://www.pokemon.com/">Pokemon</a>, a game I play with my daughter), and that phrase has, for better or for worse, stuck. My talk was on how to be banned from an open source project, and I swore entirely too much. It was a nice release, however, as I try to be politic in public usually, and sometimes just need to rant.</p>
<p>I got to see a ton of old and new friends alike while there — former Zenders <a href="http://mikenaberezny.com/">Mike Naberezny</a> and <a href="http://paul-m-jones.com/">Paul M. Jones</a>, <a href="http://caseysoftware.com/blog/">Keith Casey</a>, <a href="http://ishouldbecoding.com/">Matthew Turland</a>, <a href="http://jansch.nl/">Ivo</a> and a bunch of the ibuildings crew, Pollita (sorry, I have to stop linking everyone now…), Sebastian… basically, a ton of the usual suspects. I also met a lot of new people, many of them introducing themselves as ZF users; I appreciate all of you introducing yourselves, as <em>you</em> are the reason I code.</p>
<p>The following Monday, 17 November 2008, we released Zend Framework 1.7.0, timed to coincide with the the Adobe MAX conference, as AMF support was our major story for the release. <code>Zend_Amf</code> has generated tremendous buzz in both the PHP and Flash/Flex communities, due to the simplicity and robustness of its design. This release also marked the first release to include the extras repository — which now ships with community-contributed <a href="http://jquery.com/">JQuery</a> support.</p>
<h2>December</h2>
<p><a href="http://shiflett.org/">Chris Shiflett</a> and <a href="http://seancoates.com/">Sean Coates</a> organized this year's <a href="http://phpadvent.org/2008/">PHP Advent Calendar</a>, and solicited entries from a select group of PHP community members a week in advance. I didn't volunteer to contribute for the first week, but managed to get mine in on the first day… only to see it appear the very next. Hopefuly, my guide to responsible contributions will help those wondering how to report and/or fix bugs in open source projects.</p>
<p>I started blogging more, in part due to more free time in the evenings (it's nice when the kids go to bed at a reasonable hour!), and in part due to finally putting a number of ideas into a blogging &quot;backlog&quot; so that I could pick up and post when I had time. From this, I added an entry on mumbles/irssi integration, autocompletion with ZF and Dojo, created a simple pubsub implementation for PHP, and started a series of posts on how to architect models (and some concrete tips for doing so). I have more posts in December than I have in several other months combined.</p>
<h2>Reflection</h2>
<p>This past year, I became much more involved with both the Zend Framework and greater PHP communities, and feel I have enriched my life with many wonderful new friends — some local, some global. I feel truly fortunate to be working in a job I love, contributing to a project that helps others do the jobs they love, and part of such an accepting and vibrant group of people.</p>
<p>Looking back, I travelled less, though because most of it was in a five month period, it felt like more. On that note, I vow never to do back to back trips across the big pond, as it was incredibly exhausting.</p>
<h2>Looking ahead to 2009</h2>
<p>I have several things to look forward to already in 2009. I'll be continuing my series of posts on models. In February, I will have an article published in a print magazine for the first tiem. I'll be speaking at PHP Quebec in March, presenting two sessions and sitting in on a panel. I hope to speak at several other conferences, and potentially write more articles and tutorials. Overall, I want to contribute more to the ecosystem of best practices in PHP, particularly in the areas of testing and deployment strategies.</p>
<p>I hope this post finds <em>you</em> in good health and spirits, and that you have a fantastic start to the new year!</p>


<div class="h-entry">
    <img class="u-photo photo" width="50" src="https://avatars0.githubusercontent.com/u/25943?v=3&u=79dd2ea1d4d8855944715d09ee4c86215027fa80&s=140" alt="matthew">
    <a class="u-url u-uid p-name" href="https://mwop.net/blog/203-2008-The-year-in-review.html">2008: The year in review</a> was originally
    published <time class="dt-published" datetime="2008-12-31T14:17:03-06:00">31 December 2008</time>
    on <a href="https://mwop.net">https://mwop.net</a> by
    <a rel="author" class="p-author" href="https://mwop.net">Matthew Weier O&#039;Phinney</a>.
</div>
]]></content:encoded>
      <slash:comments>0</slash:comments>
    </item>
    <item>
      <title>A Simple PHP Publish-Subscribe System</title>
      <pubDate>Wed, 31 Dec 2008 07:05:35 -0600</pubDate>
      <link>https://mwop.net/blog/199-A-Simple-PHP-Publish-Subscribe-System.html</link>
      <guid>https://mwop.net/blog/199-A-Simple-PHP-Publish-Subscribe-System.html</guid>
      <author>contact@mwop.net (Matthew Weier O'Phinney)</author>
      <dc:creator>Matthew Weier O'Phinney</dc:creator>
      <content:encoded><![CDATA[<p>I've been playing a lot with <a href="http://dojotoolkit.org/">Dojo</a> lately, and have
been very impressed by its elegant publish-subscribe system. Basically, any
object can publish an event, and any other object can subscribe to it. This
creates an incredibly flexible notification architecture that's completely
opt-in.</p>
<p>The system has elements of Aspect Oriented Programming (AOP), as well as the
Observer pattern. Its power, however, is in the fact that an individual object
does not need to implement any specific interface in order to act as either a
Subject or an Observer; the system is globally available.</p>
<p>Being a developer who recognizes good ideas when he sees them, of course I
decided to port the idea to PHP. You can see the results
<a href="http://github.com/weierophinney/phly/tree/master/Phly_PubSub">on github</a>.</p>


<p>Usage is incredibly simple: an object publishes an event, which triggers all
subscribers.</p>
<p>Probably the most illustrative solution would be for optionally logging. Say
for instance that you create a logger instance in your application bootstrap;
you could then subscribe it to all &quot;log&quot; events:</p>
<pre><code class="language-php hljs php" data-lang="php">$log = <span class="hljs-keyword">new</span> Zend_Log(<span class="hljs-keyword">new</span> Zend_Log_Writer_Stream(<span class="hljs-string">'/tmp/application.log'</span>));
Phly_PubSub::subscribe(<span class="hljs-string">'log'</span>, $log, <span class="hljs-string">'info'</span>);
</code></pre>
<p>Then, in your code, whenever you might want to log some information, simply
publish to the &quot;log&quot; topic:</p>
<pre><code class="language-php hljs php" data-lang="php">Phly_PubSub::publish(<span class="hljs-string">'log'</span>, <span class="hljs-string">'Log message...'</span>);
</code></pre>
<p>In production, you could simply comment out the log definition and
subscription, disabling logging throughout the application. Events that publish
to topics without subscribers simply return early — meaning no ramifications
for code that uses the system. You could then enable the logger at will when
you need to debug or determine what events are triggering.</p>
<p>As another example, consider a model that has a <code>save</code> method. You may want to
log the data sent to it, as well as the id returned. Additionally, you may want
to update your search index and caches once the item has been saved to your
persistence store.</p>
<p>Your model's <code>save</code> method might then look like this:</p>
<pre><code class="language-php hljs php" data-lang="php"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Foo</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">save</span><span class="hljs-params">(array $data)</span>
    </span>{
        Phly_PubSub::publish(<span class="hljs-string">'Foo::save::start'</span>, $data, <span class="hljs-keyword">$this</span>);

        <span class="hljs-comment">// ...</span>

        Phly_PubSub::publish(<span class="hljs-string">'Foo::save::end'</span>, $id, <span class="hljs-keyword">$this</span>);
        <span class="hljs-keyword">return</span> $id;
    }
}
</code></pre>
<p>Elsewhere, you may have defined your logger, indexer, and cache. Where those
are defined, you would tell them what topics you're subscribing each to.</p>
<pre><code class="language-php hljs php" data-lang="php">Phly_PubSub::subscribe(<span class="hljs-string">'Foo::save::start'</span>, $logger, <span class="hljs-string">'logSaveData'</span>);
Phly_PubSub::subscribe(<span class="hljs-string">'Foo::save::end'</span>, $logger, <span class="hljs-string">'logSaveId'</span>);
Phly_PubSub::subscribe(<span class="hljs-string">'Foo::save::end'</span>, $cache, <span class="hljs-string">'updateFooItem'</span>);
Phly_PubSub::subscribe(<span class="hljs-string">'Foo::save::end'</span>, $index, <span class="hljs-string">'updateFooItem'</span>);
</code></pre>
<p>The beauty of the approach is the simplicity: Foo doesn't need to implement
its own pub/sub interface — in fact, if Foo already existed in your
application, you could drop in this functionality trivially. On the other side
of the coin, if you have no subscribers to the events, there are no drawbacks.</p>
<p>Some places it could be improved:</p>
<ul>
<li>The ability for return values could be useful, to allow interruption of
method execution or to modify arguments sent by the publisher. However, since
each topic may have multiple handlers, a simple interface would be difficult
to achieve.</li>
<li>Exception handling. In most cases, you probably don't want method execution
to halt due to a subscriber raising an exception. However, you still need
some way to report such errors.</li>
</ul>
<p>I'm excited to see what uses <em>you</em> may be able to put this to; drop me a line
if you start using it!</p>
<p><strong>Update (2008-12-30):</strong> Based on some of the comments to this post, I created
<code>Phly_PubSub_Provider</code>, which is a non-static implementation that can be
attached to individual classes — basically providing a per-object plugin
system. Usage is as follows:</p>
<pre><code class="language-php hljs php" data-lang="php"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Foo</span>
</span>{
    <span class="hljs-keyword">protected</span> $_plugins;

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span><span class="hljs-params">()</span>
    </span>{
        <span class="hljs-keyword">$this</span>-&gt;_plugins = <span class="hljs-keyword">new</span> Phly_PubSub_Provider();
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getPluginProvider</span><span class="hljs-params">()</span>
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;_plugins;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">bar</span><span class="hljs-params">()</span>
    </span>{
        <span class="hljs-keyword">$this</span>-&gt;_plugins-&gt;publish(<span class="hljs-string">'bar'</span>);
    }
}

$foo = <span class="hljs-keyword">new</span> Foo();

<span class="hljs-comment">// Subscribe echo() to the 'bar' event:</span>
$foo-&gt;getPluginProvider()-&gt;subscribe(<span class="hljs-string">'bar'</span>, <span class="hljs-string">'echo'</span>);

$foo-&gt;bar(); <span class="hljs-comment">// echo's 'bar'</span>
</code></pre>


<div class="h-entry">
    <img class="u-photo photo" width="50" src="https://avatars0.githubusercontent.com/u/25943?v=3&u=79dd2ea1d4d8855944715d09ee4c86215027fa80&s=140" alt="matthew">
    <a class="u-url u-uid p-name" href="https://mwop.net/blog/199-A-Simple-PHP-Publish-Subscribe-System.html">A Simple PHP Publish-Subscribe System</a> was originally
    published <time class="dt-published" datetime="2008-12-15T10:26:00-06:00">15 December 2008</time>
    on <a href="https://mwop.net">https://mwop.net</a> by
    <a rel="author" class="p-author" href="https://mwop.net">Matthew Weier O&#039;Phinney</a>.
</div>
]]></content:encoded>
      <slash:comments>0</slash:comments>
    </item>
    <item>
      <title>Autocompletion with Zend Framework and Dojo</title>
      <pubDate>Mon, 15 Dec 2008 06:49:51 -0600</pubDate>
      <link>https://mwop.net/blog/198-Autocompletion-with-Zend-Framework-and-Dojo.html</link>
      <guid>https://mwop.net/blog/198-Autocompletion-with-Zend-Framework-and-Dojo.html</guid>
      <author>contact@mwop.net (Matthew Weier O'Phinney)</author>
      <dc:creator>Matthew Weier O'Phinney</dc:creator>
      <content:encoded><![CDATA[<p>I've fielded several questions about setting up an autocompleter with
<a href="http://framework.zend.com/">Zend Framework</a> and <a href="http://dojotoolkit.org/">Dojo</a>, and
decided it was time to create a HOWTO on the subject, particularly as there are
some nuances you need to pay attention to.</p>


<h2>Which dijits perform autocompletion?</h2>
<p>Your first task is selecting an appropriate form element capable of
autocompletion. Dijit provides two, <code>ComboBox</code> and <code>FilteringSelect</code>. However,
they have different capabilities:</p>
<ul>
<li><code>ComboBox</code> allows you to enter arbitrary text; if it doesn't match the
associated list, it is still considered valid. The text <em>entered</em> is
submitted — <em><strong>not</strong></em> the option value. (This differs from normal dropdown
selects.)</li>
<li><code>FilteringSelect</code> also allows you to enter arbitrary text, but it will only
be considered valid if it matches an option provided to it. The <em>option
value</em> is submitted, just like a normal dropdown select.</li>
</ul>
<p>Once you've chose the appropriate form element type, you then need to specify a
<code>dojo.data</code> store. <code>dojo.data</code> provides a consistent API for data structures
consumed by dijits and other dojo components. At its heart, it's simply an
array of arbitrary JSON structures that each contain a common identifier field
containing a unique value per item. Internally, both <code>ComboBox</code> and
<code>FilteringSelect</code> can utilize <code>dojo.data</code> stores to populate their options
and/or provide matches. Dojo provides a variety of <code>dojo.data</code> stores for such
purposes.</p>
<h3>Defining the form element</h3>
<p>Defining the form element is very straightforward. From your <code>Zend_Dojo_Form</code>
instance (or your form extending that class), simply call <code>addElement()</code> as
usual. Later in this tutorial, depending on the approach you use, you may need
to add some information to the element definition, but for now, all that's
needed is the most basic of element definitions:</p>
<pre><code class="language-php hljs php" data-lang="php">$form-&gt;addElement(<span class="hljs-string">'ComboBox'</span>, <span class="hljs-string">'myAutoCompleteField'</span>, <span class="hljs-keyword">array</span>(
    <span class="hljs-string">'label'</span> =&gt; <span class="hljs-string">'My autocomplete field:'</span>,
));
</code></pre>
<h2>Providing data to a dojo.data store</h2>
<p>We're going to work backwards now, as providing data to the data store is
relatively trivial when using <code>Zend_Dojo_Data</code>.</p>
<p>First, we'll create an action in our controller, and assign the model and the
query parameter to the view. We'll be setting up our <code>dojo.data</code> store to send
the query string via the GET parameter <code>q</code>, so that's what we'll assign to the
view.</p>
<pre><code class="language-php hljs php" data-lang="php">    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">autocompleteAction</span><span class="hljs-params">()</span>
    </span>{
        <span class="hljs-comment">// First, get the model somehow</span>
        <span class="hljs-keyword">$this</span>-&gt;view-&gt;model = <span class="hljs-keyword">$this</span>-&gt;getModel();

        <span class="hljs-comment">// Then get the query, defaulting to an empty string</span>
        <span class="hljs-keyword">$this</span>-&gt;view-&gt;query = <span class="hljs-keyword">$this</span>-&gt;_getParam(<span class="hljs-string">'q'</span>, <span class="hljs-string">''</span>);
    }
</code></pre>
<p>Now, let's create the view script. First, we'll disable layouts; second, we'll
pass our query to the model; third, we'll instantiate our <code>Zend_Dojo_Data</code>
object with the results of our query; and finally, we'll echo the
<code>Zend_Dojo_Data</code> instance.</p>
<pre><code class="language-php hljs php" data-lang="php"><span class="hljs-meta">&lt;?php</span>
<span class="hljs-comment">// Disable layouts</span>
<span class="hljs-keyword">$this</span>-&gt;layout()-&gt;disableLayout();

<span class="hljs-comment">// Fetch results from the model; again, merely illustrative</span>
$results = <span class="hljs-keyword">$this</span>-&gt;model-&gt;query(<span class="hljs-keyword">$this</span>-&gt;params);

<span class="hljs-comment">// Now, create a Zend_Dojo_Data object.</span>
<span class="hljs-comment">// The first parameter is the name of the field that has a</span>
<span class="hljs-comment">// unique identifier. The second is the dataset. The third</span>
<span class="hljs-comment">// should be specified for autocompletion, and should be the</span>
<span class="hljs-comment">// name of the field representing the data to display in the</span>
<span class="hljs-comment">// dropdown. Note how it corresponds to \"name\" in the </span>
<span class="hljs-comment">// AutocompleteReadStore.</span>
$data = <span class="hljs-keyword">new</span> Zend_Dojo_Data(<span class="hljs-string">'id'</span>, $results, <span class="hljs-string">'name'</span>);

<span class="hljs-comment">// Send our output</span>
<span class="hljs-keyword">echo</span> $data;
</code></pre>
<p>That's really all there is to it. You can actually automate some of this using
the <code>AjaxContext</code> action helper, making it even simpler.</p>
<h2>Using dojox.data.QueryReadStore</h2>
<p>We now have an endpoint for our <code>dojo.data</code> data store, so now we need to
determine which store type to use.</p>
<p><code>dojox.data.QueryReadStore</code> is a fantastic <code>dojo.data</code> store allowing you to
create arbitrary queries on data. It creates the query as a JSON object:</p>
<pre><code class="language-javascript hljs javascript" data-lang="javascript">{
    <span class="hljs-string">"query"</span>: { <span class="hljs-string">"name"</span>: <span class="hljs-string">"A*"</span> },
    <span class="hljs-string">"queryOptions"</span>: { <span class="hljs-string">"ignoreCase"</span>: <span class="hljs-literal">true</span> },
    <span class="hljs-string">"sort"</span>: [{ <span class="hljs-string">"attribute"</span>: <span class="hljs-string">"name"</span>, <span class="hljs-string">"descending"</span>: <span class="hljs-literal">false</span> }],
    <span class="hljs-string">"start"</span>: <span class="hljs-number">0</span>,
    <span class="hljs-string">"count"</span>: <span class="hljs-number">10</span>
}
</code></pre>
<p>This is problematic in two ways. First, if you were to use it directly, you'd
be limited to POST requests, submitting it as a raw post. Second, and related,
this means that requests could not be cached client-side.</p>
<p>Fortunately, there's an easy way to correct the situation: extend
<code>dojox.data.QueryReadStore</code> and override the <code>fetch</code> method to rewrite the
query as a simple GET query with a single parameter.</p>
<pre><code class="language-javascript hljs javascript" data-lang="javascript">dojo.provide(<span class="hljs-string">"custom.AutocompleteReadStore"</span>);

dojo.declare(
    <span class="hljs-string">"custom.AutocompleteReadStore"</span>, <span class="hljs-comment">// our class name</span>
    dojox.data.QueryReadStore,      <span class="hljs-comment">// what we're extending</span>
    {
        <span class="hljs-attr">fetch</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">request</span>) </span>{  <span class="hljs-comment">// the fetch method</span>
            <span class="hljs-comment">// set the serverQuery, which sets query string parameters</span>
            request.serverQuery = {<span class="hljs-attr">q</span>: request.query.name};

            <span class="hljs-comment">// and then operate as normal:</span>
            <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.inherited(<span class="hljs-string">"fetch"</span>, <span class="hljs-built_in">arguments</span>);
        }
    }
);
</code></pre>
<p>The question now is, where to create this definition?</p>
<p>You have two options: you can inline the custom definition (less intuitive) and
connect the data store manually to the form element, or you can create an
actual javascript class file (slightly more work) and have your form element
setup the data store for you.</p>
<h3>Inlining a custom QueryReadStore class extension</h3>
<p>Inlining is a bit tricky to accomplish, as you need to declare things in the
appropriate order. When using this technique, you need to do the following:</p>
<ol>
<li>require the <code>dojox.data.QueryReadStore</code> class</li>
<li>define a global JS variable that will be used to identify your store</li>
<li>use <code>dojo.provide</code> and <code>dojo.declare</code> to create your custom data store extension</li>
<li>define an onLoad event that instantiates the data store and attaches it to the form element</li>
</ol>
<p>We can do all the above within the same view script in which we spit out our form:</p>
<pre><code class="language-php hljs php" data-lang="php"><span class="hljs-meta">&lt;?php</span>
<span class="hljs-keyword">$this</span>-&gt;dojo()-&gt;requireModule(<span class="hljs-string">"dojox.data.QueryReadStore"</span>);

<span class="hljs-comment">// Define a new data store class, and </span>
<span class="hljs-comment">// setup our autocompleter data store</span>
<span class="hljs-keyword">$this</span>-&gt;dojo()-&gt;javascriptCaptureStart() <span class="hljs-meta">?&gt;</span>
dojo.provide(<span class="hljs-string">"custom.AutocompleteReadStore"</span>);
dojo.<span class="hljs-keyword">declare</span>(
    <span class="hljs-string">"custom.AutocompleteReadStore"</span>, 
    dojox.data.QueryReadStore, 
    {
        fetch: <span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">(request)</span> </span>{
            request.serverQuery = {q: request.query.name};
            <span class="hljs-keyword">return</span> this.inherited(<span class="hljs-string">"fetch"</span>, arguments);
        }
    }
);
<span class="hljs-keyword">var</span> autocompleter;
<span class="hljs-meta">&lt;?php</span> <span class="hljs-keyword">$this</span>-&gt;dojo()-&gt;javascriptCaptureEnd();

<span class="hljs-comment">// Once dijits have been created and all classes defined,</span>
<span class="hljs-comment">// instantiate the autocompleter and attach it to the element.</span>
<span class="hljs-keyword">$this</span>-&gt;dojo()-&gt;onLoadCaptureStart() <span class="hljs-meta">?&gt;</span>
<span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">()</span> </span>{
    autocompleter = <span class="hljs-keyword">new</span> custom.AutocompleteReadStore({
        url: <span class="hljs-string">"/test/autocomplete"</span>,
        requestMethod: <span class="hljs-string">"get"</span>
    });
    dijit.byId(<span class="hljs-string">"myAutoCompleteField"</span>).attr({
        store: autocompleter
    });
}
<span class="hljs-meta">&lt;?php</span> <span class="hljs-keyword">$this</span>-&gt;dojo()-&gt;onLoadCaptureEnd() <span class="hljs-meta">?&gt;</span>
&lt;h1&gt;Autocompletion Example&lt;/h1&gt;
&lt;div <span class="hljs-class"><span class="hljs-keyword">class</span>="<span class="hljs-title">tundra</span>"&gt;
&lt;?<span class="hljs-title">php</span> <span class="hljs-title">echo</span> $<span class="hljs-title">this</span>-&gt;<span class="hljs-title">form</span> ?&gt;
&lt;/<span class="hljs-title">div</span>&gt;
</span></code></pre>
<p>This works well, and is an expedient way to get autocompletion working for your
element. However, it breaks the DRY principle as you cannot re-use the custom
class in other areas. So, let's look at a better solution</p>
<h3>Creating a reusable custom QueryReadStore class extension</h3>
<p>The recommendation by the Dojo developers is that you should create this class
as a <em>javascript</em> class, with your other <em>javascript</em> code. The reasons for
this are numerous: you can re-use the class elsewhere, and you can also include
it in custom builds — which will ensure that it is stripped of whitespace and
packed, leading to smaller downloads for your end users.</p>
<p>The process isn't as scary as it may initially sound. Assuming that your
<code>public/</code> directory has the following structure:</p>
<pre><code class="language-arduino hljs arduino" data-lang="arduino"><span class="hljs-keyword">public</span>/
    js/
        dojo/
            dojo.js
        dijit/
        dojox/
</code></pre>
<p>what we'll do here is to create a sibling to the <code>dojo</code> subdirectory, called
<code>custom&quot;</code> and create our class file there:</p>
<pre><code class="language-arduino hljs arduino" data-lang="arduino"><span class="hljs-keyword">public</span>/
    js/
        dojo/
            dojo.js
        dijit/
        dojox/
        custom/
            AutocompleteReadStore.js
</code></pre>
<p>We'll use the definition as originally shown above, and simply save it as
<code>public/js/custom/AutocompleteReadStore.js</code>, with one addition: after the
<code>dojo.provide</code> call, add this:</p>
<pre><code class="language-javascript hljs javascript" data-lang="javascript">dojo.require(<span class="hljs-string">"dojox.data.QueryReadStore"</span>);
</code></pre>
<p>This is analagous to a <code>require_once</code> call in PHP, and ensures that the class
has all dependencies prior to declaring itself. We'll leverage this fact later,
when we hint in our <code>ComboBox</code> element what type of data store to use.</p>
<p>On the framework side of things, we're going to alter our element definition
slightly to include information about the <code>dojo.data</code> store it will be using:</p>
<pre><code class="language-php hljs php" data-lang="php">$form-&gt;addElement(<span class="hljs-string">'ComboBox'</span>, <span class="hljs-string">'myAutoCompleteField'</span>, <span class="hljs-keyword">array</span>(
    <span class="hljs-string">'label'</span>     =&gt; <span class="hljs-string">'My autocomplete field:'</span>,

    <span class="hljs-comment">// The javascript identifier for the data store:</span>
    <span class="hljs-string">'storeId'</span>   =&gt; <span class="hljs-string">'autocompleter'</span>,

    <span class="hljs-comment">// The class type for the data store:</span>
    <span class="hljs-string">'storeType'</span> =&gt; <span class="hljs-string">'custom.AutocompleteReadStore'</span>,

    <span class="hljs-comment">// Parameters to use when initializint the data store:</span>
    <span class="hljs-string">'storeParams'</span> =&gt; <span class="hljs-keyword">array</span>(
        <span class="hljs-string">'url'</span>           =&gt; <span class="hljs-string">'/foo/autocomplete'</span>,
        <span class="hljs-string">'requestMethod'</span> =&gt; <span class="hljs-string">'get'</span>,
    ),
));
</code></pre>
<p>If you've been following along closely, you'll notice that the &quot;storeParams&quot;
are exactly the same as what we used to initialize the data store when
inlining. The difference is that now the <code>ComboBox</code> view helper will create all
the necessary Javascript for you.</p>
<p>The view script now becomes greatly simplified; we no longer need to setup any
javascript, and can literally simply echo the form:</p>
<pre><code class="language-php hljs php" data-lang="php"><span class="hljs-meta">&lt;?</span>= <span class="hljs-keyword">$this</span>-&gt;form <span class="hljs-meta">?&gt;</span>
</code></pre>
<p>Hopefully it should now be clear which method is easiest in the long run.</p>
<h2>Next Steps</h2>
<p><code>dojox.data.QueryReadStore</code> offers much more than simply specifying the query
string. As noted when introducing the component, it creates a JSON structure
that also includes keys for sorting, selecting how many results to display, and
offsets when pulling results. These, too, can be added to your query strings to
allow finer grained selection of results — for instance, you could ensure that
no more than 3 or 5 results are returned, to allow for a more manageable list
of matches, or specify a sort order that makes more sense to users.</p>
<h2>Summary</h2>
<p>Learning new tools can be difficult, and Dojo and Zend Framework are no
exceptions. One compelling reason to learn Dojo if you're using Zend Framework,
however, is that its structure and design should be familiar: it uses the same
1:1 class name:filename mapping paradigm. Additionally, because it is written
to utilize strong OOP principles, familiar concepts such as extending classes
can be used to customize Dojo for your site's needs.</p>
<p>Hopefully this tutorial will shed a little light on both the subject of
autocompletion in Dojo, as well as class extensions in Dojo, and help get you
started creating your own custom Dojo libraries for use with your applications.</p>


<div class="h-entry">
    <img class="u-photo photo" width="50" src="https://avatars0.githubusercontent.com/u/25943?v=3&u=79dd2ea1d4d8855944715d09ee4c86215027fa80&s=140" alt="matthew">
    <a class="u-url u-uid p-name" href="https://mwop.net/blog/198-Autocompletion-with-Zend-Framework-and-Dojo.html">Autocompletion with Zend Framework and Dojo</a> was originally
    published <time class="dt-published" datetime="2008-12-12T11:07:29-06:00">12 December 2008</time>
    on <a href="https://mwop.net">https://mwop.net</a> by
    <a rel="author" class="p-author" href="https://mwop.net">Matthew Weier O&#039;Phinney</a>.
</div>
]]></content:encoded>
      <slash:comments>0</slash:comments>
    </item>
    <item>
      <title>Tidings of the Season</title>
      <pubDate>Sat, 06 Dec 2008 18:48:16 -0600</pubDate>
      <link>https://mwop.net/blog/196-Tidings-of-the-Season.html</link>
      <guid>https://mwop.net/blog/196-Tidings-of-the-Season.html</guid>
      <author>contact@mwop.net (Matthew Weier O'Phinney)</author>
      <dc:creator>Matthew Weier O'Phinney</dc:creator>
      <content:encoded><![CDATA[<p>Just about every day, I have an idea for a blog post, and most days, by the end
of the day, I just don't have the time or energy to actually write anything up.
The inner writer in me screams, &quot;no excuses!&quot; while the aging adult in me
whispers, &quot;time for bed, dear.&quot;</p>
<p>So, to keep my hand in the game, here are a few things running through my head,
or that I'm working on, or that I'll be doing soon.</p>


<h3>Speaking at PHP Quebec</h3>
<p><img src="http://conf.phpquebec.org/img/icone/2009/2009_150x100_speakat_blue_en.gif" alt="PHP Quebec 2009" /></p>
<p>I'm speaking at PHP Quebec this coming spring, and presenting &quot;Practical Zend
Framework Jutsu with Dojo&quot;. I will be reworking the talk I did at php|works to
present new features and new techniques I've been working on for effectively
using Dojo and Zend Framework together. Hopefully my laptop and the projector
will play nice together this time!</p>
<h3>PHP Advent Calendar</h3>
<p><a href="http://shiflett.org/">Chris Shiflett</a> and <a href="http://seancoates.com">Sean Coates</a>
have generously donated some time and a domain to this year's
<a href="http://phpadvent.org/2008">PHP Advent Calendar</a>. I was invited to submit an
entry, and wrote up a piece I titled <a href="http://phpadvent.org/2008/use-responsibly-by-matthew-weier-ophinney">&quot;Use Responsibly&quot;</a>,
where I discuss good development habits when consuming open source projects.</p>
<h3>Burlington, VT PHP User's Group</h3>
<p>This week marks the one year anniversary of regular meetings of the
<a href="http://groups.google.com/group/Burlington-VT-PHP">Burlington, VT PHP User's Group</a>.
We <a href="http://groups.google.com/group/Burlington-VT-PHP/web/meeting-2008-12-04">meet this week</a>
for a special presentation from <a href="http://asynchronous.org/">Josh Sled</a> of Sun
Microsystems, on database indexing, joins and subqueries, database
optimization, and more. If you're in the area Thursday evening, come join us!</p>
<h3>Zend Framework 1.7.1</h3>
<p>Yesterday, we released <a href="http://framework.zend.com/download/latest">Zend Framework 1.7.1</a>,
the first bugfix release in the 1.7 series. Not much more to say about it,
other than start downloading!</p>
<h3>Pastebin updates</h3>
<p>I've been continuing development on the <a href="http://github.com/weierophinney/pastebin">pastebin application</a>
I developed for demonstrating Zend Framework and Dojo integration. In the past
couple weeks, I've reworked it substantially, adding support for <code>dojo.back</code> so
as to stay in the same page while utilizing the application; the results are
quite good. One side effect of this is that I've reworked and simplified the
view scripts, and added REST, JSON-RPC, and XML-RPC endpoints to simplify the
XHR infrastructure.  I'm getting pretty happy with the results…</p>
<p>…which has led me to jump to the next milestone, which is to integrate the
<a href="http://github.com/weierophinney/bugapp">bug application</a> I worked up for the Dutch
PHP Conference last summer and start creating a suite of collaborative
developer tools. These are intended to do three things: (1) demonstrate best
practices and good architecture when using Zend Framework, (2) demonstrate
appropriate techniques when using Dojo with Zend Framework, and (3) to scratch
an itch (I'd like to use these tools for my personal projects). I've code named
the project &quot;Spindle&quot;, a name I like for its rich connotations. If you're
interested in contributing, drop me a line, and I'll set you up with commit
access. Or fork it, and send me patches. Whatever.</p>
<h3>Oh, and one more thing…</h3>
<p>Ha! fooled you!</p>
<p>Seriously, though, there are, to quote something I saw on
<a href="http://twitter.com">twitter</a> today, a &quot;metric shit-ton&quot; of holidays and
observances of just about every faith and geographic origin in the coming
month. Enjoy, and best tidings of the season to you!</p>


<div class="h-entry">
    <img class="u-photo photo" width="50" src="https://avatars0.githubusercontent.com/u/25943?v=3&u=79dd2ea1d4d8855944715d09ee4c86215027fa80&s=140" alt="matthew">
    <a class="u-url u-uid p-name" href="https://mwop.net/blog/196-Tidings-of-the-Season.html">Tidings of the Season</a> was originally
    published <time class="dt-published" datetime="2008-12-02T22:07:13-06:00">2 December 2008</time>
    on <a href="https://mwop.net">https://mwop.net</a> by
    <a rel="author" class="p-author" href="https://mwop.net">Matthew Weier O&#039;Phinney</a>.
</div>
]]></content:encoded>
      <slash:comments>0</slash:comments>
    </item>
    <item>
      <title>Pastebin app updates</title>
      <pubDate>Fri, 03 Oct 2008 05:39:15 -0500</pubDate>
      <link>https://mwop.net/blog/193-Pastebin-app-updates.html</link>
      <guid>https://mwop.net/blog/193-Pastebin-app-updates.html</guid>
      <author>contact@mwop.net (Matthew Weier O'Phinney)</author>
      <dc:creator>Matthew Weier O'Phinney</dc:creator>
      <content:encoded><![CDATA[<p>I've been getting a lot of interest in my
<a href="/blog/189-Pastebin-app-and-conference-updates.html">Pastebin</a> demo app —
partly by those wanting to play with Dojo+ZF, partly by those just interested
in the application.</p>
<p>I'm constantly trying to improve the application. I've done one webinar and one
UnCon session showcasing it, and will be presenting it at
<a href="http://dojotoolkit.org/2008/07/10/dojo-developer-day-boston">Dojo Develper Day in Boston</a>
this Monday as well as at <a href="http://phpworks.mtacon.com/c/index">php|works</a> later
this fall, and want to keep the materials up-to-date and freely available. To
this end, I've created a <a href="http://github.com">Github</a> repository so you can
track the latest developments, as well as pull custom tarballs:</p>
<ul>
<li><a href="http://github.com/weierophinney/pastebin/tree/master">Pastebin on Github</a></li>
</ul>
<p>All patches and feedback are welcome!</p>




<div class="h-entry">
    <img class="u-photo photo" width="50" src="https://avatars0.githubusercontent.com/u/25943?v=3&u=79dd2ea1d4d8855944715d09ee4c86215027fa80&s=140" alt="matthew">
    <a class="u-url u-uid p-name" href="https://mwop.net/blog/193-Pastebin-app-updates.html">Pastebin app updates</a> was originally
    published <time class="dt-published" datetime="2008-09-27T14:14:59-05:00">27 September 2008</time>
    on <a href="https://mwop.net">https://mwop.net</a> by
    <a rel="author" class="p-author" href="https://mwop.net">Matthew Weier O&#039;Phinney</a>.
</div>
]]></content:encoded>
      <slash:comments>0</slash:comments>
    </item>
    <item>
      <title>ZendCon08 Wrapup</title>
      <pubDate>Sat, 27 Sep 2008 12:06:11 -0500</pubDate>
      <link>https://mwop.net/blog/192-ZendCon08-Wrapup.html</link>
      <guid>https://mwop.net/blog/192-ZendCon08-Wrapup.html</guid>
      <author>contact@mwop.net (Matthew Weier O'Phinney)</author>
      <dc:creator>Matthew Weier O'Phinney</dc:creator>
      <content:encoded><![CDATA[<p>I'm a bit late on my <a href="http://www.zendcon.com/">ZendCon'08</a> wrapup; the
conference left me both exhausted and with a backlog of email and work that has
consumed me since it ended. However, this, too, is good, as it has given me
time to reflect… and to finally get my slides up on SlideShare.</p>
<p>ZendCon was alternately exhausting, rewarding, educational, fruitful,
infurating, and ultimately wonderful. I've been to every single ZendCon so far
— I started at Zend a scant month before the inaugural event — and have spoken
at each. My first time speaking was a fluke; <a href="http://www.sklar.com/">David Sklar</a>
had just started at <a href="http://www.ning.com/">Ning</a> and had to back out of his
&quot;Configuring PHP&quot; tutorial session. <a href="http://mikenaberezny.com/">Mike Naberezny</a>
and I were drafted to take it over, and we had N+1 attendees, where N was the
number of speakers. Since that inauspicious beginning, I've gradually taken on
more sessions and stuck around to participate in the conference more. I can
honestly say that this was the biggest, busiest, and most community focussed
ZendCon I can remember.</p>


<p>This year, I was involved in a marathon seven — yes, that's right, seven —
sessions over three days, and only finally got the last day off.
<a href="http://mikenaberezny.com/">Mike</a> and I did our
<a href="http://www.slideshare.net/weierophinney/best-practices-of-php-development-presentation/">Best Practices tutorial session</a>
on Monday, which was very well attended. Based on the numbers of people raising
their hands as we asked if they were implementing or familiar with the various
practices we enumerated, we may be able to begin doing more advanced, in-depth
sessions in the future.</p>
<p>On Tuesday, <a href="http://inside.e-novative.de/">Stefan Priebsch</a> <del>roped me into</del>
convinced me to help with a &quot;round table&quot; UnConference session on the role of
ORMs in PHP. The consensus we had was that ORM tools are quite good for
prototyping and rapid development, but that any good ORM solution should
de-couple the data access layer to allow stubbing with well-tuned SQL when
performance becomes a consideration.</p>
<p>Later that morning, I did a presentation on <a href="http://www.slideshare.net/weierophinney/getting-started-with-zend-framework-presentation/">Getting Started with Zend Framework</a>.
I developed this presentation to follow our newly re-launched
<a href="http://framework.zend.com/docs/quickstart">Quick Start</a>. The talk was very well
attended, and I received some excellent questions from attendees following the
talk. I hope to streamline it in the future so it can be presented as a
screencast or webinar. If you are interested in the material, I suggest heading
to the link above and downloading the quick start materials; they are
well-documented and will cover at least as much as I covered in the talk.</p>
<p>In the afternoon, I did another unconference session, this time performing my
<a href="http://www.slideshare.net/weierophinney/rich-uis-and-easy-remoting-with-dojo-and-zend-framework-presentation/">Rich UIs and Easy XHR with Dojo and Zend Framework</a>
talk. (Did I mention that conference attendees could not seem to get enough
Zend Framework material?) I really enjoyed doing this talk <em>live</em> this time
(I've done it previously for a webinar) — I received some wonderful questions,
but even better, I was able to gauge the audience reactions to what I was
presenting. I was pleased to see people getting as excited about Dojo as I've
become, and I hope to see that enthusiasm grow. Dojo is truly a fantastic
choice when it comes to javascript toolkits, and I think I suitably
demonstrated how easy it is to use Dojo now from Zend Framework.</p>
<p>Tuesday afternoon, I presented my session on
<a href="http://www.slideshare.net/weierophinney/zendform-presentation/">Zend_Form</a>.
We'd originally planned to do a talk on <code>Zend_Layout</code> and <code>Zend_Form</code>, but
there's at least two hours of material there that simply does not condense to 1
hour. Instead, we had Ralph present a session on <code>Zend_Layout</code> during an
UnConference session, while I focussed on <code>Zend_Form</code>. Again, it was fun to do
this in front of a live audience — albeit one I could barely see from my perch
on the mainstage. I saw some places to trim for next time — which will allow me
to show off <code>Zend_Dojo</code> integration with <code>Zend_Form</code> in the future.</p>
<p>Immediately following that, I headed off to do yet another UnConference session
with <a href="http://lornajane.net/">Lorna Jane</a>. <a href="http://caseysoftware.com/blog">Keith Casey</a>
had approached me on Monday following the tutorial Mike and I presented,
indicating that there were requests for an &quot;svn tips and tricks&quot; presentation
for the UnCon. I told him to ask Lorna Jane if she'd be interested, as I'd seen
her do an excellent presentation on the subject at the Dutch PHP Conference in
June. After some back and forth, we decided to do it together, and sketched out
a rough outline early Wednesday morning. The talk was very well attended, and
again had great audience participation. Doing the presentation has inspired us
to consider submitting a joint proposal for a conference in the future.</p>
<p>I quickly ran downstairs, only to find I was immediately wanted for a &quot;Meet the
Team&quot; session. This has become a staple at ZendCon, and has had led to some…
interesting… interchanges in the past. This year, the session was packed, and
we had some very good discussions touching on every Zend product — from Zend
Framework to Zend Platform. There were certainly some hecklers, but all of it
was in good fun, and we had a brilliant time. (Man, I think hanging with the UK
folk has worn off on my vocabulary.)</p>
<p>I actually attended fewer sessions than I was involved in, which was unusual
and strange. Every one I was able to attend was quite good. Standouts for me
include Jay Pipes' tutorial on Join Foo, which raised many questions for me and
sparked a number of discussion points all week. Additionally, I was delighted
to be able to attend Alex Russell's Dojo talk; I've exchanged dozens of emails
with him over the past months while doing the ZF/Dojo integration, and it was
fascinating to hear his summary of the state of HTML and browser support, as
well as how he feels Dojo fits in the ecosystem. I was fortunate enough to be
able to grab him afterwards so we could have lunch and talk shop — and got an
even larger surprise to discover he was not only familiar with all aspects of
the Dojo support I'd done, but had used much of it!</p>
<p>Being as busy as I was, I didn't have much chance to stop and enjoy the
community until Wednesday evening. And the community is quite vibrant! I have
often been behind in my slide preparations or tied up in meetings and unable to
&quot;join the fun&quot; that often marks good PHP events. This time, I felt quite tapped
into the community, as well as welcomed by all. I had innumerable
conversations, both with people wholly unfamiliar to me, people I've seen
yearly at ZendCon, and people I've been &quot;seeing&quot; virtually on IRC and the
mailing lists. The strength of any open source project is only as good as the
community it attracts, and on this basis alone, PHP is thriving.</p>
<p>So, goodbye, ZendCon08 and all my new and old friends — let's hope we can meet
again next year!</p>


<div class="h-entry">
    <img class="u-photo photo" width="50" src="https://avatars0.githubusercontent.com/u/25943?v=3&u=79dd2ea1d4d8855944715d09ee4c86215027fa80&s=140" alt="matthew">
    <a class="u-url u-uid p-name" href="https://mwop.net/blog/192-ZendCon08-Wrapup.html">ZendCon08 Wrapup</a> was originally
    published <time class="dt-published" datetime="2008-09-25T23:11:30-05:00">25 September 2008</time>
    on <a href="https://mwop.net">https://mwop.net</a> by
    <a rel="author" class="p-author" href="https://mwop.net">Matthew Weier O&#039;Phinney</a>.
</div>
]]></content:encoded>
      <slash:comments>0</slash:comments>
    </item>
    <item>
      <title>Pastebin app and conference updates</title>
      <pubDate>Tue, 16 Sep 2008 01:15:30 -0500</pubDate>
      <link>https://mwop.net/blog/189-Pastebin-app-and-conference-updates.html</link>
      <guid>https://mwop.net/blog/189-Pastebin-app-and-conference-updates.html</guid>
      <author>contact@mwop.net (Matthew Weier O'Phinney)</author>
      <dc:creator>Matthew Weier O'Phinney</dc:creator>
      <content:encoded><![CDATA[<p>I have a number of updates and followups, and decided to post them in a single
entry.</p>
<p>First off, you may now <a href="http://www.zend.com/en/webinar/Framework-Dojo/Webinar-Rec-Framework-Dev-EN-ZFDojo-20080903.flv">view my Dojo Webinar online</a>
(requires login and registration at zend.com). Attendance was phenomenal, and
I've had some really good feedback. If you want to see it live, I'm giving the
talk (with revisions!) at the <a href="http://www.zendcon.com/">ZendCon</a> UnConference,
at <a href="http://dojotoolkit.org/2008/07/10/dojo-developer-day-boston">Dojo Developer Day Boston</a>
later this month, and at <a href="http://phpworks.mtacon.com/c/schedule/talk/d1s5/1">php|works</a> in
November. I hope to be able to show new functionality at each presentation.</p>
<p>Second, I've completed what I'm calling version 1.0.0 of the pastebin
application I demo'd in the webinar. The PHP code is fully unit tested (though
I haven't yet delved into using DOH! to test the JS), and incorporates a number
of best practices and tips that Pete Higgins from Dojo was kind enough to
provide to me. When using a custom build (and I provide a profile for building
one), it simply flies.</p>
<ul>
<li><a href="/uploads/pastebin-1.0.0.tar.gz">Download the pastebin application</a></li>
</ul>
<p>The pastebin application showcases a number of features besides Dojo:
<code>Zend_Test_PHPUnit</code> was used to test the application, and <code>Zend_Wildfire</code>'s
FireBug logger and DB profiler are used to provide profiling and debug
information.</p>
<p>Finally, <a href="http://www.zendcon.com/">ZendCon</a> is next week! I'll be around, but
already have a packed schedule (1 tutorial, 2 regular sessions, an UnCon
session, a meet-the-developers session… and that's just what I know about!).
I look forward to meeting ZF users and developers, though, so feel free to grab
me and introduce yourself.</p>




<div class="h-entry">
    <img class="u-photo photo" width="50" src="https://avatars0.githubusercontent.com/u/25943?v=3&u=79dd2ea1d4d8855944715d09ee4c86215027fa80&s=140" alt="matthew">
    <a class="u-url u-uid p-name" href="https://mwop.net/blog/189-Pastebin-app-and-conference-updates.html">Pastebin app and conference updates</a> was originally
    published <time class="dt-published" datetime="2008-09-09T10:19:23-05:00">9 September 2008</time>
    on <a href="https://mwop.net">https://mwop.net</a> by
    <a rel="author" class="p-author" href="https://mwop.net">Matthew Weier O&#039;Phinney</a>.
</div>
]]></content:encoded>
      <slash:comments>0</slash:comments>
    </item>
    <item>
      <title>Proper Layer files when using Dojo with Zend Framework</title>
      <pubDate>Mon, 08 Sep 2008 09:17:34 -0500</pubDate>
      <link>https://mwop.net/blog/188-Proper-Layer-files-when-using-Dojo-with-Zend-Framework.html</link>
      <guid>https://mwop.net/blog/188-Proper-Layer-files-when-using-Dojo-with-Zend-Framework.html</guid>
      <author>contact@mwop.net (Matthew Weier O'Phinney)</author>
      <dc:creator>Matthew Weier O'Phinney</dc:creator>
      <content:encoded><![CDATA[<p>During my <a href="http://www.zend.com/en/resources/webinars/framework">Dojo and ZF webinar</a> on Wednesday,
<a href="http://higginsforpresident.net/">Pete Higgins</a> of
<a href="http://dojotoolkit.org/">Dojo</a> fame noted that I could do something different
and better on one of my slides.</p>
<p>This particular item had to do with how I was consuming custom Dojo build
layers within my code. I contacted him afterwards to find out what he
suggested, and did a little playing of my own, and discovered some more Dojo
and javascript beauty in the process.</p>


<p>The code in question looked like this:</p>
<pre><code class="language-php hljs php" data-lang="php">Zend_Dojo::enableView($view);
$view-&gt;dojo()-&gt;setDjConfigOption(<span class="hljs-string">'usePlainJson'</span>, <span class="hljs-keyword">true</span>)
             <span class="hljs-comment">// -&gt;setDjConfigOption('isDebug', true)</span>
             -&gt;addStylesheetModule(<span class="hljs-string">'dijit.themes.tundra'</span>)
             -&gt;addStylesheet(<span class="hljs-string">'/js/dojox/grid/_grid/tundraGrid.css'</span>)
             -&gt;setLocalPath(<span class="hljs-string">'/js/dojo/dojo.js'</span>)
             -&gt;addLayer(<span class="hljs-string">'/js/paste/main.js'</span>)
             <span class="hljs-comment">// -&gt;addLayer('/js/paste/paste.js')</span>
             -&gt;registerModulePath(<span class="hljs-string">'../paste'</span>, <span class="hljs-string">'paste'</span>)
             -&gt;addJavascript(<span class="hljs-string">'paste.main.init();'</span>)
             -&gt;disable();
</code></pre>
<p>The lines he was commenting on were the <code>addLayer()</code> lines.</p>
<p>As noted in my webinar, layers, or custom builds, are a fantastic feature of
Dojo. Dojo is incredibly modular, and acts in many ways like a good server-side
library should — only include what is needed, and when its needed. The problem
comes at deployment: the user suddenly experiences a situation where the
application is making dozens of requests back to the server to get what it
needs. The solution is to create a custom build, which pulls in all
dependencies into a single file, inters any templates, and then does
minification heuristics on the code prior to stripping all whitespace and
compressing it. Once done, you now have a single, small file that needs to load
on the request — making the final deployed application snappy.</p>
<p>When I displayed this during the webinar, I noted that after doing so, you have
to change your code to point at the new build — and that's what the two lines
I pointed out are for. In essence, one is for development, the other for
production. Of course, this is just ripe for problems — you forget to switch
comments in production, or accidently re-merge the development version, etc.</p>
<p>Pete showed me another solution that was much more elegant, and which also got
rid of another line in that solution above, the <code>addJavascript()</code></p>
<p>The solution is to write your code in the same layer file as you'll compile to.
When doing so, you can put all your <code>dojo.require()</code> statements in the file, as
well as mixin any code you want in the main module namespace:</p>
<pre><code class="language-javascript hljs javascript" data-lang="javascript">dojo.provide(<span class="hljs-string">"paste.layer"</span>);

<span class="hljs-comment">/* Dojo modules to require... */</span>
dojo.require(<span class="hljs-string">"dijit.layout.ContentPane"</span>);
<span class="hljs-comment">/* ... */</span>

<span class="hljs-comment">/* onLoad actions to perform... */</span>
dojo.addOnLoad(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
    paste.upgrade(); 
});

<span class="hljs-comment">/* mixin functionality to the "paste" namespace: */</span>
dojo.mixin(paste, {
    <span class="hljs-comment">/* paste.newPasteButton() */</span>
    <span class="hljs-attr">newPasteButton</span>:  <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-keyword">var</span> form = dijit.byId(<span class="hljs-string">"pasteform"</span>);
        <span class="hljs-keyword">if</span> (form.isValid()) {
            form.submit(); 
        }
    },
    
    <span class="hljs-comment">/* ... */</span>
});
</code></pre>
<p>In my original code, I had a <code>paste.main.init</code> method that performed all my
<code>dojo.require</code> and <code>dojo.addOnLoad</code> statements, but these now can be simply a
part of the layer — eliminating more work for me.</p>
<p>Then, when creating the profile, you simply have it create the layer in the
same file — in this case, <code>paste/layer.js</code> — but also have it create a
<em>dependency</em> on the original layer file. The compiler will ensure that the
original code gets slurped into the build. As an example:</p>
<pre><code class="language-javascript hljs javascript" data-lang="javascript">dependencies = {
    <span class="hljs-attr">layers</span>: [
        {
            <span class="hljs-attr">name</span>: <span class="hljs-string">"../paste/layer.js"</span>,
            <span class="hljs-attr">dependencies</span>: [
                <span class="hljs-string">"paste.layer"</span>,
                <span class="hljs-comment">/* other dependencies...*/</span>
            ]
        },
    ],
    <span class="hljs-attr">prefixes</span>: [
        [ <span class="hljs-string">"paste"</span>, <span class="hljs-string">"../paste"</span> ],
        <span class="hljs-comment">/* other prefixes -- dijit, etc. */</span>
    ]
}
</code></pre>
<p>This changes the original ZF snippet above to simply:</p>
<pre><code class="language-php hljs php" data-lang="php">Zend_Dojo::enableView($view);
$view-&gt;dojo()-&gt;setDjConfigOption(<span class="hljs-string">'usePlainJson'</span>, <span class="hljs-keyword">true</span>)
             <span class="hljs-comment">// -&gt;setDjConfigOption('isDebug', true)</span>
             -&gt;addStylesheetModule(<span class="hljs-string">'dijit.themes.tundra'</span>)
             -&gt;addStylesheet(<span class="hljs-string">'/js/dojox/grid/_grid/tundraGrid.css'</span>)
             -&gt;setLocalPath(<span class="hljs-string">'/js/dojo/dojo.js'</span>)
             -&gt;addLayer(<span class="hljs-string">'/js/paste/layer.js'</span>)
             -&gt;registerModulePath(<span class="hljs-string">'../paste'</span>, <span class="hljs-string">'paste'</span>)
             -&gt;disable();
</code></pre>
<p>Not much shorter — but because I no longer need to worry about changing the
file name, I can rest easier at night.</p>
<p>I'll be blogging more tips such as these in the coming weeks, to help support
the new <a href="http://framework.zend.com/announcements/2008-09-03-dojo">Dojo integration</a>
in Zend Framework.</p>


<div class="h-entry">
    <img class="u-photo photo" width="50" src="https://avatars0.githubusercontent.com/u/25943?v=3&u=79dd2ea1d4d8855944715d09ee4c86215027fa80&s=140" alt="matthew">
    <a class="u-url u-uid p-name" href="https://mwop.net/blog/188-Proper-Layer-files-when-using-Dojo-with-Zend-Framework.html">Proper Layer files when using Dojo with Zend Framework</a> was originally
    published <time class="dt-published" datetime="2008-09-05T09:30:00-05:00">5 September 2008</time>
    on <a href="https://mwop.net">https://mwop.net</a> by
    <a rel="author" class="p-author" href="https://mwop.net">Matthew Weier O&#039;Phinney</a>.
</div>
]]></content:encoded>
      <slash:comments>0</slash:comments>
    </item>
  </channel>
</rss>
