Tudor Barbu's blog

Ramblings about software development

17 Feb

Zend Framework and hidden fields

Posted by Tudor. Tags: , ,

One thing I really hate about forms in Zend Framework is the fact that the hidden fields are displayed as blank lines – sounds stupid but this is what really happens – and if you have more than one – let’s say 4 or 5 – their presence can become really annoying and ruin the layout. This happens because although the hidden fields aren’t shown by the browser, their wrapping tags are. ZF wraps all the form elements in additional markup with the help of decorators. The default XHTML for a hidden field in a Zend_Form looks something like this:

<dt>&nbsp;</dt>
<dd><input type="hidden" id="myElement" name="myElement" /></dd>

The definition tags have display:block, so they insert a lot of empty spaces in the layout. Which in the end will make the designer very unhappy. The solution is to remove all the definition tags or to hide them. Since this is presentational matter, it should fall to a view helper. The first idea was to remove the tags completely for hidden fields. Like such:

class Motanelu_View_Helper_FormFixer {
    public function formFixer( Zend_Form $_form ) {
        foreach( $_form->getElements() as $element ) {
            if( $element instanceof Zend_Form_Element_Hidden ) {
                $element->removeDecorator( 'HtmlTag' );
                $element->removeDecorator( 'Label' );
            }
        }
        return $_form;
    }
}

…and in the view (assuming that the helper is the the right path and will be picked out automatically by Zend Framework)…

echo $this->formFixer( $this->form );

Should do the trick. And it does. A lame trick :) If there are more elements in the form, the resulting markup will look something like this:

<form enctype="application/x-www-form-urlencoded" action="" method="post">
    <dl class="zend_form">
        <dt><label for="name" class="optional">Enter your name</label></dt>
        <dd><input type="text" name="name" id="name" value="" /></dd>
        <input type="hidden" name="id" value="" id="id" />
        <dt>&nbsp;</dt>
        <dd><input type="submit" name="submit" id="submit" value="Go go go!" /></dd>
    </dl>
</form>

Yep, that’s right! Invalid code. Not good. Another approach would be to hide the dt and dd tags that wrap around hidden fields with CSS. First attempt:

class Motanelu_View_Helper_FormFixer {
    public function formFixer( Zend_Form $_form ) {
        foreach( $_form->getElements() as $element ) {
            if( $element instanceof Zend_Form_Element_Hidden ) {
                foreach( $element->getDecorators() as $decorator ) {
                    $decorator->setOption( 'class', 'hidden' );
                }
            }
        }
        return $_form;
    }
}

But this doesn’t work as expected. The code above will produce:

<dt>&nbsp;</dt>
<dd class="hidden"><input type="hidden" name="id" value="" id="id" /></dd>

The dt doesn’t have the hidden class added to it. After some debugging, I’ve found why. It’s not a bug, it’s an…well…undocumented feature of Zend Framework.

// Zend_Form_Decorator_Label - line 306
if (!empty($label)) {
    $options['class'] = $class;
    $label = $view->formLabel($element->getFullyQualifiedName(), trim($label), $options);
} else {
    $label = '&nbsp;';
}

I’m very curious who is the rocket scientist that came up with this idea and more important why. Why shouldn’t I be allowed to change the class of an empty label? Well, never mind…But since it’s a very bad practice to change a framework’s source code, I’ve looked for a workaround. And found one: if the element doesn’t have a label, I’ll add a blank one. Like such:

class Motanelu_View_Helper_FormFixer {
    public function formFixer( Zend_Form $_form ) {
        foreach( $_form->getElements() as $element ) {
            if( $element instanceof Zend_Form_Element_Hidden ) {
                $label = $element->getLabel();
                if( empty( $label ) ) {
                    $element->setLabel( '&nbsp;' );
                }
                foreach( $element->getDecorators() as $decorator ) {
                    $decorator->setOption( 'class', 'hidden' );
                }
            }
        }
        return $_form;
    }
}

After adding the following code to my CSS file

.hidden {
    display: none;
}

…I can finally say that it works, that all the hidden fields stay hidden and that the resulting markup will validate even against the draconian XHTML Strict specification of the W3C.

air_appicon_150x150As previously stated, I intend to get my bachelor degree this year. And I have to chose from a variety of projects. I have 2 options, either choose a PHP project, that will be ready in no time and get rid of it fast or choose to do a project with a technology I don’t know yet and learn that technology in the process, so that I can honestly that I’ve learn something useful while in school. I decided to give AIR a try, for one possible project, a RSS aggregator and a RSS reader (desktop app). I if get along with AIR, this will be painless. I’ll develop the browser based application and use AIR to build the desktop one on top of this one.

Installing AIR on my Ubuntu box was a piece of cake, it worked right out the box. Unfortunately I can’t say the same about Aptana, which kept poping errors and I had a hard time installing the AIR plugin. But I get this type of problems a lot when dealing with Eclipse based software and I got used to it in time…

So I’ve the gas and tried out some code examples. Copy/paste, monkey style, see how well it does. Well, what can I say…I’m impressed. If this was a gaming blog, I would have to say “AIR pwnz”. Really! AIR is a much developer friendly platform that I initially thought. So today I’m starting my AIR learning quest for 1 week and at which end I’ll decide if I’ll go forward with AIR for my project. As I’m a seasoned web developer, I want to see how easy it is to port an web application from a browser based app to an AIR one. Yes, I know AIR does that by default. And not quite. For instance, in order to send something to the server, in Javascript you use Ajax, like such

new Ajax.Request( url, options);

…while in AIR you have to write…

var request = new air.URLRequest( url );
var loader = new air.URLLoader();
loader.load( request );

If I were to use a design pattern like MVC, it will be a lot easier to port a browser application to AIR. I’ll have to rewrite the model and probably the view. No meddling with the controller, the application’s logic would remain unchanged (parse some feeds and display them to the user). This would be a big plus. So first of all I’ve wanted to try AIR with Javascript MVC and make some sniffing in the controller, see if the application is running inside the browser or on AIR, load a different model and a different view for each case. But after giving it some thought I’ve realised that I also have to read the Javascript MVC’s documentation, try it out and get used to it. And I just don’t have enough time for that, because those South Park episodes aren’t going to watch themselves. Or do I? I’ll post some code examples as things go forward. This is a plead to my readers, if any of you is familiar with AIR, please leave a comment. I would appreciate having someone to share my problems with ;)

Motto: I’m not fat, I’m just big boned. Back to South Park…

31 Jan

Zend Framework base url

Posted by Tudor. Tags: ,

I’m a new Zend Framework user, coming from CakePHP. I like ZF’s approach on things, it’s much more flexible and allows a greater degree of control on things. (this doesn’t mean I’ve given up on CakePHP, I have a post comparing these two on the way). But still, Zend Framework lacks some – quite basic – features, such as the ability to easily get the application’s root url.

I’ve googled around for a solution and found this post on Thijs Lensselink’s blog. His first implementation was:

class Zend_View_Helper_BaseUrl
{
    function baseUrl()
    {
        $base_url = substr($_SERVER['PHP_SELF'], 0, -9);
        return $base_url;
    }
}

Quite an interesting approach, that works most of the times, because no matter how complicated the url is (www.example.com/controller/action/first/value1/second/value2/and-so/on) it will still be rewritten to the index.php file by Apache’s mod_rewrite. Thus, the value stored in the $_SERVER['PHP_SELF'] superglobal will always be the site’s URL in the format www.example.com/index.php. The string “index.php” is 9 characters long, so the substr will return the correct base url.

But if the project was launched in a hurry and still has some bugs, it’s a good idea to call it a beta version. It’s quite a common practice nowadays, in our web2.0 world to hold a project in a perpetual beta. So, instead of www.example.com, one might want to rewrite all the urls to www.example.com/beta. This is quite simple to achieve with ZF, with some minor changes in the bootstrap.php file:

$front_controller = Zend_Controller_Front::getInstance();
// your bootstrap
$request = new Zend_Controller_Request_Http();
$request->setBaseUrl( $request->getBaseUrl() . '/beta' );
$front_controller->dispatch( $request );

Now, the first approach – with substr – won’t work as expected. That leaves us with one bullet proof option: to write a helper that will return the base url that is encapsulated in the front controller object.

/**
 * Helper that retuns the base url
 *
 * @package View Helpers
 */

class Generic_View_Helper_BaseUrl {
    /**
     * returns the base url
     *
     * @return string
     */
    public function baseUrl() {
        return Zend_Controller_Front::getInstance()->getBaseUrl();
    }
}
// EOF

And this won’t create overhead, because Zend_Controller_Front::getInstance() returns a static singleton object, just as the user called Gary said on the original post.

10 Jan

Page titles and MVC

Posted by Tudor. Tags: ,

After taking the Zend PHP 5 exam, I’m focusing on the Zend Framework (I think that the sidebar on the right hand side could use a little green :P ). A more theoretical subject today. It’s about the page’s <title> tag and the MVC pattern. According to CakePHP’s implementation of the MVC, the decision about a page’s title should be taken at the “controller level”.

class StudentsController extends AppController {
    public function index() {
        $this->pageTitle = 'View all students'; // setting the page title
    }
}

In Zend’s documentation, I couldn’t find anything on this issue, as ZF is much more permissive than CakePHP and anyone can choose his own way to do things. And it isn’t always a good thing. Sometimes less options are better. In Zend Framework, you can set the page title in the controller, like such:

class StudentsController extends Zend_Controller_Action {
	public function indexAction() {
		$this->_helper->layout()->getView()->headTitle('View all students'); //  setting the page title
	}
}

or in the view

/**
 * views/scripts/students/index.phtml
 */
$this->headTitle('View all students');

The main question here is if the title is tag is business logic or presentation. Due to the title tag high impact on SEO and my CakePHP background, I personally lean towards the first option. The title isn’t just presentation, it’s more than that and setting the title should be done at the controller level.

28 Dec

Javascript MVC

Posted by Tudor. Tags: , ,

Javascript Model View Controller

I’ve stumbled upon this javascript MVC framework. I didn’t quite get a good look at it, but it sound pretty promising and I’m going to experiment with it, as I’m a big fan of MVC frameworks.

So far I’ve used Zend Framework, CakePHP, looked over CodeIngiter and Symfony. Even tried Rails, but I didn’t like Ruby at all so I quit RoR after about 30 minutes. I consider MVC to be the best development pattern I’ve encountered so far. But I’ve always used it on the server side. Now I have the chance to see how MVC behaves on the client side.

I’m quite confident that this approach will save a lot of headaches, due to the separation of concerns. The thing I’m most excited with are the views, because all the cross-browser issues will most likely migrate here. And solving a small problem in IE 6 won’t jeopardize the rest of the application, by following the pattern we all know and hate – solve a bug, add 3 new ones in its place.

PS: this is just small talk, as I haven’t tried Javascript MVC so far…:P