A blog has formed

September 11th, 2008 jasoneisen

In preparation for a ZendCon “unconvention” talk I’m giving about making ZF modules distributable, I’ve had to throw a quick demo app together to show how easy it is to install my security module into an existing application. I had initially hoped to check out planetarium, which is a blog app thats been brewing for quite a few weeks now, and I was especially excited to see huge amounts of files being pulled down when I did a repository checkout. But 4 libraries and 10 million lines of code later, I was rather disappointed to be presented with only a hello world page. Not gonna cut it!

So, considering the talk is on Tuesday, I’ve taken things into my own hands and spent the evening making this:

Currently, it’s nothing but controllers with empty actions, and their corresponding view files. This evening has just been building out the structure and getting design elements in order, which at the moment is a hacked up version of the Mollio template. But this will be a semi-functional blog app by the end of this weekend, I promise! And not to mention, it will have a handy security module ready to be installed, too :)

You can check it out in the security module repository under “demo” which, by the way, is also coming along nicely. Hopefully this talk will get some documentation out of me as well. (I’ve heard rumors that talks would be recorded and put online, too, but I’m not sure if its for unconvention talks.)

Go to the repository, pull it down, and try it out. It’ll only take 2 minutes… and if you break it who cares? You can make a bug report and I’ll fix it!

Tags: , , , , , ,

Posted in Doctrine, Zend | 3 Comments »

Rails-like url helper for Zend Framework

September 7th, 2008 jasoneisen

I’ve been doing a lot of research into rails lately, and one of it’s most useful features is it’s routing. It strictly follows the REST methodology, which can help make application design much simpler. If you’re not familiar with this, or have no idea what I’m talking about, heres a cheat sheet to help you out.

The Problem:

Spitting out a route in the view is so annoyingly verbose. As an example:

 
// /users
<?php echo $this->Url(array(), 'users_path', true); ?>
 
// /users/4/edit
<?php echo $this->Url(array('id' => 4), 'edit_user_path', true); ?>
 
// /company/123/users/4/edit
<?php echo $this->Url(array('company_id' => 123, 'id' => 4), 'edit_company_user_path', true); ?>

Do you see how the code to get a string is twice as long as the string itself? An even more annoying part is that the options array and the route name parameter order is backwards. If I want to spit out a named route without any options, I have to provide an empty array() to get to the name.

The Solution:

If you looked at the cheat sheet, you will have noticed how beautifully simple it is to print out a route in rails. Here’s one usage of my new alternative:

 
// /users
<?php echo $this->Path('users'); ?>
 
// /users/4/edit
<?php echo $this->Path('edit_user', 4); ?>
 
// /company/123/users/4/edit
<?php echo $this->Path('edit_company_user', array('company_id' => 123, 'id' => 4)); ?>

Note that this isn’t the final product, it gets better. But see how that cut down on code? It’s not _that_ much better, but it’s a start. The key feature here is putting the options array and route name in the right order, automatically adding “_path” to the route name (it’s the name of the function, cmon that would be redundant), making $reset true by default, and creating an array(’id’=>$arg) options array when the argument isn’t an array.

Here’s the code for the view helper:

 
class My_View_Helper_Path
{
    public function Path($name, $urlOptions = array(), $reset = true, $encode = true)
    {
        if (substr($name, -5) != '_path') {
            $name .= "_path";
        }
 
        if (!empty($urlOptions) && !is_array($urlOptions)) {
            $urlOptions = array('id' => $urlOptions);
        }
 
        $router = Zend_Controller_Front::getInstance()->getRouter();
 
        return $router->assemble($urlOptions, $name, $reset, $encode);
    }
}

Now if you look closely, you’ll wonder “why check for ‘_path’ on the route? I thought if we used that it was redundant?”. That’s because this is only the first half. I now introduce to you the second possible usage with a little more magic:

 
// /users
<?php echo $this->users_path(); ?>
 
// /users/4/edit
<?php echo $this->edit_user_path(4); ?>
 
// /company/123/users/4/edit
<?php echo $this->edit_company_user_path(array('company_id' => 123, 'id' => 4)); ?>

That, folks, is as close as the php language will let us come to rails, barring the removal of “echo” and having the method do that itself (in which case it would lose the functionality of being used in non view-specific tasks). You might be wondering what the hell I did to my view to get this to work. It was actually quite simple: make my own view class that overrides the __call() method.

Here’s the entire class in all it’s glory:

 
class My_View extends Zend_View
{
    public function __call($method, $args)
    {
        if (substr($method, -5) == '_path') {
            array_unshift($args, $method);
            $method = 'Path';
        }
 
        return parent::__call($method, $args);
    }
}

Just simply use this view instead of Zend_View. In case you don’t know how to do that, somewhere early on in your app’s loading process do the following:

 
$viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
$viewRenderer->setView(new My_View());

Note that the view helper will work perfectly by itself with the first example usage, no overriding the view is necessary.

Namespaces will make things like this a lot easier when they get here, but for now, this does the trick. Have fun :)

Update Sept 7, 2:12 pm:

I’ve written a quick little method in my base controller to use this that I thought I’d share:

 
    protected function _gotoPathAndExit($name = null, $urlOptions = array(), $reset = false)
    {
        $path = $this->view->Path($name, $urlOptions = array(), $reset = false);
        $this->_helper->redirector->setPrependBase(false);
 
        $this->_redirect($path);
    }
 
    // Old usage
    $this->getHelper('Redirector')->gotoRouteAndExit(array(), 'users_path');
 
    // New hotness
    $this->_gotoPathAndExit('users');

Tags: , , , , , , ,

Posted in REST, Zend | 3 Comments »