<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title type="text">Blog entries tagged dojo :: mwop.net</title>
  <updated>2009-02-23T08:17:00-06:00</updated>
  <generator uri="https://getlaminas.org" version="2">Laminas_Feed_Writer</generator>
  <link rel="alternate" type="text/html" href="https://mwop.net/blog/tag/dojo"/>
  <link rel="self" type="application/atom+xml" href="https://mwop.net/blog/tag/dojo/atom.xml"/>
  <id>https://mwop.net/blog/tag/dojo</id>
  <entry xmlns:xhtml="http://www.w3.org/1999/xhtml">
    <title type="html"><![CDATA[Recursively Destroying Dojo ContentPanes]]></title>
    <published>2009-02-23T08:17:00-06:00</published>
    <updated>2009-02-23T08:17:00-06:00</updated>
    <link rel="alternate" type="text/html" href="https://mwop.net/blog/208-Recursively-Destroying-Dojo-ContentPanes.html"/>
    <id>https://mwop.net/blog/208-Recursively-Destroying-Dojo-ContentPanes.html</id>
    <author>
      <name>Matthew Weier O'Phinney</name>
      <email>contact@mwop.net</email>
      <uri>https://mwop.net</uri>
    </author>
    <content xmlns:xhtml="http://www.w3.org/1999/xhtml" type="xhtml">
      <xhtml:div xmlns:xhtml="http://www.w3.org/1999/xhtml"><xhtml: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.</xhtml:p>
<xhtml:p>Most Dijits have a <xhtml:code>destroyRecursive()</xhtml: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.</xhtml:p>
<xhtml:p>ContentPanes fall into this latter category. fortunately, it's
relatively easy to accomplish, due to Dojo's heavily object
oriented nature.</xhtml:p>
<xhtml:pre><xhtml:code class="language-javascript hljs javascript" data-lang="javascript">dojo.provide(\<xhtml: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);
    }
});
</xhtml:span></xhtml:code></xhtml:pre>
<xhtml:p>The <xhtml:code>destroyRecursive()</xhtml:code> method is not that different
from the one in <xhtml:code>dijit._Widget</xhtml:code>; the difference is that
instead of calling simply <xhtml:code>destroy()</xhtml:code> on any discovered
widgets, we destroy recursively.</xhtml:p>
<xhtml:p>The <xhtml:code>postMixInProperties</xhtml: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.
<xhtml:code>postMixInProperties()</xhtml:code> checks to see if the dijit ID is
still around, and if so, destroys it recursively. This allows the
ContentPane initialization to proceed.</xhtml:p>
<xhtml:div class="h-entry"><xhtml:img class="u-photo photo" width="50" src="https://avatars0.githubusercontent.com/u/25943?v=3&amp;u=79dd2ea1d4d8855944715d09ee4c86215027fa80&amp;s=140" alt="matthew"/> <xhtml:a class="u-url u-uid p-name" href="https://mwop.net/blog/208-Recursively-Destroying-Dojo-ContentPanes.html">
Recursively Destroying Dojo ContentPanes</xhtml:a> was originally
published <xhtml:time class="dt-published" datetime="2009-02-23T08:17:00-06:00">23 February 2009</xhtml:time> on <xhtml:a href="https://mwop.net">https://mwop.net</xhtml:a> by <xhtml:a rel="author" class="p-author" href="https://mwop.net">Matthew Weier
O'Phinney</xhtml:a>.</xhtml:div>
</xhtml:div>
    </content>
  </entry>
  <entry xmlns:xhtml="http://www.w3.org/1999/xhtml">
    <title type="html"><![CDATA[Using JSLint]]></title>
    <published>2009-02-20T08:11:41-06:00</published>
    <updated>2009-02-20T08:11:41-06:00</updated>
    <link rel="alternate" type="text/html" href="https://mwop.net/blog/207-Using-JSLint.html"/>
    <id>https://mwop.net/blog/207-Using-JSLint.html</id>
    <author>
      <name>Matthew Weier O'Phinney</name>
      <email>contact@mwop.net</email>
      <uri>https://mwop.net</uri>
    </author>
    <content xmlns:xhtml="http://www.w3.org/1999/xhtml" type="xhtml">
      <xhtml:div xmlns:xhtml="http://www.w3.org/1999/xhtml"><xhtml:p>I've been doing a fair bit of programming in <xhtml:a href="http://dojotoolkit.org/">Dojo</xhtml: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.</xhtml:p>
<xhtml:p>Fortunately, there's a tool for lazy developers like myself:
<xhtml:a href="http://jslint.com">JSLint</xhtml: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.</xhtml:p>
<xhtml: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.</xhtml:p>
<xhtml:p>To get JSLint running on the command line using the Rhino
shipped with Dojo, you'll need to download the following file:</xhtml:p>
<xhtml:ul>
<xhtml:li><xhtml:a href="http://jslint.com/rhino/jslint.js">jslint.js</xhtml:a></xhtml:li>
</xhtml:ul>
<xhtml:p>Put these files in a directory of your choosing. Then, create a
file called <xhtml:code>jslint</xhtml:code>, with the following:</xhtml:p>
<xhtml:pre><xhtml:code class="language-bash hljs bash" data-lang="bash"><xhtml:span class="hljs-meta">#!/bin/sh</xhtml:span>
<xhtml:span class="hljs-built_in">exec</xhtml:span> java \
-jar /path/to/dojo/util/shrinksafe/custom_rhino.jar \
/path/to/jslint.js <xhtml:span class="hljs-variable">$1</xhtml:span>
</xhtml:code></xhtml:pre>
<xhtml:p>Note: you'll need to put in the correct paths to your Dojo
installation as well as to where you placed the
<xhtml:code>jslint.js</xhtml:code> file.</xhtml:p>
<xhtml:p>Make that file executable, and put it somewhere on your path.
Once you do, you can invoke it quite simply:</xhtml:p>
<xhtml:pre><xhtml:code class="language-bash hljs bash" data-lang="bash">$ jslint foo.js
</xhtml:code></xhtml:pre>
<xhtml: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:</xhtml:p>
<xhtml:pre><xhtml:code class="language-bash hljs bash" data-lang="bash">$ <xhtml:span class="hljs-keyword">for</xhtml:span> f <xhtml:span class="hljs-keyword">in</xhtml:span> *.js;<xhtml:span class="hljs-keyword">do</xhtml:span> jslint <xhtml:span class="hljs-variable">$f</xhtml:span>;<xhtml:span class="hljs-keyword">done</xhtml:span>
</xhtml:code></xhtml:pre>
<xhtml: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.</xhtml:p>
<xhtml:div class="h-entry"><xhtml:img class="u-photo photo" width="50" src="https://avatars0.githubusercontent.com/u/25943?v=3&amp;u=79dd2ea1d4d8855944715d09ee4c86215027fa80&amp;s=140" alt="matthew"/> <xhtml:a class="u-url u-uid p-name" href="https://mwop.net/blog/207-Using-JSLint.html">Using JSLint</xhtml:a> was
originally published <xhtml:time class="dt-published" datetime="2009-02-20T08:11:41-06:00">20 February 2009</xhtml:time> on <xhtml:a href="https://mwop.net">https://mwop.net</xhtml:a> by <xhtml:a rel="author" class="p-author" href="https://mwop.net">Matthew Weier
O'Phinney</xhtml:a>.</xhtml:div>
</xhtml:div>
    </content>
  </entry>
  <entry xmlns:xhtml="http://www.w3.org/1999/xhtml">
    <title type="html"><![CDATA[2008: The year in review]]></title>
    <published>2008-12-31T14:17:03-06:00</published>
    <updated>2009-01-05T02:00:49-06:00</updated>
    <link rel="alternate" type="text/html" href="https://mwop.net/blog/203-2008-The-year-in-review.html"/>
    <id>https://mwop.net/blog/203-2008-The-year-in-review.html</id>
    <author>
      <name>Matthew Weier O'Phinney</name>
      <email>contact@mwop.net</email>
      <uri>https://mwop.net</uri>
    </author>
    <content xmlns:xhtml="http://www.w3.org/1999/xhtml" type="xhtml">
      <xhtml:div xmlns:xhtml="http://www.w3.org/1999/xhtml"><xhtml: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.</xhtml:p>
<xhtml:p>The short, executive summary:</xhtml:p>
<xhtml:ul>
<xhtml:li>One trip to Israel</xhtml:li>
<xhtml:li>One trip to The Netherlands</xhtml:li>
<xhtml:li>One trip to California's Bay Area</xhtml:li>
<xhtml:li>One trip to Atlanta, GA</xhtml:li>
<xhtml:li>Three minor releases of Zend Framework</xhtml:li>
<xhtml:li>Seven webinars, six for zend.com and one for Adobe</xhtml:li>
<xhtml:li>Three conferences attended as a speaker, including:
<xhtml:ul>
<xhtml:li>One six-hour workshop</xhtml:li>
<xhtml:li>One three-hour tutorial (as a co-presenter)</xhtml:li>
<xhtml:li>Four regular sessions</xhtml:li>
<xhtml:li>Two panel sessions (one scheduled, one for an uncon)</xhtml:li>
<xhtml:li>Two uncon sessions (one as a co-presenter)</xhtml:li>
<xhtml:li>One foul-mouthed Pecha Kucha talk</xhtml:li>
</xhtml:ul>
</xhtml:li>
<xhtml:li>Ten Burlington, VT PHP User's Group meetings attended; I spoke
at many</xhtml:li>
<xhtml:li>One Bug Hunt week organized</xhtml:li>
<xhtml:li>Two books reviewed as a technical editor</xhtml:li>
<xhtml:li>Six articles for <xhtml:a href="http://devzone.zend.com/">DevZone</xhtml:a></xhtml:li>
<xhtml:li>50 blog entries (including this one)</xhtml:li>
</xhtml:ul>
<xhtml:p>Read on for the gruesome, month-by-month breakdown.</xhtml:p>
<xhtml:h2>January and February</xhtml:h2>
<xhtml:p>I started coding <xhtml:code>Zend_Form</xhtml: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.</xhtml:p>
<xhtml:p>I also answered many questions for and had many discussions with
<xhtml:a href="http://www.calevans.com/">Cal Evans</xhtml:a> relating to his
"Guide to Programming Zend Framework".</xhtml:p>
<xhtml:h2>March</xhtml:h2>
<xhtml:p>I gave my first webinar of the year early in March, on the
subject of <xhtml:code>Zend_Form</xhtml: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.</xhtml:p>
<xhtml:p>While working towards the 1.5.0 release, <xhtml:a href="http://ralphschindler.com/">Ralph Schindler</xhtml:a> and I also
finished up final touches on <xhtml:code>Zend_Layout</xhtml:code> and the
various "placeholder" view helper implementations.</xhtml:p>
<xhtml:p>On 17 March 2008, we released Zend Framework 1.5, our first
minor release following 1.0.0.</xhtml:p>
<xhtml:p>I started blogging tips and tricks for 1.5, and also writing
articles for <xhtml:a href="http://devzone.zend.com/">DevZone</xhtml:a> during
March, and had tremendous amounts of feedback. In fact, one blog
post, on "Login and Authentication", is still one of the most
trafficked on my blog after 9 months.</xhtml:p>
<xhtml:p>I also began what I envisioned as a series of Vim posts, but,
alas, it has resulted only in two.</xhtml:p>
<xhtml:h2>April</xhtml:h2>
<xhtml: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.</xhtml:p>
<xhtml:h2>May</xhtml:h2>
<xhtml:p>At the beginning of the month, I released the last in my series
of 1.5 tutorials on <xhtml:a href="http://devzone.zend.com/">DevZone</xhtml:a>,
covering Form decorators. This has saved me countless hours on IRC
and in the mailing lists explaining how this aspect of forms
work.</xhtml:p>
<xhtml:p>During this month, we also finally announced that Zend Framework
would be partnering with <xhtml:a href="http://dojotoolkit.org/">Dojo</xhtml: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.</xhtml:p>
<xhtml:p>At the end of the month, the ZF team reorganized the subversion
repository to allow for an "Extras" 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!</xhtml:p>
<xhtml:h2>June</xhtml:h2>
<xhtml:p>I started June with a trip to Israel, to visit the Zend offices.
I met up with <xhtml:a href="http://andigutmans.blogspot.com/">Andi</xhtml: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.</xhtml:p>
<xhtml:p>Four days after returning from Israel, I flew to Amsterdam for
the <xhtml:a href="http://www.phpconference.nl">Dutch PHP Conference</xhtml:a>,
to which I'd been invited to speak. My good friend <xhtml:a href="http://wolerized.com/">Remi</xhtml: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. <xhtml:a href="http://www.leftontheweb.com/">Stefan Koopmanschap</xhtml: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 <xhtml:a href="http://www.priebsch.de/">Stefan Priebsch</xhtml:a>, <xhtml:a href="http://www.lornajane.net/">Lorna Jane Mitchell</xhtml:a>, <xhtml:a href="http://andries.systray.be/">Andries Seutens</xhtml:a>, and many, many
more — plus many familiar faces, such as Sebastian Bergmann, Derek
Rethans, Mike Van Dam, Felix de Vliegher, and Marco Tabini.</xhtml:p>
<xhtml: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.</xhtml:p>
<xhtml: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 <xhtml:a href="http://higginsforpresident.net/">Pete Higgins</xhtml:a>), and preparing
<xhtml:code>Zend_Test_PHPUnit</xhtml:code> for inclusion in Zend Framework
1.6.</xhtml:p>
<xhtml:h2>July</xhtml:h2>
<xhtml:p>I think I'll remember July as the month of the neverending
release cycle.</xhtml:p>
<xhtml:h2>August</xhtml:h2>
<xhtml: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.</xhtml:p>
<xhtml:p>The following Monday, we released the second release candidate
of Zend Framework 1.6.0.</xhtml:p>
<xhtml:p>August, too, became part of the month of the neverending release
cycle.</xhtml:p>
<xhtml:h2>September</xhtml:h2>
<xhtml: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.</xhtml:p>
<xhtml: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.</xhtml:p>
<xhtml: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 <xhtml:em>community</xhtml:em> following, including <xhtml:a href="http://www.bombdiggity.net/">Jon Whitcraft</xhtml:a>, <xhtml:a href="http://akrabat.com/">Rob Allen</xhtml:a>, the <xhtml:a href="http://ibuildings.nl/">ibuildings</xhtml:a> crew, and more.</xhtml:p>
<xhtml:p>I also finally got to meet <xhtml:a href="http://sklar.com/">David
Sklar</xhtml:a>, to whom I owe the fact of my first public speaking
engagement at the first ZendCon.</xhtml:p>
<xhtml: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.</xhtml:p>
<xhtml:h2>October</xhtml:h2>
<xhtml:p>I helped <xhtml:a href="http://wadearnold.com/blog/">Wade Arnold</xhtml:a>
complete testing of <xhtml:code>Zend_Amf</xhtml:code> as we prepared for the
Zend Framework 1.7.0 release, and learned a fair deal about Flex in
the process.</xhtml:p>
<xhtml:p>During this time, I also completed a technical review of
<xhtml:a href="http://zendframeworkinaction.com">Zend Framework in
Action</xhtml: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.</xhtml:p>
<xhtml:p>For the 1.7 release of Zend Framework, I worked on performance
benchmarking, profiling, improvements, and a best practices
guide.</xhtml:p>
<xhtml:p>Late in the month, I delivered a webinar with Lee Brimelow for
Adobe to showcase the upcoming AMF support in Zend Framework.</xhtml:p>
<xhtml:h2>November</xhtml:h2>
<xhtml:p>The last few days of October and first week of November, I
organized a bug hunt week for Zend Framework, culminating in a
<xhtml:a href="http://bughuntday.org/">Bug Hunt Day</xhtml:a> event held and
organized by <xhtml:a href="http://www.phpbelgium.be/">PHP Belgium</xhtml:a>
and <xhtml:a href="http://phpgg.nl/">phpGG</xhtml: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.</xhtml:p>
<xhtml:p>The second week of November, I flew down to Atlanta, GA, to
attend <xhtml:a href="http://phpworks.mtacon.com/">php|works</xhtml:a>.. err,
php|works/pyworks. First off, a huge thank you to <xhtml:a href="http://naramore.net/blog/">Elizabeth Naramore</xhtml: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.</xhtml:p>
<xhtml:p>I also presented a <xhtml:a href="http://en.wikipedia.org/wiki/Pecha_Kucha">Pecha Kucha</xhtml:a> talk — I
re-branded the phrase as "Pikachu" a couple weeks earlier (a
reference to the iconic character in <xhtml:a href="http://www.pokemon.com/">Pokemon</xhtml: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.</xhtml:p>
<xhtml:p>I got to see a ton of old and new friends alike while there —
former Zenders <xhtml:a href="http://mikenaberezny.com/">Mike
Naberezny</xhtml:a> and <xhtml:a href="http://paul-m-jones.com/">Paul M.
Jones</xhtml:a>, <xhtml:a href="http://caseysoftware.com/blog/">Keith
Casey</xhtml:a>, <xhtml:a href="http://ishouldbecoding.com/">Matthew
Turland</xhtml:a>, <xhtml:a href="http://jansch.nl/">Ivo</xhtml: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
<xhtml:em>you</xhtml:em> are the reason I code.</xhtml:p>
<xhtml: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.
<xhtml:code>Zend_Amf</xhtml: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
<xhtml:a href="http://jquery.com/">JQuery</xhtml:a> support.</xhtml:p>
<xhtml:h2>December</xhtml:h2>
<xhtml:p><xhtml:a href="http://shiflett.org/">Chris Shiflett</xhtml:a> and <xhtml:a href="http://seancoates.com/">Sean Coates</xhtml:a> organized this year's
<xhtml:a href="http://phpadvent.org/2008/">PHP Advent Calendar</xhtml: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.</xhtml:p>
<xhtml: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 "backlog" 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.</xhtml:p>
<xhtml:h2>Reflection</xhtml:h2>
<xhtml: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.</xhtml:p>
<xhtml: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.</xhtml:p>
<xhtml:h2>Looking ahead to 2009</xhtml:h2>
<xhtml: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.</xhtml:p>
<xhtml:p>I hope this post finds <xhtml:em>you</xhtml:em> in good health and spirits,
and that you have a fantastic start to the new year!</xhtml:p>
<xhtml:div class="h-entry"><xhtml:img class="u-photo photo" width="50" src="https://avatars0.githubusercontent.com/u/25943?v=3&amp;u=79dd2ea1d4d8855944715d09ee4c86215027fa80&amp;s=140" alt="matthew"/> <xhtml: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</xhtml:a> was originally published <xhtml:time class="dt-published" datetime="2008-12-31T14:17:03-06:00">31 December
2008</xhtml:time> on <xhtml:a href="https://mwop.net">https://mwop.net</xhtml:a> by
<xhtml:a rel="author" class="p-author" href="https://mwop.net">Matthew
Weier O'Phinney</xhtml:a>.</xhtml:div>
</xhtml:div>
    </content>
  </entry>
  <entry xmlns:xhtml="http://www.w3.org/1999/xhtml">
    <title type="html"><![CDATA[A Simple PHP Publish-Subscribe System]]></title>
    <published>2008-12-15T10:26:00-06:00</published>
    <updated>2008-12-31T07:05:35-06:00</updated>
    <link rel="alternate" type="text/html" href="https://mwop.net/blog/199-A-Simple-PHP-Publish-Subscribe-System.html"/>
    <id>https://mwop.net/blog/199-A-Simple-PHP-Publish-Subscribe-System.html</id>
    <author>
      <name>Matthew Weier O'Phinney</name>
      <email>contact@mwop.net</email>
      <uri>https://mwop.net</uri>
    </author>
    <content xmlns:xhtml="http://www.w3.org/1999/xhtml" type="xhtml">
      <xhtml:div xmlns:xhtml="http://www.w3.org/1999/xhtml"><xhtml:p>I've been playing a lot with <xhtml:a href="http://dojotoolkit.org/">Dojo</xhtml: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.</xhtml:p>
<xhtml: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.</xhtml:p>
<xhtml: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 <xhtml:a href="http://github.com/weierophinney/phly/tree/master/Phly_PubSub">on
github</xhtml:a>.</xhtml:p>
<xhtml:p>Usage is incredibly simple: an object publishes an event, which
triggers all subscribers.</xhtml:p>
<xhtml: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 "log"
events:</xhtml:p>
<xhtml:pre><xhtml:code class="language-php hljs php" data-lang="php">$log = <xhtml:span class="hljs-keyword">new</xhtml:span> Zend_Log(<xhtml:span class="hljs-keyword">new</xhtml:span> Zend_Log_Writer_Stream(<xhtml:span class="hljs-string">'/tmp/application.log'</xhtml:span>));
Phly_PubSub::subscribe(<xhtml:span class="hljs-string">'log'</xhtml:span>, $log, <xhtml:span class="hljs-string">'info'</xhtml:span>);
</xhtml:code></xhtml:pre>
<xhtml:p>Then, in your code, whenever you might want to log some
information, simply publish to the "log" topic:</xhtml:p>
<xhtml:pre><xhtml:code class="language-php hljs php" data-lang="php">Phly_PubSub::publish(<xhtml:span class="hljs-string">'log'</xhtml:span>, <xhtml:span class="hljs-string">'Log message...'</xhtml:span>);
</xhtml:code></xhtml:pre>
<xhtml: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.</xhtml:p>
<xhtml:p>As another example, consider a model that has a
<xhtml:code>save</xhtml: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.</xhtml:p>
<xhtml:p>Your model's <xhtml:code>save</xhtml:code> method might then look like
this:</xhtml:p>
<xhtml:pre><xhtml:code class="language-php hljs php" data-lang="php"><xhtml:span class="hljs-class"><xhtml:span class="hljs-keyword">class</xhtml:span> <xhtml:span class="hljs-title">Foo</xhtml:span>
</xhtml:span>{
    <xhtml:span class="hljs-keyword">public</xhtml:span> <xhtml:span class="hljs-function"><xhtml:span class="hljs-keyword">function</xhtml:span> <xhtml:span class="hljs-title">save</xhtml:span><xhtml:span class="hljs-params">(array $data)</xhtml:span>
    </xhtml:span>{
        Phly_PubSub::publish(<xhtml:span class="hljs-string">'Foo::save::start'</xhtml:span>, $data, <xhtml:span class="hljs-keyword">$this</xhtml:span>);

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

        Phly_PubSub::publish(<xhtml:span class="hljs-string">'Foo::save::end'</xhtml:span>, $id, <xhtml:span class="hljs-keyword">$this</xhtml:span>);
        <xhtml:span class="hljs-keyword">return</xhtml:span> $id;
    }
}
</xhtml:code></xhtml:pre>
<xhtml: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.</xhtml:p>
<xhtml:pre><xhtml:code class="language-php hljs php" data-lang="php">Phly_PubSub::subscribe(<xhtml:span class="hljs-string">'Foo::save::start'</xhtml:span>, $logger, <xhtml:span class="hljs-string">'logSaveData'</xhtml:span>);
Phly_PubSub::subscribe(<xhtml:span class="hljs-string">'Foo::save::end'</xhtml:span>, $logger, <xhtml:span class="hljs-string">'logSaveId'</xhtml:span>);
Phly_PubSub::subscribe(<xhtml:span class="hljs-string">'Foo::save::end'</xhtml:span>, $cache, <xhtml:span class="hljs-string">'updateFooItem'</xhtml:span>);
Phly_PubSub::subscribe(<xhtml:span class="hljs-string">'Foo::save::end'</xhtml:span>, $index, <xhtml:span class="hljs-string">'updateFooItem'</xhtml:span>);
</xhtml:code></xhtml:pre>
<xhtml: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.</xhtml:p>
<xhtml:p>Some places it could be improved:</xhtml:p>
<xhtml:ul>
<xhtml: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.</xhtml:li>
<xhtml: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.</xhtml:li>
</xhtml:ul>
<xhtml:p>I'm excited to see what uses <xhtml:em>you</xhtml:em> may be able to put
this to; drop me a line if you start using it!</xhtml:p>
<xhtml:p><xhtml:strong>Update (2008-12-30):</xhtml:strong> Based on some of the
comments to this post, I created <xhtml:code>Phly_PubSub_Provider</xhtml: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:</xhtml:p>
<xhtml:pre><xhtml:code class="language-php hljs php" data-lang="php"><xhtml:span class="hljs-class"><xhtml:span class="hljs-keyword">class</xhtml:span> <xhtml:span class="hljs-title">Foo</xhtml:span>
</xhtml:span>{
    <xhtml:span class="hljs-keyword">protected</xhtml:span> $_plugins;

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

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

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

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

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

$foo-&gt;bar(); <xhtml:span class="hljs-comment">// echo's 'bar'</xhtml:span>
</xhtml:code></xhtml:pre>
<xhtml:div class="h-entry"><xhtml:img class="u-photo photo" width="50" src="https://avatars0.githubusercontent.com/u/25943?v=3&amp;u=79dd2ea1d4d8855944715d09ee4c86215027fa80&amp;s=140" alt="matthew"/> <xhtml: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</xhtml:a> was originally published
<xhtml:time class="dt-published" datetime="2008-12-15T10:26:00-06:00">15
December 2008</xhtml:time> on <xhtml:a href="https://mwop.net">https://mwop.net</xhtml:a> by <xhtml:a rel="author" class="p-author" href="https://mwop.net">Matthew Weier
O'Phinney</xhtml:a>.</xhtml:div>
</xhtml:div>
    </content>
  </entry>
  <entry xmlns:xhtml="http://www.w3.org/1999/xhtml">
    <title type="html"><![CDATA[Autocompletion with Zend Framework and Dojo]]></title>
    <published>2008-12-12T11:07:29-06:00</published>
    <updated>2008-12-15T06:49:51-06:00</updated>
    <link rel="alternate" type="text/html" href="https://mwop.net/blog/198-Autocompletion-with-Zend-Framework-and-Dojo.html"/>
    <id>https://mwop.net/blog/198-Autocompletion-with-Zend-Framework-and-Dojo.html</id>
    <author>
      <name>Matthew Weier O'Phinney</name>
      <email>contact@mwop.net</email>
      <uri>https://mwop.net</uri>
    </author>
    <content xmlns:xhtml="http://www.w3.org/1999/xhtml" type="xhtml">
      <xhtml:div xmlns:xhtml="http://www.w3.org/1999/xhtml"><xhtml:p>I've fielded several questions about setting up an autocompleter
with <xhtml:a href="http://framework.zend.com/">Zend Framework</xhtml:a> and
<xhtml:a href="http://dojotoolkit.org/">Dojo</xhtml: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.</xhtml:p>
<xhtml:h2>Which dijits perform autocompletion?</xhtml:h2>
<xhtml:p>Your first task is selecting an appropriate form element capable
of autocompletion. Dijit provides two, <xhtml:code>ComboBox</xhtml:code> and
<xhtml:code>FilteringSelect</xhtml:code>. However, they have different
capabilities:</xhtml:p>
<xhtml:ul>
<xhtml:li><xhtml:code>ComboBox</xhtml:code> allows you to enter arbitrary text; if it
doesn't match the associated list, it is still considered valid.
The text <xhtml:em>entered</xhtml:em> is submitted —
<xhtml:em><xhtml:strong>not</xhtml:strong></xhtml:em> the option value. (This differs from
normal dropdown selects.)</xhtml:li>
<xhtml:li><xhtml:code>FilteringSelect</xhtml:code> also allows you to enter arbitrary
text, but it will only be considered valid if it matches an option
provided to it. The <xhtml:em>option value</xhtml:em> is submitted, just like a
normal dropdown select.</xhtml:li>
</xhtml:ul>
<xhtml:p>Once you've chose the appropriate form element type, you then
need to specify a <xhtml:code>dojo.data</xhtml:code> store.
<xhtml:code>dojo.data</xhtml: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 <xhtml:code>ComboBox</xhtml:code> and
<xhtml:code>FilteringSelect</xhtml:code> can utilize <xhtml:code>dojo.data</xhtml:code>
stores to populate their options and/or provide matches. Dojo
provides a variety of <xhtml:code>dojo.data</xhtml:code> stores for such
purposes.</xhtml:p>
<xhtml:h3>Defining the form element</xhtml:h3>
<xhtml:p>Defining the form element is very straightforward. From your
<xhtml:code>Zend_Dojo_Form</xhtml:code> instance (or your form extending that
class), simply call <xhtml:code>addElement()</xhtml: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:</xhtml:p>
<xhtml:pre><xhtml:code class="language-php hljs php" data-lang="php">$form-&gt;addElement(<xhtml:span class="hljs-string">'ComboBox'</xhtml:span>, <xhtml:span class="hljs-string">'myAutoCompleteField'</xhtml:span>, <xhtml:span class="hljs-keyword">array</xhtml:span>(
    <xhtml:span class="hljs-string">'label'</xhtml:span> =&gt; <xhtml:span class="hljs-string">'My autocomplete field:'</xhtml:span>,
));
</xhtml:code></xhtml:pre>
<xhtml:h2>Providing data to a dojo.data store</xhtml:h2>
<xhtml:p>We're going to work backwards now, as providing data to the data
store is relatively trivial when using
<xhtml:code>Zend_Dojo_Data</xhtml:code>.</xhtml:p>
<xhtml: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
<xhtml:code>dojo.data</xhtml:code> store to send the query string via the GET
parameter <xhtml:code>q</xhtml:code>, so that's what we'll assign to the
view.</xhtml:p>
<xhtml:pre><xhtml:code class="language-php hljs php" data-lang="php">    <xhtml:span class="hljs-keyword">public</xhtml:span> <xhtml:span class="hljs-function"><xhtml:span class="hljs-keyword">function</xhtml:span> <xhtml:span class="hljs-title">autocompleteAction</xhtml:span><xhtml:span class="hljs-params">()</xhtml:span>
    </xhtml:span>{
        <xhtml:span class="hljs-comment">// First, get the model somehow</xhtml:span>
        <xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;view-&gt;model = <xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;getModel();

        <xhtml:span class="hljs-comment">// Then get the query, defaulting to an empty string</xhtml:span>
        <xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;view-&gt;query = <xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;_getParam(<xhtml:span class="hljs-string">'q'</xhtml:span>, <xhtml:span class="hljs-string">''</xhtml:span>);
    }
</xhtml:code></xhtml:pre>
<xhtml: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 <xhtml:code>Zend_Dojo_Data</xhtml:code> object with the results of our
query; and finally, we'll echo the <xhtml:code>Zend_Dojo_Data</xhtml:code>
instance.</xhtml:p>
<xhtml:pre><xhtml:code class="language-php hljs php" data-lang="php"><xhtml:span class="hljs-meta">&lt;?php</xhtml:span>
<xhtml:span class="hljs-comment">// Disable layouts</xhtml:span>
<xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;layout()-&gt;disableLayout();

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

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

<xhtml:span class="hljs-comment">// Send our output</xhtml:span>
<xhtml:span class="hljs-keyword">echo</xhtml:span> $data;
</xhtml:code></xhtml:pre>
<xhtml:p>That's really all there is to it. You can actually automate some
of this using the <xhtml:code>AjaxContext</xhtml:code> action helper, making it
even simpler.</xhtml:p>
<xhtml:h2>Using dojox.data.QueryReadStore</xhtml:h2>
<xhtml:p>We now have an endpoint for our <xhtml:code>dojo.data</xhtml:code> data
store, so now we need to determine which store type to use.</xhtml:p>
<xhtml:p><xhtml:code>dojox.data.QueryReadStore</xhtml:code> is a fantastic
<xhtml:code>dojo.data</xhtml:code> store allowing you to create arbitrary
queries on data. It creates the query as a JSON object:</xhtml:p>
<xhtml:pre><xhtml:code class="language-javascript hljs javascript" data-lang="javascript">{
    <xhtml:span class="hljs-string">"query"</xhtml:span>: { <xhtml:span class="hljs-string">"name"</xhtml:span>: <xhtml:span class="hljs-string">"A*"</xhtml:span> },
    <xhtml:span class="hljs-string">"queryOptions"</xhtml:span>: { <xhtml:span class="hljs-string">"ignoreCase"</xhtml:span>: <xhtml:span class="hljs-literal">true</xhtml:span> },
    <xhtml:span class="hljs-string">"sort"</xhtml:span>: [{ <xhtml:span class="hljs-string">"attribute"</xhtml:span>: <xhtml:span class="hljs-string">"name"</xhtml:span>, <xhtml:span class="hljs-string">"descending"</xhtml:span>: <xhtml:span class="hljs-literal">false</xhtml:span> }],
    <xhtml:span class="hljs-string">"start"</xhtml:span>: <xhtml:span class="hljs-number">0</xhtml:span>,
    <xhtml:span class="hljs-string">"count"</xhtml:span>: <xhtml:span class="hljs-number">10</xhtml:span>
}
</xhtml:code></xhtml:pre>
<xhtml: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.</xhtml:p>
<xhtml:p>Fortunately, there's an easy way to correct the situation:
extend <xhtml:code>dojox.data.QueryReadStore</xhtml:code> and override the
<xhtml:code>fetch</xhtml:code> method to rewrite the query as a simple GET
query with a single parameter.</xhtml:p>
<xhtml:pre><xhtml:code class="language-javascript hljs javascript" data-lang="javascript">dojo.provide(<xhtml:span class="hljs-string">"custom.AutocompleteReadStore"</xhtml:span>);

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

            <xhtml:span class="hljs-comment">// and then operate as normal:</xhtml:span>
            <xhtml:span class="hljs-keyword">return</xhtml:span> <xhtml:span class="hljs-keyword">this</xhtml:span>.inherited(<xhtml:span class="hljs-string">"fetch"</xhtml:span>, <xhtml:span class="hljs-built_in">arguments</xhtml:span>);
        }
    }
);
</xhtml:code></xhtml:pre>
<xhtml:p>The question now is, where to create this definition?</xhtml:p>
<xhtml: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.</xhtml:p>
<xhtml:h3>Inlining a custom QueryReadStore class extension</xhtml:h3>
<xhtml: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:</xhtml:p>
<xhtml:ol>
<xhtml:li>require the <xhtml:code>dojox.data.QueryReadStore</xhtml:code> class</xhtml:li>
<xhtml:li>define a global JS variable that will be used to identify your
store</xhtml:li>
<xhtml:li>use <xhtml:code>dojo.provide</xhtml:code> and <xhtml:code>dojo.declare</xhtml:code> to
create your custom data store extension</xhtml:li>
<xhtml:li>define an onLoad event that instantiates the data store and
attaches it to the form element</xhtml:li>
</xhtml:ol>
<xhtml:p>We can do all the above within the same view script in which we
spit out our form:</xhtml:p>
<xhtml:pre><xhtml:code class="language-php hljs php" data-lang="php"><xhtml:span class="hljs-meta">&lt;?php</xhtml:span>
<xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;dojo()-&gt;requireModule(<xhtml:span class="hljs-string">"dojox.data.QueryReadStore"</xhtml:span>);

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

<xhtml:span class="hljs-comment">// Once dijits have been created and all classes defined,</xhtml:span>
<xhtml:span class="hljs-comment">// instantiate the autocompleter and attach it to the element.</xhtml:span>
<xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;dojo()-&gt;onLoadCaptureStart() <xhtml:span class="hljs-meta">?&gt;</xhtml:span>
<xhtml:span class="hljs-function"><xhtml:span class="hljs-keyword">function</xhtml:span><xhtml:span class="hljs-params">()</xhtml:span> </xhtml:span>{
    autocompleter = <xhtml:span class="hljs-keyword">new</xhtml:span> custom.AutocompleteReadStore({
        url: <xhtml:span class="hljs-string">"/test/autocomplete"</xhtml:span>,
        requestMethod: <xhtml:span class="hljs-string">"get"</xhtml:span>
    });
    dijit.byId(<xhtml:span class="hljs-string">"myAutoCompleteField"</xhtml:span>).attr({
        store: autocompleter
    });
}
<xhtml:span class="hljs-meta">&lt;?php</xhtml:span> <xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;dojo()-&gt;onLoadCaptureEnd() <xhtml:span class="hljs-meta">?&gt;</xhtml:span>
&lt;h1&gt;Autocompletion Example&lt;/h1&gt;
&lt;div <xhtml:span class="hljs-class"><xhtml:span class="hljs-keyword">class</xhtml:span>="<xhtml:span class="hljs-title">tundra</xhtml:span>"&gt;
&lt;?<xhtml:span class="hljs-title">php</xhtml:span> <xhtml:span class="hljs-title">echo</xhtml:span> $<xhtml:span class="hljs-title">this</xhtml:span>-&gt;<xhtml:span class="hljs-title">form</xhtml:span> ?&gt;
&lt;/<xhtml:span class="hljs-title">div</xhtml:span>&gt;
</xhtml:span></xhtml:code></xhtml:pre>
<xhtml: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</xhtml:p>
<xhtml:h3>Creating a reusable custom QueryReadStore class extension</xhtml:h3>
<xhtml:p>The recommendation by the Dojo developers is that you should
create this class as a <xhtml:em>javascript</xhtml:em> class, with your other
<xhtml:em>javascript</xhtml: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.</xhtml:p>
<xhtml:p>The process isn't as scary as it may initially sound. Assuming
that your <xhtml:code>public/</xhtml:code> directory has the following
structure:</xhtml:p>
<xhtml:pre><xhtml:code class="language-arduino hljs arduino" data-lang="arduino"><xhtml:span class="hljs-keyword">public</xhtml:span>/
    js/
        dojo/
            dojo.js
        dijit/
        dojox/
</xhtml:code></xhtml:pre>
<xhtml:p>what we'll do here is to create a sibling to the
<xhtml:code>dojo</xhtml:code> subdirectory, called <xhtml:code>custom"</xhtml:code> and
create our class file there:</xhtml:p>
<xhtml:pre><xhtml:code class="language-arduino hljs arduino" data-lang="arduino"><xhtml:span class="hljs-keyword">public</xhtml:span>/
    js/
        dojo/
            dojo.js
        dijit/
        dojox/
        custom/
            AutocompleteReadStore.js
</xhtml:code></xhtml:pre>
<xhtml:p>We'll use the definition as originally shown above, and simply
save it as <xhtml:code>public/js/custom/AutocompleteReadStore.js</xhtml:code>,
with one addition: after the <xhtml:code>dojo.provide</xhtml:code> call, add
this:</xhtml:p>
<xhtml:pre><xhtml:code class="language-javascript hljs javascript" data-lang="javascript">dojo.require(<xhtml:span class="hljs-string">"dojox.data.QueryReadStore"</xhtml:span>);
</xhtml:code></xhtml:pre>
<xhtml:p>This is analagous to a <xhtml:code>require_once</xhtml: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
<xhtml:code>ComboBox</xhtml:code> element what type of data store to use.</xhtml:p>
<xhtml:p>On the framework side of things, we're going to alter our
element definition slightly to include information about the
<xhtml:code>dojo.data</xhtml:code> store it will be using:</xhtml:p>
<xhtml:pre><xhtml:code class="language-php hljs php" data-lang="php">$form-&gt;addElement(<xhtml:span class="hljs-string">'ComboBox'</xhtml:span>, <xhtml:span class="hljs-string">'myAutoCompleteField'</xhtml:span>, <xhtml:span class="hljs-keyword">array</xhtml:span>(
    <xhtml:span class="hljs-string">'label'</xhtml:span>     =&gt; <xhtml:span class="hljs-string">'My autocomplete field:'</xhtml:span>,

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

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

    <xhtml:span class="hljs-comment">// Parameters to use when initializint the data store:</xhtml:span>
    <xhtml:span class="hljs-string">'storeParams'</xhtml:span> =&gt; <xhtml:span class="hljs-keyword">array</xhtml:span>(
        <xhtml:span class="hljs-string">'url'</xhtml:span>           =&gt; <xhtml:span class="hljs-string">'/foo/autocomplete'</xhtml:span>,
        <xhtml:span class="hljs-string">'requestMethod'</xhtml:span> =&gt; <xhtml:span class="hljs-string">'get'</xhtml:span>,
    ),
));
</xhtml:code></xhtml:pre>
<xhtml:p>If you've been following along closely, you'll notice that the
"storeParams" are exactly the same as what we used to initialize
the data store when inlining. The difference is that now the
<xhtml:code>ComboBox</xhtml:code> view helper will create all the necessary
Javascript for you.</xhtml:p>
<xhtml:p>The view script now becomes greatly simplified; we no longer
need to setup any javascript, and can literally simply echo the
form:</xhtml:p>
<xhtml:pre><xhtml:code class="language-php hljs php" data-lang="php"><xhtml:span class="hljs-meta">&lt;?</xhtml:span>= <xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;form <xhtml:span class="hljs-meta">?&gt;</xhtml:span>
</xhtml:code></xhtml:pre>
<xhtml:p>Hopefully it should now be clear which method is easiest in the
long run.</xhtml:p>
<xhtml:h2>Next Steps</xhtml:h2>
<xhtml:p><xhtml:code>dojox.data.QueryReadStore</xhtml: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.</xhtml:p>
<xhtml:h2>Summary</xhtml:h2>
<xhtml: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.</xhtml:p>
<xhtml: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.</xhtml:p>
<xhtml:div class="h-entry"><xhtml:img class="u-photo photo" width="50" src="https://avatars0.githubusercontent.com/u/25943?v=3&amp;u=79dd2ea1d4d8855944715d09ee4c86215027fa80&amp;s=140" alt="matthew"/> <xhtml: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</xhtml:a> was originally
published <xhtml:time class="dt-published" datetime="2008-12-12T11:07:29-06:00">12 December 2008</xhtml:time> on <xhtml:a href="https://mwop.net">https://mwop.net</xhtml:a> by <xhtml:a rel="author" class="p-author" href="https://mwop.net">Matthew Weier
O'Phinney</xhtml:a>.</xhtml:div>
</xhtml:div>
    </content>
  </entry>
  <entry xmlns:xhtml="http://www.w3.org/1999/xhtml">
    <title type="html"><![CDATA[Tidings of the Season]]></title>
    <published>2008-12-02T22:07:13-06:00</published>
    <updated>2008-12-06T18:48:16-06:00</updated>
    <link rel="alternate" type="text/html" href="https://mwop.net/blog/196-Tidings-of-the-Season.html"/>
    <id>https://mwop.net/blog/196-Tidings-of-the-Season.html</id>
    <author>
      <name>Matthew Weier O'Phinney</name>
      <email>contact@mwop.net</email>
      <uri>https://mwop.net</uri>
    </author>
    <content xmlns:xhtml="http://www.w3.org/1999/xhtml" type="xhtml">
      <xhtml:div xmlns:xhtml="http://www.w3.org/1999/xhtml"><xhtml: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, "no
excuses!" while the aging adult in me whispers, "time for bed,
dear."</xhtml:p>
<xhtml: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.</xhtml:p>
<xhtml:h3>Speaking at PHP Quebec</xhtml:h3>
<xhtml:p><xhtml:img src="http://conf.phpquebec.org/img/icone/2009/2009_150x100_speakat_blue_en.gif" alt="PHP Quebec 2009"/></xhtml:p>
<xhtml:p>I'm speaking at PHP Quebec this coming spring, and presenting
"Practical Zend Framework Jutsu with Dojo". 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!</xhtml:p>
<xhtml:h3>PHP Advent Calendar</xhtml:h3>
<xhtml:p><xhtml:a href="http://shiflett.org/">Chris Shiflett</xhtml:a> and <xhtml:a href="http://seancoates.com">Sean Coates</xhtml:a> have generously donated
some time and a domain to this year's <xhtml:a href="http://phpadvent.org/2008">PHP Advent Calendar</xhtml:a>. I was invited
to submit an entry, and wrote up a piece I titled <xhtml:a href="http://phpadvent.org/2008/use-responsibly-by-matthew-weier-ophinney">
"Use Responsibly"</xhtml:a>, where I discuss good development habits when
consuming open source projects.</xhtml:p>
<xhtml:h3>Burlington, VT PHP User's Group</xhtml:h3>
<xhtml:p>This week marks the one year anniversary of regular meetings of
the <xhtml:a href="http://groups.google.com/group/Burlington-VT-PHP">Burlington, VT
PHP User's Group</xhtml:a>. We <xhtml:a href="http://groups.google.com/group/Burlington-VT-PHP/web/meeting-2008-12-04">
meet this week</xhtml:a> for a special presentation from <xhtml:a href="http://asynchronous.org/">Josh Sled</xhtml: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!</xhtml:p>
<xhtml:h3>Zend Framework 1.7.1</xhtml:h3>
<xhtml:p>Yesterday, we released <xhtml:a href="http://framework.zend.com/download/latest">Zend Framework
1.7.1</xhtml:a>, the first bugfix release in the 1.7 series. Not much
more to say about it, other than start downloading!</xhtml:p>
<xhtml:h3>Pastebin updates</xhtml:h3>
<xhtml:p>I've been continuing development on the <xhtml:a href="http://github.com/weierophinney/pastebin">pastebin application</xhtml:a>
I developed for demonstrating Zend Framework and Dojo integration.
In the past couple weeks, I've reworked it substantially, adding
support for <xhtml:code>dojo.back</xhtml: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…</xhtml:p>
<xhtml:p>…which has led me to jump to the next milestone, which is to
integrate the <xhtml:a href="http://github.com/weierophinney/bugapp">bug
application</xhtml: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 "Spindle", 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.</xhtml:p>
<xhtml:h3>Oh, and one more thing…</xhtml:h3>
<xhtml:p>Ha! fooled you!</xhtml:p>
<xhtml:p>Seriously, though, there are, to quote something I saw on
<xhtml:a href="http://twitter.com">twitter</xhtml:a> today, a "metric shit-ton"
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!</xhtml:p>
<xhtml:div class="h-entry"><xhtml:img class="u-photo photo" width="50" src="https://avatars0.githubusercontent.com/u/25943?v=3&amp;u=79dd2ea1d4d8855944715d09ee4c86215027fa80&amp;s=140" alt="matthew"/> <xhtml:a class="u-url u-uid p-name" href="https://mwop.net/blog/196-Tidings-of-the-Season.html">Tidings of
the Season</xhtml:a> was originally published <xhtml:time class="dt-published" datetime="2008-12-02T22:07:13-06:00">2 December 2008</xhtml:time> on
<xhtml:a href="https://mwop.net">https://mwop.net</xhtml:a> by <xhtml:a rel="author" class="p-author" href="https://mwop.net">Matthew Weier
O'Phinney</xhtml:a>.</xhtml:div>
</xhtml:div>
    </content>
  </entry>
  <entry xmlns:xhtml="http://www.w3.org/1999/xhtml">
    <title type="html"><![CDATA[Pastebin app updates]]></title>
    <published>2008-09-27T14:14:59-05:00</published>
    <updated>2008-10-03T05:39:15-05:00</updated>
    <link rel="alternate" type="text/html" href="https://mwop.net/blog/193-Pastebin-app-updates.html"/>
    <id>https://mwop.net/blog/193-Pastebin-app-updates.html</id>
    <author>
      <name>Matthew Weier O'Phinney</name>
      <email>contact@mwop.net</email>
      <uri>https://mwop.net</uri>
    </author>
    <content xmlns:xhtml="http://www.w3.org/1999/xhtml" type="xhtml">
      <xhtml:div xmlns:xhtml="http://www.w3.org/1999/xhtml"><xhtml:p>I've been getting a lot of interest in my <xhtml:a href="/blog/189-Pastebin-app-and-conference-updates.html">Pastebin</xhtml:a>
demo app — partly by those wanting to play with Dojo+ZF, partly by
those just interested in the application.</xhtml:p>
<xhtml: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 <xhtml:a href="http://dojotoolkit.org/2008/07/10/dojo-developer-day-boston">Dojo
Develper Day in Boston</xhtml:a> this Monday as well as at <xhtml:a href="http://phpworks.mtacon.com/c/index">php|works</xhtml:a> later this fall,
and want to keep the materials up-to-date and freely available. To
this end, I've created a <xhtml:a href="http://github.com">Github</xhtml:a>
repository so you can track the latest developments, as well as
pull custom tarballs:</xhtml:p>
<xhtml:ul>
<xhtml:li><xhtml:a href="http://github.com/weierophinney/pastebin/tree/master">Pastebin on
Github</xhtml:a></xhtml:li>
</xhtml:ul>
<xhtml:p>All patches and feedback are welcome!</xhtml:p>
<xhtml:div class="h-entry"><xhtml:img class="u-photo photo" width="50" src="https://avatars0.githubusercontent.com/u/25943?v=3&amp;u=79dd2ea1d4d8855944715d09ee4c86215027fa80&amp;s=140" alt="matthew"/> <xhtml:a class="u-url u-uid p-name" href="https://mwop.net/blog/193-Pastebin-app-updates.html">Pastebin app
updates</xhtml:a> was originally published <xhtml:time class="dt-published" datetime="2008-09-27T14:14:59-05:00">27 September 2008</xhtml:time> on
<xhtml:a href="https://mwop.net">https://mwop.net</xhtml:a> by <xhtml:a rel="author" class="p-author" href="https://mwop.net">Matthew Weier
O'Phinney</xhtml:a>.</xhtml:div>
</xhtml:div>
    </content>
  </entry>
  <entry xmlns:xhtml="http://www.w3.org/1999/xhtml">
    <title type="html"><![CDATA[ZendCon08 Wrapup]]></title>
    <published>2008-09-25T23:11:30-05:00</published>
    <updated>2008-09-27T12:06:11-05:00</updated>
    <link rel="alternate" type="text/html" href="https://mwop.net/blog/192-ZendCon08-Wrapup.html"/>
    <id>https://mwop.net/blog/192-ZendCon08-Wrapup.html</id>
    <author>
      <name>Matthew Weier O'Phinney</name>
      <email>contact@mwop.net</email>
      <uri>https://mwop.net</uri>
    </author>
    <content xmlns:xhtml="http://www.w3.org/1999/xhtml" type="xhtml">
      <xhtml:div xmlns:xhtml="http://www.w3.org/1999/xhtml"><xhtml:p>I'm a bit late on my <xhtml:a href="http://www.zendcon.com/">ZendCon'08</xhtml: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.</xhtml:p>
<xhtml: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; <xhtml:a href="http://www.sklar.com/">David Sklar</xhtml:a> had
just started at <xhtml:a href="http://www.ning.com/">Ning</xhtml:a> and had to
back out of his "Configuring PHP" tutorial session. <xhtml:a href="http://mikenaberezny.com/">Mike Naberezny</xhtml: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.</xhtml:p>
<xhtml: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. <xhtml:a href="http://mikenaberezny.com/">Mike</xhtml:a> and I
did our <xhtml:a href="http://www.slideshare.net/weierophinney/best-practices-of-php-development-presentation/">
Best Practices tutorial session</xhtml: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.</xhtml:p>
<xhtml:p>On Tuesday, <xhtml:a href="http://inside.e-novative.de/">Stefan
Priebsch</xhtml:a> <xhtml:del>roped me into</xhtml:del> convinced me to help with a
"round table" 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.</xhtml:p>
<xhtml:p>Later that morning, I did a presentation on <xhtml:a href="http://www.slideshare.net/weierophinney/getting-started-with-zend-framework-presentation/">
Getting Started with Zend Framework</xhtml:a>. I developed this
presentation to follow our newly re-launched <xhtml:a href="http://framework.zend.com/docs/quickstart">Quick Start</xhtml: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.</xhtml:p>
<xhtml:p>In the afternoon, I did another unconference session, this time
performing my <xhtml: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</xhtml:a> talk. (Did I
mention that conference attendees could not seem to get enough Zend
Framework material?) I really enjoyed doing this talk <xhtml:em>live</xhtml: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.</xhtml:p>
<xhtml:p>Tuesday afternoon, I presented my session on <xhtml:a href="http://www.slideshare.net/weierophinney/zendform-presentation/">Zend_Form</xhtml:a>.
We'd originally planned to do a talk on <xhtml:code>Zend_Layout</xhtml:code>
and <xhtml:code>Zend_Form</xhtml: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 <xhtml:code>Zend_Layout</xhtml:code> during an
UnConference session, while I focussed on <xhtml:code>Zend_Form</xhtml: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
<xhtml:code>Zend_Dojo</xhtml:code> integration with <xhtml:code>Zend_Form</xhtml:code> in
the future.</xhtml:p>
<xhtml:p>Immediately following that, I headed off to do yet another
UnConference session with <xhtml:a href="http://lornajane.net/">Lorna
Jane</xhtml:a>. <xhtml:a href="http://caseysoftware.com/blog">Keith Casey</xhtml:a>
had approached me on Monday following the tutorial Mike and I
presented, indicating that there were requests for an "svn tips and
tricks" 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.</xhtml:p>
<xhtml:p>I quickly ran downstairs, only to find I was immediately wanted
for a "Meet the Team" 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.)</xhtml:p>
<xhtml: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!</xhtml:p>
<xhtml: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 "join the fun" 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 "seeing" 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.</xhtml:p>
<xhtml:p>So, goodbye, ZendCon08 and all my new and old friends — let's
hope we can meet again next year!</xhtml:p>
<xhtml:div class="h-entry"><xhtml:img class="u-photo photo" width="50" src="https://avatars0.githubusercontent.com/u/25943?v=3&amp;u=79dd2ea1d4d8855944715d09ee4c86215027fa80&amp;s=140" alt="matthew"/> <xhtml:a class="u-url u-uid p-name" href="https://mwop.net/blog/192-ZendCon08-Wrapup.html">ZendCon08
Wrapup</xhtml:a> was originally published <xhtml:time class="dt-published" datetime="2008-09-25T23:11:30-05:00">25 September 2008</xhtml:time> on
<xhtml:a href="https://mwop.net">https://mwop.net</xhtml:a> by <xhtml:a rel="author" class="p-author" href="https://mwop.net">Matthew Weier
O'Phinney</xhtml:a>.</xhtml:div>
</xhtml:div>
    </content>
  </entry>
  <entry xmlns:xhtml="http://www.w3.org/1999/xhtml">
    <title type="html"><![CDATA[Pastebin app and conference updates]]></title>
    <published>2008-09-09T10:19:23-05:00</published>
    <updated>2008-09-16T01:15:30-05:00</updated>
    <link rel="alternate" type="text/html" href="https://mwop.net/blog/189-Pastebin-app-and-conference-updates.html"/>
    <id>https://mwop.net/blog/189-Pastebin-app-and-conference-updates.html</id>
    <author>
      <name>Matthew Weier O'Phinney</name>
      <email>contact@mwop.net</email>
      <uri>https://mwop.net</uri>
    </author>
    <content xmlns:xhtml="http://www.w3.org/1999/xhtml" type="xhtml">
      <xhtml:div xmlns:xhtml="http://www.w3.org/1999/xhtml"><xhtml:p>I have a number of updates and followups, and decided to post
them in a single entry.</xhtml:p>
<xhtml:p>First off, you may now <xhtml:a href="http://www.zend.com/en/webinar/Framework-Dojo/Webinar-Rec-Framework-Dev-EN-ZFDojo-20080903.flv">
view my Dojo Webinar online</xhtml: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 <xhtml:a href="http://www.zendcon.com/">ZendCon</xhtml:a>
UnConference, at <xhtml:a href="http://dojotoolkit.org/2008/07/10/dojo-developer-day-boston">Dojo
Developer Day Boston</xhtml:a> later this month, and at <xhtml:a href="http://phpworks.mtacon.com/c/schedule/talk/d1s5/1">php|works</xhtml:a>
in November. I hope to be able to show new functionality at each
presentation.</xhtml:p>
<xhtml: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.</xhtml:p>
<xhtml:ul>
<xhtml:li><xhtml:a href="/uploads/pastebin-1.0.0.tar.gz">Download the pastebin
application</xhtml:a></xhtml:li>
</xhtml:ul>
<xhtml:p>The pastebin application showcases a number of features besides
Dojo: <xhtml:code>Zend_Test_PHPUnit</xhtml:code> was used to test the
application, and <xhtml:code>Zend_Wildfire</xhtml:code>'s FireBug logger and DB
profiler are used to provide profiling and debug information.</xhtml:p>
<xhtml:p>Finally, <xhtml:a href="http://www.zendcon.com/">ZendCon</xhtml: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.</xhtml:p>
<xhtml:div class="h-entry"><xhtml:img class="u-photo photo" width="50" src="https://avatars0.githubusercontent.com/u/25943?v=3&amp;u=79dd2ea1d4d8855944715d09ee4c86215027fa80&amp;s=140" alt="matthew"/> <xhtml: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</xhtml:a> was originally published
<xhtml:time class="dt-published" datetime="2008-09-09T10:19:23-05:00">9
September 2008</xhtml:time> on <xhtml:a href="https://mwop.net">https://mwop.net</xhtml:a> by <xhtml:a rel="author" class="p-author" href="https://mwop.net">Matthew Weier
O'Phinney</xhtml:a>.</xhtml:div>
</xhtml:div>
    </content>
  </entry>
  <entry xmlns:xhtml="http://www.w3.org/1999/xhtml">
    <title type="html"><![CDATA[Proper Layer files when using Dojo with Zend Framework]]></title>
    <published>2008-09-05T09:30:00-05:00</published>
    <updated>2008-09-08T09:17:34-05:00</updated>
    <link rel="alternate" type="text/html" href="https://mwop.net/blog/188-Proper-Layer-files-when-using-Dojo-with-Zend-Framework.html"/>
    <id>https://mwop.net/blog/188-Proper-Layer-files-when-using-Dojo-with-Zend-Framework.html</id>
    <author>
      <name>Matthew Weier O'Phinney</name>
      <email>contact@mwop.net</email>
      <uri>https://mwop.net</uri>
    </author>
    <content xmlns:xhtml="http://www.w3.org/1999/xhtml" type="xhtml">
      <xhtml:div xmlns:xhtml="http://www.w3.org/1999/xhtml"><xhtml:p>During my <xhtml:a href="http://www.zend.com/en/resources/webinars/framework">Dojo and ZF
webinar</xhtml:a> on Wednesday, <xhtml:a href="http://higginsforpresident.net/">Pete Higgins</xhtml:a> of <xhtml:a href="http://dojotoolkit.org/">Dojo</xhtml:a> fame noted that I could do
something different and better on one of my slides.</xhtml:p>
<xhtml: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.</xhtml:p>
<xhtml:p>The code in question looked like this:</xhtml:p>
<xhtml:pre><xhtml:code class="language-php hljs php" data-lang="php">Zend_Dojo::enableView($view);
$view-&gt;dojo()-&gt;setDjConfigOption(<xhtml:span class="hljs-string">'usePlainJson'</xhtml:span>, <xhtml:span class="hljs-keyword">true</xhtml:span>)
             <xhtml:span class="hljs-comment">// -&gt;setDjConfigOption('isDebug', true)</xhtml:span>
             -&gt;addStylesheetModule(<xhtml:span class="hljs-string">'dijit.themes.tundra'</xhtml:span>)
             -&gt;addStylesheet(<xhtml:span class="hljs-string">'/js/dojox/grid/_grid/tundraGrid.css'</xhtml:span>)
             -&gt;setLocalPath(<xhtml:span class="hljs-string">'/js/dojo/dojo.js'</xhtml:span>)
             -&gt;addLayer(<xhtml:span class="hljs-string">'/js/paste/main.js'</xhtml:span>)
             <xhtml:span class="hljs-comment">// -&gt;addLayer('/js/paste/paste.js')</xhtml:span>
             -&gt;registerModulePath(<xhtml:span class="hljs-string">'../paste'</xhtml:span>, <xhtml:span class="hljs-string">'paste'</xhtml:span>)
             -&gt;addJavascript(<xhtml:span class="hljs-string">'paste.main.init();'</xhtml:span>)
             -&gt;disable();
</xhtml:code></xhtml:pre>
<xhtml:p>The lines he was commenting on were the <xhtml:code>addLayer()</xhtml:code>
lines.</xhtml:p>
<xhtml: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.</xhtml:p>
<xhtml: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.</xhtml:p>
<xhtml:p>Pete showed me another solution that was much more elegant, and
which also got rid of another line in that solution above, the
<xhtml:code>addJavascript()</xhtml:code></xhtml:p>
<xhtml: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
<xhtml:code>dojo.require()</xhtml:code> statements in the file, as well as
mixin any code you want in the main module namespace:</xhtml:p>
<xhtml:pre><xhtml:code class="language-javascript hljs javascript" data-lang="javascript">dojo.provide(<xhtml:span class="hljs-string">"paste.layer"</xhtml:span>);

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

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

<xhtml:span class="hljs-comment">/* mixin functionality to the "paste" namespace: */</xhtml:span>
dojo.mixin(paste, {
    <xhtml:span class="hljs-comment">/* paste.newPasteButton() */</xhtml:span>
    <xhtml:span class="hljs-attr">newPasteButton</xhtml:span>:  <xhtml:span class="hljs-function"><xhtml:span class="hljs-keyword">function</xhtml:span>() </xhtml:span>{
        <xhtml:span class="hljs-keyword">var</xhtml:span> form = dijit.byId(<xhtml:span class="hljs-string">"pasteform"</xhtml:span>);
        <xhtml:span class="hljs-keyword">if</xhtml:span> (form.isValid()) {
            form.submit(); 
        }
    },
    
    <xhtml:span class="hljs-comment">/* ... */</xhtml:span>
});
</xhtml:code></xhtml:pre>
<xhtml:p>In my original code, I had a <xhtml:code>paste.main.init</xhtml:code> method
that performed all my <xhtml:code>dojo.require</xhtml:code> and
<xhtml:code>dojo.addOnLoad</xhtml:code> statements, but these now can be simply
a part of the layer — eliminating more work for me.</xhtml:p>
<xhtml:p>Then, when creating the profile, you simply have it create the
layer in the same file — in this case, <xhtml:code>paste/layer.js</xhtml:code>
— but also have it create a <xhtml:em>dependency</xhtml:em> on the original
layer file. The compiler will ensure that the original code gets
slurped into the build. As an example:</xhtml:p>
<xhtml:pre><xhtml:code class="language-javascript hljs javascript" data-lang="javascript">dependencies = {
    <xhtml:span class="hljs-attr">layers</xhtml:span>: [
        {
            <xhtml:span class="hljs-attr">name</xhtml:span>: <xhtml:span class="hljs-string">"../paste/layer.js"</xhtml:span>,
            <xhtml:span class="hljs-attr">dependencies</xhtml:span>: [
                <xhtml:span class="hljs-string">"paste.layer"</xhtml:span>,
                <xhtml:span class="hljs-comment">/* other dependencies...*/</xhtml:span>
            ]
        },
    ],
    <xhtml:span class="hljs-attr">prefixes</xhtml:span>: [
        [ <xhtml:span class="hljs-string">"paste"</xhtml:span>, <xhtml:span class="hljs-string">"../paste"</xhtml:span> ],
        <xhtml:span class="hljs-comment">/* other prefixes -- dijit, etc. */</xhtml:span>
    ]
}
</xhtml:code></xhtml:pre>
<xhtml:p>This changes the original ZF snippet above to simply:</xhtml:p>
<xhtml:pre><xhtml:code class="language-php hljs php" data-lang="php">Zend_Dojo::enableView($view);
$view-&gt;dojo()-&gt;setDjConfigOption(<xhtml:span class="hljs-string">'usePlainJson'</xhtml:span>, <xhtml:span class="hljs-keyword">true</xhtml:span>)
             <xhtml:span class="hljs-comment">// -&gt;setDjConfigOption('isDebug', true)</xhtml:span>
             -&gt;addStylesheetModule(<xhtml:span class="hljs-string">'dijit.themes.tundra'</xhtml:span>)
             -&gt;addStylesheet(<xhtml:span class="hljs-string">'/js/dojox/grid/_grid/tundraGrid.css'</xhtml:span>)
             -&gt;setLocalPath(<xhtml:span class="hljs-string">'/js/dojo/dojo.js'</xhtml:span>)
             -&gt;addLayer(<xhtml:span class="hljs-string">'/js/paste/layer.js'</xhtml:span>)
             -&gt;registerModulePath(<xhtml:span class="hljs-string">'../paste'</xhtml:span>, <xhtml:span class="hljs-string">'paste'</xhtml:span>)
             -&gt;disable();
</xhtml:code></xhtml:pre>
<xhtml:p>Not much shorter — but because I no longer need to worry about
changing the file name, I can rest easier at night.</xhtml:p>
<xhtml:p>I'll be blogging more tips such as these in the coming weeks, to
help support the new <xhtml:a href="http://framework.zend.com/announcements/2008-09-03-dojo">Dojo
integration</xhtml:a> in Zend Framework.</xhtml:p>
<xhtml:div class="h-entry"><xhtml:img class="u-photo photo" width="50" src="https://avatars0.githubusercontent.com/u/25943?v=3&amp;u=79dd2ea1d4d8855944715d09ee4c86215027fa80&amp;s=140" alt="matthew"/> <xhtml: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</xhtml:a> was
originally published <xhtml:time class="dt-published" datetime="2008-09-05T09:30:00-05:00">5 September 2008</xhtml:time> on <xhtml:a href="https://mwop.net">https://mwop.net</xhtml:a> by <xhtml:a rel="author" class="p-author" href="https://mwop.net">Matthew Weier
O'Phinney</xhtml:a>.</xhtml:div>
</xhtml:div>
    </content>
  </entry>
</feed>
