OT: Need something? Ask Hoosgot!

31st December 2007

If it takes off, I expect everyone will be talking about hoosgot over the next weeks and months. The idea is to allow you to ask the world if anyone has got what you want maybe help you find what you are looking for, given the international nature of the web.

All you have to do is include "hoosgot" (pronounced "who's got") or "lazyweb" in your blog post or tweet and it'll pick it up. (Is it just me, or is that pronunciation a stretch?). You can follow it on Twitter, but I suspect that it'll be tweeting a bit too regularly for me though unless hoosgot works out what's a question, what's an answer and what is just commentary (like this post!).

Assuming that they sort out the filtering, It could be useful for anything that doesn't require UPS in nature. i.e. asking for device drivers for esoteric hardware or to find out answers to stuff such as "hoosgot a good receipe for dairy free banana milkshake?" I can't see questions such as "hoosgot a spare washing machine that I can borrow?" working outside your own circle of friends and freecycle and craigslist has that covered anyway.

Definitely worth keeping an eye on to see where it goes.

Notes to self, re: IE6

27th December 2007

I've just spent way too long today debugging stuff in IE6 that I already knew once I found the problems!

So, next time I have vertical spacing issue in IE6, I can come here and remind myself that in IE, <form> has margin on it by default…

Also, the YUI panel doesn't seem to work properly in IE6 if it's contained within an element that is positioned "relative" with CSS.

Now that Christmas is over, I'm going to be dedicating significant time to completing my outstanding copy for my development editor to make her happier with me!

Simple Zend_Layout Example

11th December 2007

Zend_Layout is in the trunk now, so here's a super simple MVC example that shows it in action:
Zend_Layout Example_Small.png

This example consists of three view files: the outer layout file, the index action view script and a right hand side bar. The remainder of this post describes the key files. If you just want to poke around with the code, then it's at the bottom, so page down now!

Setting up

This is the directory layout:

Zend_Layout Directory.png

As you can see, it's the standard layout and we have one controller, Index, with one action (also index). For good measure, I've thrown in a view helper to collect the base URL to reference the CSS file and also render into a sidebar.

Let's look at the bootstrap file, index.php, first:

<?php

define('ROOT_DIR'dirname(dirname(__FILE__)));

// Setup path to the Zend Framework files
set_include_path('.'
PATH_SEPARATOR ROOT_DIR.'/lib/'
PATH_SEPARATOR get_include_path()
);

// Register the autoloader
require_once 'Zend/Loader.php';
Zend_Loader::registerAutoload();

// Initialise Zend_Layout's MVC helpers
Zend_Layout::startMvc(array('layoutPath' => ROOT_DIR.'/app/views/layouts'));

// Run!
$frontController Zend_Controller_Front::getInstance();
$frontController->addControllerDirectory(ROOT_DIR.'/app/controllers');
$frontController->throwExceptions(true);
try {
    $frontController->dispatch();
} catch(Exception $e) {
    echo nl2br($e->__toString());
}


This is a standard bootstrap with the exception that we initialise the Zend_Layout using the startMvc() function. This takes an array of options, but the one thing you really need to pass in is the directory to find the layout files. I've chosen app/views/layouts as it makes sense in this case. If you are using modules, then maybe app/layouts would be better.

The controller

The index controller contains two functions: init() to render the sidebar to a named response section for use in the layout and then the indexAction() which just puts some text into the view:

<?php

class IndexController extends Zend_Controller_Action
{
    function init()
    {
        // Render sidebar for every action
        $response $this->getResponse();
        $response->insert('sidebar'$this->view->render('sidebar.phtml')); 
    }

    function indexAction()
    {
        $this->view->pageTitle "Zend Layout Example";

        $this->view->bodyTitle '<h1>Hello World!</h1>';
        $this->view->bodyCopy "<p>Lorem ipsum dolor etc.</p>";
    }
}

Two-step view

The view is now two-step. This means that we split our HTML between multiple files. The first step is to render the "inner" scripts, such as the sidebar and the action specific scripts. Then we render the "outer", layout script which embeds the rendered "inner" scripts.

The "inner" scripts

The action view script, index/index.phtml is trivial as it just needs to display the text relevant to the index action only:

<?php echo $this->bodyTitle ;?>
<?php echo $this->bodyCopy ;?>

(told you it was simple!)

The sidebar.phtml is similarly, just the HTML required for our sidebar:


<h2>Sidebar</h2>
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
<li>Item 5</li>
</ul>

Again, nice and easy HTML, for this example at least!

The layout script

The layout script, layout.phtml, ties it all together. It contains the HTML that is common to all pages on our website and uses the special construct <?php echo $this->layout()->content ?> to render a named response segment. Note that the view renderer will render to "content" for the action controller's script.

The layout script looks like this:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8″ />
    <title><?php echo $this->escape($this->pageTitle); ?></title>
    <link rel="stylesheet" href="<?php echo $this->baseUrl(); ?>/main.css" type="text/css">
</head>
<body>
    <div id="content">
        <?php echo $this->layout()->content ?>
    </div>
    <div id="sidebar">
        <?php echo $this->layout()->sidebar?>
    </div>
</body>
</html>

For simplicity, we use the baseUrl view helper to retrieve the base URL from the request (via the Front Controller) and we render our two named response segments (content and sidebar) using the view helper layout() which is provide by Zend_Layout.

Conclusion

That's all there is to it. We could have use the partial() view helper to render the sidebar script and coming soon to a svn tree near you is other useful view helpers such as headScript() and headTitle() which will make the <head> section easier to manage.

Here's a zip file of this project: Zend_Layout_Example.zip(It includes a snapshot of the trunk of the Zend Framework which is why it's 3MB big.)

It works for me, at least.

Where to set up your view?

9th December 2007

With Zend_Layout on the horizon, I've been looking at how to use it and it will remove the need for my own front controller plugin which I call SiteTemplate. As a result, I need to find a new home for the view customisation stuff I do in SiteTemplate.

My current plan is to create a new front controller plugin called ViewSetup (for want of a better name!) that contains just the view setup stuff from

<?php
require_once 'Zend/Controller/Plugin/Abstract.php';

/**
 * Front Controller plug in to set up the view with the Akra view helper
 * path and some useful request variables.
 *
 */
class Akra_Controller_Plugin_ViewSetup extends Zend_Controller_Plugin_Abstract
{    
    public function dispatchLoopStartup(Zend_Controller_Request_Abstract $request)
    {
        $viewRenderer Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
        $viewRenderer->setView(new Akra_View());

        // add helper path to View/Helper directory within this library
        $prefix 'Akra_View_Helper';
        $dir dirname(__FILE__) . '/../../View/Helper';
        $viewRenderer->view->addHelperPath($dir$prefix);
    
        // set up variables that the view may want to know    
        $viewRenderer->view->baseUrl $request->getBaseUrl();
        $viewRenderer->view->module $request->getModuleName();
        $viewRenderer->view->controller $request->getControllerName();
        $viewRenderer->view->action $request->getActionName();
        $viewRenderer->view->theme $request->getParam('theme''default');
    }
}

(I'll talk about how cool Akra_View is another time…)

I had a dig into Zend_Layout's source and it collects its view object from the view renderer too, so this works as expected. (*phew*!)

The alternative, as I see it is to put the view creation into my bootstrap and then create a series of view helpers like this one for the base url:

<?php

class Places_View_Helper_BaseUrl
{
    protected $_baseUrl;
    
    function __construct()
    {
        $fc Zend_Controller_Front::getInstance();
        $request $fc->getRequest();
        $this->_baseUrl =  $request->getBaseUrl();
    }
    
    function baseUrl()
    {
        return $this->_baseUrl;
    }
}

How does everyone else do it? Is the bootstrap + many view helpers approach a better one than using a front controller plugin? Have I missed a completely obvious better solution?

Zend_View: Access the view from a view helper

6th December 2007

It's in the manual, but I thought I'd blog about my simple View Helper setup that ensures that I can get at the view with minimal effort.

Firstly we create a parent class:

<?php

abstract class My_View_Helper_Abstract
{
    protected $_view;
    
    public function setView($view)
    {
        $this->_view $view;
    }
}

This class contains the code required by Zend_View to collect an instance of the view and assign it to a protected variable. All my view helpers extend this class and so I can acess the view using $this->_view. For instance:

<?php

require_once 'My/View/Helper/Abstract.php';

class My_View_Helper_TreeUl extends My_View_Helper_Abstract
{
    /**
     * Render a nested array as a set of nested <ul>s.
     *
     * @param array|instanceof Iterator $list
     * @return string
     */
    function treeUl($list)
    {
        $output ";
        if (is_array($list) || $list instanceof Iterator) {
            if (count($list) > 0) {
                $output "<ul>\n";
                foreach ($list as $item) {
                    $output .= "\t<li>";
                    if(is_string($item)) {
                        $output .= $this->_view->escape($item);
                    } else {
                        $output .= $this->treeUl($item);
                    }
                    $output .= "</li>\n";
                }
                $output .= "</ul>\n";
            }
        }
        return $output;
    }
}

Simple, isn't it ?!