Archive for the 'Code' Category

RewriteRouter and Zend_Config play together

Tuesday, July 18th, 2006

While getting the hang of the Zend_Controller_RewriteRouter, which is now included in Zend Framework 0.1.5, I was adding the routes in my index.php (bootstrap) file and wondered if there was any way of storing them elsewhere. It is possible to loop over Zend_Controller_RewriteRouter::addRoutes() but the method I will describe here is based on some recent updates to Zend_Controller_RewriteRouter by its author Michael Minicki.

The point of RewriteRouter is to map urls, like ingredients.com.au/recipe/tomato_sambal, to whatever controller, action and parameters needed without having to use external (and often painful!) methods like mod_rewrite.

For the sake of this article I’ll use a relatively simple URL…

ingredients.com.au/articles/cooking/

First setup some routes in a config file “routes.php”. Note that this does require the latest version of the RewriteRouter which needs to be checked out from the subversion repository

$config['routes']['articles'] = 
new Zend_Controller_Router_Route('articles/:category', 
array('category' => 'all', 
       'controller' => 'articles', 
       'action'      => 'index' ), 
       array('category' => '[a-z_]+') );

This establishes a route called “articles” that will respond to any url of the form “/articles/whatever” with the colon in :category indicating that it is an url variable that can be recovered through Zend_Controller_Action::_getParam( ‘category’ ). The controller and action indexes make the action “indexAction” in the controller file “ArticlesController.php” the final target. To cover cases where there is no category specified the default setting “all” is given. For extra assurance :category has to be a string containing only lower case letters and underscores as indicated by the final requirements array.

Next load them into the bootstrap file using Zend_Config_Array:

$routes = new Zend_Config( 
        Zend_Config_Array::load( 
       '../application/configuration/routes.php', 'routes' ) );

Then create the RewriteRouter object and pass it the $routes…

$router = new Zend_Controller_RewriteRouter;
$router->addRoutes( $routes );

All that is needed now is to pass the $router to the front controller…

$controller = Zend_Controller_Front::getInstance();
$controller->setRouter( $router );

That’s it, now the routes are nicely stored outside of the bootstrap file and with the rest of the domain files.

Further Reading

Aside from the manual pages mentioned I can’t close without pointing to an actual recipe for tomato sambal !!

Endnote

I should also mention that it’s well worth getting involved with the development of the framework even if you can only do so in a small way. After a relatively short discussion via the issue tracker about having some means to load routes in one hit, Michael Minicki had implemented one (thanks Michael).

Mr Dizzy, Getters/Setters and Constructors

Monday, July 17th, 2006

Mr Dizzy“Mr Dizzy was to be quite honest, not very clever.”

One day, while refactoring a web application from procedural to object oriented code, Mr Dizzy decided to use constructors in a way that anyone in Cleverland would have pointed out was really not very clever.

While Mr Dizzy was building his user class he decided that it would be useful to have getPermissions() and getOrganisations() methods. These methods needed to make a query or more to the database to get the information they needed.

Mr Dizzy thought it might be a good idea to have the setters for these methods in a constructor so that when he needed a User object it would have gathered all the necessary information and was ready to go, so, he added setPermissions() and setOrganisations() methods.

“Great”, thought Mr Dizzy, and he proceeded to use his new user object. His idea seemed to be working well so he decided to use the same idea in his Organisation class so it could also get its own permissions on call. “Even better”, thought Mr Dizzy, “I can’t wait to show this to the other programmers in Cleverland”.

Before taking a trip to Cleverland, Mr Dizzy decided to finish off some code to allow him to show a list of users. This list included using many instances of his newly built user class.

Can you guess what happened?

Of course, every time a new user object was created so too was a new organisation object and so too was a new permissions object and all of these objects made database queries. Before long hundreds of queries had been made to the database, all hidden away nicely in constructors.

Luckily for Mr Dizzy he had done his usual trick of missing the last bus to Cleverland and had also recently installed the Zend_Db_Profiler which showed just how silly he had been before anyone else could see.

From that day on Mr Dizzy knew to be very careful when deciding what to do within constructors.

Obvious, but necessary disclaimer

Surprised as you may be, Roger Hargreaves, the original author of the excellent Mr Men series of children’s books, did not in fact author any of the above. Nor, unfortunately, was it narrated by Arthur Lowe, but I’d recommend that if you know his voice then you imagine him doing so.

Mr Dizzy is obviously copyright and I probably shouldn’t be messing with the classics, so if there are any copyright objections then I’m happy to alter this tribute. I do recommend that even if you don’t have kids you should own at least one Mr Men or Little Miss book if only for the great graphics!

Finally, I, of course, would never do something as silly as Mr Dizzy!

Zend Frameworking underwater.com.au

Tuesday, July 4th, 2006

Now that the host for underwater.com.au has upgraded to PHP5 I’m working on migrating it to use the Zend Framework. I thought it may be interesting to run through a few of the reasons I’ve chosen to do so especially while the framework is in such an early stage of development.

“Underware”

The engine, code-named “Underware”, that underwater.com.au currently runs on is built almost entirely (excluding a few additional class files) from my own code. Developed, via several projects, over the course of about five years from a modified version of the PHP e-Commerce application Freetrade and the FreeEnergy structure (Actually, it’s interesting to look back over that FreeEnergy article to see how it’s almost a Model-View-Controller structure), Underware is now more object-oriented, more MVC’ed and more woven with design patterns than its early incarnations, however it still has loose threads.

Why grow your own?

Considering the amount of freely-available, open-source, PHP code it seems idiotic to be doing it all yourself. Sadly, the number of applications available is no indication of their quality, nor whether they will play nicely together, a point taken up by Clay Loveless in his Stop Writing Loner Applications post.

At every stage of Underware’s development I looked at pre-existing solutions, hoping to find one that wouldn’t force me to duplicate components I already had, such as user management. It wasn’t necessarily that I had better code, more that what I did have was only what I needed. Besides, I knew as I worked on it the code quality would also improve. Inevitably, after spending many unbillable hours pouring through different solutions I’d look at the clock and think “I could have spent those hours moving forward and coding a solution”!

Pros of doing it all yourself

  • You only build, debug and support what you need.
  • You know all the code.
  • You learn a lot.

Cons of doing it all yourself

  • You have to build and support every bit of code and unless you build it it’s not just going to appear from somewhere.
  • You have to document it all.
  • You have to spend time researching solutions to every issue, including system level ones that are not directly providing solutions for your clients.

Thankfully the increasing amount of frameworks available (i.e. rather than finished applications) combined with the growing object-oriented’ness of PHP mean it’s less of an either or situation.

So why Zend Framework?

Honestly, I think because it feels right and I say that not to be facetious, but partly because I see so many lengthy arguments for and against such and such framework as if one or the other holds the golden key. Part of the reason I went back to my roots was to show the influences on my way of structuring web applications and if you’re interested enough to look into them you may see some similarities. For me the Zend Framework not only fits the way I’m currently working but moves it forward, tying up some of the aforementioned loose threads for example.

More pragmatically there are factors like the fact that my clients can worry less about being so totally dependant on me for every facet of their applications; I can benefit from all the external input to the framework itself; I can focus on solving client needs more and system level needs less and not to be ignored is the Zend part of the framework which for me puts at least some stamp of longevity and consistency on the code base.

Some further Underware influences

Some current Zend Framework reading

Custom View Helpers in Zend Framework

Monday, June 26th, 2006

The Zend Framework Manual describes View Helpers like so:

“In your view scripts, often it is necessary to perform certain complex functions over and over; e.g., formatting a date, generating form elements, or displaying action links. You can use helper classes to perform these behaviors for you.”

Currently the framework (version 0.1.3) includes a small selection of form helpers which will no doubt expand as it matures. For now I’m more interested in the ability to add custom helpers for specific project use. The first thing I did was to set up the same directory structure as Zend_View_Helper as is suggested when subclassing controllers:

library/
    Zend/
        View/
            Helper/
    MyProject/
        View/
            Helper/

Having my project specific helper files in library/MyProject/View/Helper/ will make it easy to keep them separate from Zend core updates.

The next step is to tell Zend_View to look in the custom helper directory as well as the default Zend helper directory. This just requires adding the new helper path to the Zend_View object I created in the public_html/index.php file:

$view = new Zend_View;
$view->addHelperPath('MyProject/View/Helper');

Cautionary Note (* see update below)

The above is actually a bit of a fiddle to get working if you decide like I did to use a relative path to your helper files. I had set…

set_include_path( /home/exciting_zfw_site/library/ );

…pointing to the main Zend library directory, however, Zend_View_Abstract:: _loadClass() uses is_readable() as a check before loading any helper or filter files like so…

if (is_readable($dir . $file)) {
    include $dir . $file;

    if (! class_exists($class, false)) {
        $msg = "$type '$name' loaded 
                        but class '$class' not found within";
        throw new Zend_View_Exception($msg);
    }

    return $class;
}

…and since is_readable just ignores include paths, your new helper files won’t be found. This is currently listed as a bug but for the moment I simply changed…

if (is_readable($dir . $file)) {
    include $dir . $file;

…to…

if (include $dir . $file) {

…and it worked fine. Portability was the reason I wanted to keep the paths relative as I move files from a development server to the live server. It’s much easier to keep as few path configuration settings as possible.

The next step is pretty well documented in the manual but for the sake of completeness I’ll keep going. Create a new helper file:

class Zend_View_Helper_DoStuff {

    public function doStuff()
    {
        return 'Hello to you all';
    }
}

Another Cautionary Note

Something that caught me out was that the new helper class must be called Zend_View_Helper_YourNameHere rather than MyProject_View_Helper_YourNameHere which seems a little odd considering it’s position in the directory structure I mentioned before. While logically it is a Zend_View helper class, it will be kept with other subclassed files with your own “namespaced” class names under the MyProject directory so it seems to break a convention.

Ready to use

After saving the new helper file in MyProject/View/Helper/DoStuff.php it should be available to use in your view scripts like so:

<?php echo $this->doStuff(); ?>

When writing helper classes the key points to initially getting them to work are the naming conventions as illustrated by my doStuff example:

  1. Class name must be Zend_View_Helper_DoStuff
  2. The class must contain a public function doStuff()
  3. The file must be save as DoStuff.php

As mentioned in my post on getting to know Zend_View elements of the above may well change as development continues.

Further Reading

View Helpers in the Zend Framework Manual

* Update

Forget the above hack…

if (include $dir . $file) {

…as it will produce warnings as Zend_View_Abstract::_LoadClass() attempts to include the doStuff file from any other path in the _path stack. Instead the only solution I’ve found to currently work is to specify a relative path like so:

$view->addHelperPath('../MyProject/UW/View/Helper');

File browsing in Vim

Wednesday, June 21st, 2006

Well-heeled Vim users will no doubt see the following as being pretty obvious. For anyone else like me fumbling around with Vim to the point of giving up, I hope this at least saves you the time I spent until the small hours of the morning!

The way I used to think

Coming from working with text editors like jEdit which, like others, has a file browser in a split pane, I had been trying to reproduce this in Vim.

Vim split into 4 panes

However, since upgrading to Vim 7, this had been causing irritations, like this routine to open a file:

  • Select a file in the left pane.
  • Click in a window in the right pane to indicate that was the one to open it in.
  • Go back to the file in the left pane and Shift-p to open it.

Forgetting to select the window to open it in meant it would open in the left pane instead, which was supposed to be my file browsing pane.

Not only that but for whatever reason I was getting an odd refresh when I moved to another application and back to Vim. This refresh was annoying enough to have me spend time reinstalling netrw, attempting to compile Vim for myself (which failed) and even taking time to try out Textmate.

All in all I was getting pretty fed up and was even converting the Euro to Aussie Dollar to see if I had enough pocket money to buy Textmate. Luckily, the stubbornness of anyone who has put the time into learning Vim wouldn’t go away and I stopped to have a look at the new tabs in Vim 7. It was then that I realised I’d been thinking about this all wrong…

Vim is about modes

My mistake was to think of any window in Vim as having a specific role and ignoring vim’s modal nature. I realised that file browsing was always there in the background as I edited a file and I didn’t need to have windows specifically assigned to file browsing.

The joy of :Ex (very poor, I know!)

The magic lies in the fact that the file browsing functionality of netrw is following you around as you go. For example, if I open …/Sites/zend_framework/library/Zend.php in a window…

Vim split horizontally with files

…and then hit :Ex I will be in that files directory…

Vim split horizontally with netrw in top

However, if I open a file from another directory in another window hitting :Ex for that window will bring up it’s directory. This then allows me to have a contextual file browser available at any time without having to move my hands from the keyboard.

Admittedly this is not exactly a nirvana attaining moment of enlightenment, but it’s certainly one of those “Aha!” moments that reinforces your faith in your tools and the time spent learning them.

Further Reading

Beginner’s guide to Vi Improved (vim)

Getting to know Zend_View

Saturday, June 10th, 2006

Like many other PHP developers I’m keeping an eye on the progress of the Zend Framework. It’s currently still in the very early stages of development but is nonetheless worth “getting to know”. These are some notes from a play around with the current View functionality.

I generally use a nested layout template file with PHP embedded in HTML. Variables are assigned by a controller file so a layout template may look like this “main_layout.php” file:

<body>
    <?php include 'modules/header.php'; ?>
    <?php include $page; ?>
    <?php include 'modules/footer.php'; ?>
</body>

After some much appreciated help from Paul M Jones and Simon Mundy on the Zend Framework General List, I now have the following three methods of doing the same in the Zend Framework.

Use Zend_View::_script()

Include the additional views directly in the layout using the Zend_View::_script() method:

<body>
    <?php include $this->_script('/modules/header.php') ?>
    <?php include $this->_script( $this->content ); ?>
    <?php include $this->_script('/modules/footer.php') ?>
</body>

Use assigned variables

Assign the additional views in the controller file and then use the variables in the layout:

In the view controller:

$view->header = $view->render('modules/header.php')
$view->content = $view->render('page.php')
$view->footer = $view->render('modules/footer.php')

In the view script:

<body>
    <?php echo $this->header; ?>
    <?php echo $this->content; ?>
    <?php echo $this->footer; ?>
</body>

Use Zend_View::render()

This seems to be the “proper” solution as it makes full use of the _file stack in render().

Call Zend_View::render() from within the view script:

<body>
    <?php $this->render('modules/header.php') ?>
    <?php $this->render( $this->content ) ?>
    <?php $this->render('modules/footer.php') ?>
</body>

The above three solutions all require a final call to render the whole layout in the view controller file, e.g.:

echo $view->render( 'layouts/main_layout.php' );

Cautionary Note

Since the framework is currently in preview release stage it’s possible that the above may change soon after posting this (though I suspect probably not much if at all).

Update (8th November)

As of the latest SVN checkouts Zend_View::render() does not echo the output so you will need to use…

<?php echo $this->render( $this->content ) ?>