Search code examples
phpkohanakohana-3

Kohana 3.2, displaying errors in the form


I'd like to display errors on my form, highlighting the fields which have errors, and displaying the error text next to the field. If there's no elegant way to display next to each field, above would be fine.

I've found examples from earlier versions, but the API has seemed to change and they do not work for 3.2.

It's just a project I'm learning Kohana with, so it's not critical. I just want to know the "kohana" way of handling this problem.

In my controller, I have this:

if (isset($_POST) && Valid::not_empty($_POST))
{
    $post = Validation::factory($_POST)
    ->rule('zipcode', 'not_empty'));

    if ($post->check()) {
        $errors = $post->errors('zipcode');
    }
}

$this->template->content = View::factory('myview', $data)
->bind('errors', $errors);

And here is my form in 'myview.php':

<?php echo Form::open(); ?>
<dl>
    <dt><?php echo Form::label('zipcode', 'Zip Code') ?></dt>
    <dd><?php echo Form::input('zipcode') ?></dd>
</dl>
<p><?php echo Form::submit(NULL, 'Get Records'); ?></p>
<?php echo Form::close(); ?>

Solution

  • I've taken the approach of extending the Form helper class to add an 'error' class name on the form fields, as well as showing the error message in the field label.

    <?php defined('SYSPATH') or die('No direct script access.');
    
    class Form extends Kohana_Form {
    
        private static function attributes($name, & $attributes = NULL, $errors = NULL)
        {
            // Set the id attribute
            if (!isset($attributes['id']))
            {
                $attributes['id'] = $name;
            }
    
            if ($errors !== NULL)
            {
                // Merge in external validation errors.
                $errors = array_merge($errors, (isset($errors['_external']) ? $errors['_external'] : array()));
    
                // Set the error classname
                if (isset($errors[$name]))
                {
                    $attributes['class'] = trim( (string) @$attributes['class'].' error-field');            
                }
            }
        }
    
        public static function input($name, $value = NULL, array $attributes = NULL, array $errors = NULL)
        {
            static::attributes($name, $attributes, $errors);
    
            return parent::input($name, $value, $attributes);
        }
    
        public static function select($name, array $options = NULL, $selected = NULL, array $attributes = NULL, array $errors = NULL)
        {
            static::attributes($name, $attributes, $errors);
    
            return parent::select($name, $options, $selected, $attributes);
        }
    
        public static function password($name, $value = NULL, array $attributes = NULL, array $errors = NULL)
        {
            static::attributes($name, $attributes, $errors);
    
            return parent::password($name, $value, $attributes);
        }
    
        public static function textarea($name, $body = '', array $attributes = NULL, $double_encode = TRUE, array $errors = NULL)
        {
            static::attributes($name, $attributes, $errors);
    
            return parent::textarea($name, $body, $attributes, $double_encode);
        }
    
        public static function file($name, array $attributes = NULL, array $errors = NULL)
        {
            static::attributes($name, $attributes, $errors);
    
            return parent::file($name, $attributes);
        }
    
        public static function label($input, $text = NULL, array $attributes = NULL, array $errors = NULL, $view = 'messages/label_error')
        {
            if ($errors !== NULL)
            {
                // Merge in external validation errors.
                $errors = array_merge($errors, (isset($errors['_external']) ? $errors['_external'] : array()));
    
                // Use the label_error view to append an error message to the label
                if (isset($errors[$input]))
                {
                    $text .= View::factory($view)->bind('error', $errors[$input]);
                }
            }
    
            return parent::label($input, $text, $attributes);
        }    
    } 
    

    You then pass in the $errors array into the label and field helper methods:

    <?php echo
        Form::label('username', 'Username', NULL, $errors),
        Form::input('username', $user->username, NULL, $errors);
    ?>
    

    This idea was suggested on the Kohana forums but I've struggled to find the original thread. Anyway, I've found this approach works best for me.

    [edit] View an example of this approach in action here: http://kohana3.badsyntax.co/contact (submit the form)