<?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>Tag: dojo :: phly, boy, phly</title>
    <description>Tag: dojo :: phly, boy, phly</description>
    <pubDate>Mon, 23 Feb 2009 13:17:00 +0000</pubDate>
    <generator>Zend_Feed_Writer 2.1.4dev (http://framework.zend.com)</generator>
    <link>http://mwop.net/blog/tag/dojo.html</link>
    <atom:link rel="self" type="application/rss+xml" href="http://mwop.net/blog/tag/dojo-rss.xml"/>
    <item>
      <title>Recursively Destroying Dojo ContentPanes</title>
      <pubDate>Mon, 23 Feb 2009 13:17:00 +0000</pubDate>
      <link>http://mwop.net/blog/208-Recursively-Destroying-Dojo-ContentPanes.html</link>
      <guid>http://mwop.net/blog/208-Recursively-Destroying-Dojo-ContentPanes.html</guid>
      <author>me@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><div class="example"><pre><code lang="javascript">
dojo.provide(\&quot;custom.ContentPane\&quot;);

dojo.require(\&quot;dijit.layout.ContentPane\&quot;);

dojo.declare(\&quot;custom.ContentPane\&quot;, [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);
    }
});
</code></pre></div>

<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>]]></content:encoded>
      <slash:comments>0</slash:comments>
    </item>
    <item>
      <title>Using JSLint</title>
      <pubDate>Fri, 20 Feb 2009 13:11:41 +0000</pubDate>
      <link>http://mwop.net/blog/207-Using-JSLint.html</link>
      <guid>http://mwop.net/blog/207-Using-JSLint.html</guid>
      <author>me@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
    "jslint", with the following:
</p>

<div class="example"><pre><code lang="sh">
#!/bin/sh
exec java \
-jar /path/to/dojo/util/shrinksafe/custom_rhino.jar \
/path/to/jslint.js $1
</code></pre></div>

<p>
    Note: you'll need to put in the correct paths to your Dojo installation as
    well as to where you placed the jslint.js 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>
jslint foo.js
</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>
% for f in *.js;do jslint $f;done
</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>]]></content:encoded>
      <slash:comments>0</slash:comments>
    </item>
    <item>
      <title>2008: The year in review</title>
      <pubDate>Mon, 05 Jan 2009 07:00:49 +0000</pubDate>
      <link>http://mwop.net/blog/203-2008-The-year-in-review.html</link>
      <guid>http://mwop.net/blog/203-2008-The-year-in-review.html</guid>
      <author>me@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 "Guide to
    Programming Zend Framework".
</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 "placeholder" 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 "Login and
    Authentication", 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 "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!
</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 "Pikachu" 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 "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.
</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>]]></content:encoded>
      <slash:comments>0</slash:comments>
    </item>
    <item>
      <title>A Simple PHP Publish-Subscribe System</title>
      <pubDate>Wed, 31 Dec 2008 12:05:35 +0000</pubDate>
      <link>http://mwop.net/blog/199-A-Simple-PHP-Publish-Subscribe-System.html</link>
      <guid>http://mwop.net/blog/199-A-Simple-PHP-Publish-Subscribe-System.html</guid>
      <author>me@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 "log" events:
</p>

<div class="example"><pre><code lang="php">
$log = new Zend_Log(new Zend_Log_Writer_Stream('/tmp/application.log'));
Phly_PubSub::subscribe('log', $log, 'info');
</code></pre></div>

<p>
    Then, in your code, whenever you might want to log some information, simply
    publish to the "log" topic:
</p>

<div class="example"><pre><code lang="php">
Phly_PubSub::publish('log', 'Log message...');
</code></pre></div>

<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>

<div class="example"><pre><code lang="php">
class Foo
{
    public function save(array $data)
    {
        Phly_PubSub::publish('Foo::save::start', $data, $this);

        // ...

        Phly_PubSub::publish('Foo::save::end', $id, $this);
        return $id;
    }
}
</code></pre></div>

<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>

<div class="example"><pre><code lang="php">
Phly_PubSub::subscribe('Foo::save::start', $logger, 'logSaveData');
Phly_PubSub::subscribe('Foo::save::end', $logger, 'logSaveId');
Phly_PubSub::subscribe('Foo::save::end', $cache, 'updateFooItem');
Phly_PubSub::subscribe('Foo::save::end', $index, 'updateFooItem');
</code></pre></div>

<p>
    The beauty of the approach is the simplicity: Foo doesn't need to implement
    it's 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>
    <b>Update (2008-12-30):</b> 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>

<div class="example"><pre><code lang="php">
class Foo
{
    protected $_plugins;

    public function __construct()
    {
        $this-&gt;_plugins = new Phly_PubSub_Provider();
    }

    public function getPluginProvider()
    {
        return $this-&gt;_plugins;
    }

    public function bar()
    {
        $this-&gt;_plugins-&gt;publish('bar');
    }
}

$foo = new Foo();

// Subscribe echo() to the 'bar' event:
$foo-&gt;getPluginProvider()-&gt;subscribe('bar', 'echo');

$foo-&gt;bar(); // echo's 'bar'
</code></pre></div>]]></content:encoded>
      <slash:comments>0</slash:comments>
    </item>
    <item>
      <title>Autocompletion with Zend Framework and Dojo</title>
      <pubDate>Mon, 15 Dec 2008 11:49:51 +0000</pubDate>
      <link>http://mwop.net/blog/198-Autocompletion-with-Zend-Framework-and-Dojo.html</link>
      <guid>http://mwop.net/blog/198-Autocompletion-with-Zend-Framework-and-Dojo.html</guid>
      <author>me@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 -- <b><i>not</i></b> 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 it's 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>

<div class="example"><pre><code lang="php">
$form-&gt;addElement('ComboBox', 'myAutoCompleteField', array(
    'label'     =&gt; 'My autocomplete field:',
));
</code></pre></div>

<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
    "q", so that's what we'll assign to the view.
</p>

<div class="example"><pre><code lang="php">
    public function autocompleteAction()
    {
        // First, get the model somehow
        $this-&gt;view-&gt;model = $this-&gt;getModel();

        // Then get the query, defaulting to an empty string
        $this-&gt;view-&gt;query = $this-&gt;_getParam('q', '');
    }
</code></pre></div>

<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>

<div class="example"><pre><code lang="php">
&lt;?php
// Disable layouts
$this-&gt;layout()-&gt;disableLayout();

// Fetch results from the model; again, merely illustrative
$results = $this-&gt;model-&gt;query($this-&gt;params);

// Now, create a Zend_Dojo_Data object.
// The first parameter is the name of the field that has a
// unique identifier. The second is the dataset. The third
// should be specified for autocompletion, and should be the
// name of the field representing the data to display in the
// dropdown. Note how it corresponds to \&quot;name\&quot; in the 
// AutocompleteReadStore.
$data = new Zend_Dojo_Data('id', $results, 'name');

// Send our output
echo $data;
</code></pre></div>

<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>

<div class="example"><pre><code lang="javascript">
{
    query: { name: \&quot;A*\&quot; },
    queryOptions: { ignoreCase: true },
    sort: [{ attribute: \&quot;name\&quot;, descending: false }],
    start: 0,
    count: 10
}
</code></pre></div>

<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>

<div class="example"><pre><code lang="javascript">
dojo.provide(\&quot;custom.AutocompleteReadStore\&quot;);

dojo.declare(
    \&quot;custom.AutocompleteReadStore\&quot;, // our class name
    dojox.data.QueryReadStore,      // what we're extending
    {
        fetch: function(request) {  // the fetch method
            // set the serverQuery, which sets query string parameters
            request.serverQuery = {q: request.query.name};

            // and then operate as normal:
            return this.inherited(\&quot;fetch\&quot;, arguments);
        }
    }
);
</code></pre></div>

<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>

<div class="example"><pre><code lang="php">
&lt;?php
$this-&gt;dojo()-&gt;requireModule(\&quot;dojox.data.QueryReadStore\&quot;);

// Define a new data store class, and 
// setup our autocompleter data store
$this-&gt;dojo()-&gt;javascriptCaptureStart() ?&gt;
dojo.provide(\&quot;custom.AutocompleteReadStore\&quot;);
dojo.declare(
    \&quot;custom.AutocompleteReadStore\&quot;, 
    dojox.data.QueryReadStore, 
    {
        fetch: function(request) {
            request.serverQuery = {q: request.query.name};
            return this.inherited(\&quot;fetch\&quot;, arguments);
        }
    }
);
var autocompleter;
&lt;?php $this-&gt;dojo()-&gt;javascriptCaptureEnd();

// Once dijits have been created and all classes defined,
// instantiate the autocompleter and attach it to the element.
$this-&gt;dojo()-&gt;onLoadCaptureStart() ?&gt;
function() {
    autocompleter = new custom.AutocompleteReadStore({
        url: \&quot;/test/autocomplete\&quot;,
        requestMethod: \&quot;get\&quot;
    });
    dijit.byId(\&quot;myAutoCompleteField\&quot;).attr({
        store: autocompleter
    });
}
&lt;?php $this-&gt;dojo()-&gt;onLoadCaptureEnd() ?&gt;
&lt;h1&gt;Autocompletion Example&lt;/h1&gt;
&lt;div class=\&quot;tundra\&quot;&gt;
&lt;?php echo $this-&gt;form ?&gt;
&lt;/div&gt;
</code></pre></div>

<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
    "public/" directory has the following structure:
</p>

<code><pre>
public/
    js/
        dojo/
            dojo.js
        dijit/
        dojox/
</pre></code>

<p>
    what we'll do here is to create a sibling to the "dojo" subdirectory, called
    "custom", and create our class file there:
</p>

<code><pre>
public/
    js/
        dojo/
            dojo.js
        dijit/
        dojox/
        custom/
            AutocompleteReadStore.js
</pre></code>

<p>
    We'll use the definition as originally shown above, and simply save it as
    "public/js/custom/AutocompleteReadStore.js", with one addition: after the
    <code>dojo.provide</code> call, add this:
</p>

<div class="example"><pre><code lang="javascript">
dojo.require(\&quot;dojox.data.QueryReadStore\&quot;);
</code></pre></div>

<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>

<div class="example"><pre><code lang="php">
$form-&gt;addElement('ComboBox', 'myAutoCompleteField', array(
    'label'     =&gt; 'My autocomplete field:',

    // The javascript identifier for the data store:
    'storeId'   =&gt; 'autocompleter',

    // The class type for the data store:
    'storeType' =&gt; 'custom.AutocompleteReadStore',

    // Parameters to use when initializint the data store:
    'storeParams' =&gt; array(
        'url'           =&gt; '/foo/autocomplete',
        'requestMethod' =&gt; 'get',
    ),
));
</code></pre></div>

<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 <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>

<div class="example"><pre><code lang="php">
&lt;?= $this-&gt;form ?&gt;
</code></pre></div>

<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>]]></content:encoded>
      <slash:comments>0</slash:comments>
    </item>
    <item>
      <title>Tidings of the Season</title>
      <pubDate>Sat, 06 Dec 2008 23:48:16 +0000</pubDate>
      <link>http://mwop.net/blog/196-Tidings-of-the-Season.html</link>
      <guid>http://mwop.net/blog/196-Tidings-of-the-Season.html</guid>
      <author>me@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, "no excuses!" while the aging
    adult in me whispers, "time for bed, dear."
</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 style="text-align: center;">
    <img src="http://conf.phpquebec.org/img/icone/2009/2009_150x100_speakat_blue_en.gif" alt="PHP Quebec 2009" height="100" width="150" />
</p>

<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!
</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">Use
    Responsibly</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 "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.
</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 "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!
</p>]]></content:encoded>
      <slash:comments>0</slash:comments>
    </item>
    <item>
      <title>Pastebin app updates</title>
      <pubDate>Fri, 03 Oct 2008 09:39:15 +0000</pubDate>
      <link>http://mwop.net/blog/193-Pastebin-app-updates.html</link>
      <guid>http://mwop.net/blog/193-Pastebin-app-updates.html</guid>
      <author>me@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="http://weierophinney.net/matthew/archives/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>]]></content:encoded>
      <slash:comments>0</slash:comments>
    </item>
    <item>
      <title>ZendCon08 Wrapup</title>
      <pubDate>Sat, 27 Sep 2008 16:06:11 +0000</pubDate>
      <link>http://mwop.net/blog/192-ZendCon08-Wrapup.html</link>
      <guid>http://mwop.net/blog/192-ZendCon08-Wrapup.html</guid>
      <author>me@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
    "Configuring PHP" 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>
    <strike>roped me into</strike> 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.
</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 Zend_Layout and Zend_Form, 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 Zend_Layout during an
    UnConference session, while I focussed on Zend_Form. 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 Zend_Dojo integration with Zend_Form 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 "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.
</p>

<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.)
</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 "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.
</p>

<p>
    So, goodbye, ZendCon08 and all my new and old friends -- let's hope we can
    meet again next year!
</p>]]></content:encoded>
      <slash:comments>0</slash:comments>
    </item>
    <item>
      <title>Pastebin app and conference updates</title>
      <pubDate>Tue, 16 Sep 2008 05:15:30 +0000</pubDate>
      <link>http://mwop.net/blog/189-Pastebin-app-and-conference-updates.html</link>
      <guid>http://mwop.net/blog/189-Pastebin-app-and-conference-updates.html</guid>
      <author>me@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>]]></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 13:17:34 +0000</pubDate>
      <link>http://mwop.net/blog/188-Proper-Layer-files-when-using-Dojo-with-Zend-Framework.html</link>
      <guid>http://mwop.net/blog/188-Proper-Layer-files-when-using-Dojo-with-Zend-Framework.html</guid>
      <author>me@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>

<div class="example"><pre><code lang="php">
Zend_Dojo::enableView($view);
$view-&gt;dojo()-&gt;setDjConfigOption('usePlainJson', true)
             // -&gt;setDjConfigOption('isDebug', true)
             -&gt;addStylesheetModule('dijit.themes.tundra')
             -&gt;addStylesheet('/js/dojox/grid/_grid/tundraGrid.css')
             -&gt;setLocalPath('/js/dojo/dojo.js')
             -&gt;addLayer('/js/paste/main.js')
             // -&gt;addLayer('/js/paste/paste.js')
             -&gt;registerModulePath('../paste', 'paste')
             -&gt;addJavascript('paste.main.init();')
             -&gt;disable();
</code></pre></div>

<p>
    The lines he was commenting onwere 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 call.
</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>

<div class="example"><pre><code lang="javascript">
dojo.provide(\&quot;paste.layer\&quot;);

/* Dojo modules to require... */
dojo.require(\&quot;dijit.layout.ContentPane\&quot;);
/* ... */

/* onLoad actions to perform... */
dojo.addOnLoad(function() {
    paste.upgrade(); 
});

/* mixin functionality to the \&quot;paste\&quot; namespace: */
dojo.mixin(paste, {
    /* paste.newPasteButton() */
    newPasteButton:  function() {
        var form = dijit.byId(\&quot;pasteform\&quot;);
        if (form.isValid()) {
            form.submit(); 
        }
    },
    
    /* ... */
});
</code></pre></div>

<p>
    In my original code, I had a "paste.main.init" 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, paste/layer.js -- 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>

<div class="example"><pre><code lang="javascript">
dependencies = {
    layers: [
        {
            name: \&quot;../paste/layer.js\&quot;,
            dependencies: [
                \&quot;paste.layer\&quot;,
                /* other dependencies...*/
            ]
        },
    ],
    prefixes: [
        [ \&quot;paste\&quot;, \&quot;../paste\&quot; ],
        /* other prefixes -- dijit, etc. */
    ]
}
</code></pre></div>

<p>
    This changes the original ZF snippet above to simply:
</p>

<div class="example"><pre><code lang="php">
Zend_Dojo::enableView($view);
$view-&gt;dojo()-&gt;setDjConfigOption('usePlainJson', true)
             // -&gt;setDjConfigOption('isDebug', true)
             -&gt;addStylesheetModule('dijit.themes.tundra')
             -&gt;addStylesheet('/js/dojox/grid/_grid/tundraGrid.css')
             -&gt;setLocalPath('/js/dojo/dojo.js')
             -&gt;addLayer('/js/paste/layer.js')
             -&gt;registerModulePath('../paste', 'paste')
             -&gt;disable();
</code></pre></div>

<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>]]></content:encoded>
      <slash:comments>0</slash:comments>
    </item>
  </channel>
</rss>
