using a helper to wrap injected markup

CakePHP’s FormHelper comes with several, intuitively-named options for injecting markup into a form element.

The option I use most frequently is “after”, a very simple way to append an explanatory note after a particular form element.

For example, as part of my “Venues” view let’s assume I have an input field for a phone number and I want to remind users to include their area code. I add this code to the view:

echo $this->Form->input('phone', array(
    'after' => 'Please include your area code.'
));

From which CakePHP generates this:

<div class="input tel">
    <label for="VenuePhone">Phone</label>
    <input id="VenuePhone" type="tel" maxlength="255" name="data[Venue][phone]">
    Please include your area code.
</div>

And while CakePHP makes it very easy to add a class to the input field, its error message, or enclosing DIV, there’s no such simple method for doing so to the injected markup. Rather, this is the suggestion:

echo $this->Form->input('phone', array(
    'after' => '<div class="after">Please include your area code.</div>'
));

If I’m only doing this in one place, fine. But if I’m looking to do this site-wide, it quickly becomes a great example of the particular form of cognitive dissonance I call “labor-intensive laziness”.

In the interest of staying DRY, we can instead create a helper, like so:

<!-- File: /app/View/Helper/AfterHelper.php -->
App::uses('FormHelper', 'View/Helper');
class AfterHelper extends FormHelper {
    public function input($name, $options = array()) {
        if (isset($options['after'])) {
            $options['after'] = "<div class='after'>".$options['after']."</div>";
        }
        return parent::input($name, $options);
    }
}

The helper extends the input function in FormHelper, enclosing the “after” markup in our wrapper and class. [While my example only addresses the “after” option, one could modify the other options as well, all within the same helper.]

We then use the className option to alias our helper, either within a specific controller or the AppController itself, depending on our desired scope:

public $helpers = array(
    'Html',
    'Form' => array(
        'className' => 'After' // alias of AfterHelper
    )
);