Coder1
Coder1

Reputation: 13321

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(); ?>

Upvotes: 0

Views: 2897

Answers (2)

badsyntax
badsyntax

Reputation: 9650

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)

Upvotes: 3

ndequeker
ndequeker

Reputation: 8010

This is some sample code I have used for a personal experiment with Kohana forms. It is part of a contact form. This should work for you.

The code below shows a contact form. After a user submits the form, it gives feedback (failed + errors / succeed).

if (isset($errors) && count($errors) > 0)
{
    echo '<ul>';

    foreach ($errors as $error)
    {
        echo '<li>' . $error . '</li>';
    }

    echo '</ul>';
}
// form
echo Form::open(null);

    // fields
    echo Form::label('firstname') . Form::input('firstname', null, array('id' => 'firstname')) . '<br />';
    echo Form::label('email') . Form::input('email', null, array('id' => 'email')) . '<br />';
    echo Form::label('message') . Form::textarea('message', '', array('id' => 'message')) . '<br />';

    // submit
    echo Form::submit('submit', 'Send message');

echo Form::close();

In the controller, I validate the form and assign the error- and success messages to the view.

public function action_index()
{
    // make view
    $view = View::factory('pages/contact')
        ->bind('post', $post)
        ->bind('errors', $errors)
        ->bind('success', $success);

    // check if form is submitted
    if ($_POST)
    {
        // trim fields
        $post = array_map('trim', $_POST);

        $post = Validation::factory($_POST)
            ->rules('firstname', array(
                array('not_empty'),
                array('min_length', array(':value', '2'))
            ))
            ->rules('email', array(
                array('not_empty'),
                array('email')
            ))
            ->rule('message', 'not_empty');

        if ($post->check())
        {
            $success[] = 'Thank you for your message!';
        }
        else
        {
            $errors = $post->errors('contact');
        }
    }

    // view
    $this->response->body($view);
}

I hope this helps!

Upvotes: 0

Related Questions