Skip to content

Commit

Permalink
added validation support to form helpers
Browse files Browse the repository at this point in the history
  • Loading branch information
kraih committed Sep 25, 2013
1 parent e2c3a2b commit c325cb4
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 38 deletions.
13 changes: 13 additions & 0 deletions lib/Mojolicious/Controller.pm
Expand Up @@ -415,6 +415,12 @@ sub url_for {
return $url;
}

sub validation {
my $self = shift;
return $self->stash->{'mojo.validation'}
||= $self->app->validator->validation->input($self->req->params->to_hash);
}

sub write {
my ($self, $chunk, $cb) = @_;
($cb, $chunk) = ($chunk, undef) if ref $chunk eq 'CODE';
Expand Down Expand Up @@ -895,6 +901,13 @@ to inherit query parameters from the current request.
# "/list?q=mojo&page=2" if current request was for "/list?q=mojo&page=1"
$c->url_with->query([page => 2]);
=head2 validation
my $validation = $c->validation;
Get L<Mojolicious::Validator::Validation> object for current request. Note
that this method is EXPERIMENTAL and might change without warning!
=head2 write
$c = $c->write;
Expand Down
13 changes: 3 additions & 10 deletions lib/Mojolicious/Plugin/DefaultHelpers.pm
Expand Up @@ -8,7 +8,7 @@ sub register {
my ($self, $app) = @_;

# Controller alias helpers
for my $name (qw(app flash param stash session url_for)) {
for my $name (qw(app flash param stash session url_for validation)) {
$app->helper($name => sub { shift->$name(@_) });
}

Expand All @@ -33,7 +33,6 @@ sub register {
$app->helper(include => \&_include);
$app->helper(ua => sub { shift->app->ua });
$app->helper(url_with => \&_url_with);
$app->helper(validation => \&_validation);
}

sub _content {
Expand Down Expand Up @@ -89,12 +88,6 @@ sub _url_with {
return $self->url_for(@_)->query($self->req->url->query->clone);
}

sub _validation {
my $self = shift;
return $self->stash->{'mojo.validation'}
||= $self->app->validator->validation->input($self->req->params->to_hash);
}

1;

=encoding utf8
Expand Down Expand Up @@ -262,8 +255,8 @@ request.
%= validation
Get L<Mojolicious::Validator::Validation> object for current request. Note
that this helper is EXPERIMENTAL and might change without warning!
Alias for L<Mojolicious::Controller/"validation">. Note that this helper is
EXPERIMENTAL and might change without warning!
=head1 METHODS
Expand Down
15 changes: 9 additions & 6 deletions lib/Mojolicious/Plugin/TagHelpers.pm
Expand Up @@ -82,12 +82,9 @@ sub _input {

# Others
else { $attrs{value} = $values[0] }

return _tag('input', name => $name, %attrs);
}

# Empty tag
return _tag('input', name => $name, %attrs);
return _wrap($self, $name, _tag('input', name => $name, %attrs));
}

sub _javascript {
Expand Down Expand Up @@ -162,7 +159,7 @@ sub _select_field {
return $parts;
};

return _tag('select', name => $name, %attrs, $optgroup);
return _wrap($self, $name, _tag('select', name => $name, %attrs, $optgroup));
}

sub _stylesheet {
Expand Down Expand Up @@ -227,7 +224,13 @@ sub _text_area {
$cb = sub { xml_escape $content }
}

return _tag('textarea', name => $name, @_, $cb);
return _wrap($self, $name, _tag('textarea', name => $name, @_, $cb));
}

sub _wrap {
my ($self, $name, $html) = @_;
return $html unless $self->validation->has_errors($name);
return _tag('div', class => 'fields_with_errors', sub {$html});
}

1;
Expand Down
18 changes: 9 additions & 9 deletions lib/Mojolicious/Validator.pm
Expand Up @@ -3,10 +3,10 @@ use Mojo::Base -base;

use Mojolicious::Validator::Validation;

has checks => sub { {range => \&_range} };
has checks => sub { {size => \&_size} };
has errors => sub {
{
range => sub {qq{Value needs to be $_[3]-$_[4] characters long.}},
size => sub {qq{Value needs to be $_[3]-$_[4] characters long.}},
required => sub {qq{Value is required.}}
};
};
Expand All @@ -24,7 +24,7 @@ sub _add {
return $self;
}

sub _range {
sub _size {
my ($validation, $name, $value, $min, $max) = @_;
my $len = length $value;
return $len >= $min && $len <= $max;
Expand Down Expand Up @@ -56,16 +56,16 @@ L<Mojolicious::Validator> implements the following attributes.
=head2 checks
my $checks = $validator->checks;
$validator = $validator->checks({range => sub {...}});
$validator = $validator->checks({size => sub {...}});
Registered checks, by default only C<range> is already defined.
Registered checks, by default only C<size> is already defined.
=head2 errors
my $errors = $validator->errors;
$validator = $validator->errors({range => sub {...}});
$validator = $validator->errors({size => sub {...}});
Registered error generators, by default only C<range> and C<required> are
Registered error generators, by default only C<required> and C<size> are
already defined.
=head1 METHODS
Expand All @@ -75,13 +75,13 @@ implements the following new ones.
=head2 add_check
$validator = $validator->add_check(range => sub {...});
$validator = $validator->add_check(size => sub {...});
Register a new check.
=head2 add_error
$validator = $validator->add_error(range => sub {...});
$validator = $validator->add_error(size => sub {...});
Register a new error generator.
Expand Down
2 changes: 1 addition & 1 deletion lib/Mojolicious/Validator/Validation.pm
Expand Up @@ -158,7 +158,7 @@ and implements the following new ones.
=head2 check
$validation = $validation->check('range', 2, 7);
$validation = $validation->check('size', 2, 7);
Perform validation check.
Expand Down
37 changes: 25 additions & 12 deletions t/mojolicious/validation_lite_app.t
Expand Up @@ -10,8 +10,11 @@ use Mojolicious::Lite;
use Test::Mojo;

get '/' => sub {
my $self = shift;
$self->validation->required('name')->range(2, 5);
my $self = shift;
my $validation = $self->validation;
$validation->required('foo')->size(2, 5);
$validation->optional('bar')->size(2, 5);
$validation->optional('baz')->size(2, 5);
} => 'index';

my $t = Test::Mojo->new;
Expand Down Expand Up @@ -39,18 +42,18 @@ ok $validation->has_errors, 'has errors';
is_deeply [$validation->errors('does_not_exist')->each],
['Value is required.'], 'right error';

# Range
# Size
$validation = $t->app->validation;
$validation->input({foo => 'bar', baz => 'yada', yada => 'yada'});
ok $validation->required('foo')->range(1, 3)->is_valid, 'valid';
ok $validation->required('foo')->size(1, 3)->is_valid, 'valid';
is_deeply $validation->output, {foo => 'bar'}, 'right result';
ok !$validation->has_errors, 'no errors';
ok !$validation->required('baz')->range(1, 3)->is_valid, 'not valid';
ok !$validation->required('baz')->size(1, 3)->is_valid, 'not valid';
is_deeply $validation->output, {foo => 'bar'}, 'right result';
ok $validation->has_errors, 'has errors';
is_deeply [$validation->errors('baz')->each],
['Value needs to be 1-3 characters long.'], 'right error';
ok !$validation->required('yada')->range(5, 10)->is_valid, 'not valid';
ok !$validation->required('yada')->size(5, 10)->is_valid, 'not valid';
is_deeply $validation->output, {foo => 'bar'}, 'right result';
ok $validation->has_errors, 'has errors';
is_deeply [$validation->errors('yada')->each],
Expand All @@ -70,13 +73,13 @@ ok !$validation->required('baz')->is_valid, 'not valid';
ok $validation->has_errors, 'has errors';
is_deeply [$validation->errors('baz')->each], ['Value is required.'],
'right error';
ok !$validation->required('foo')->error('Foo is too small.')->range(25, 100)
ok !$validation->required('foo')->error('Foo is too small.')->size(25, 100)
->is_valid, 'not valid';
ok $validation->has_errors, 'has errors';
is_deeply [$validation->errors('foo')->each], ['Foo is too small.'],
'right error';
is $validation->topic, 'foo', 'right topic';
ok !$validation->error('Failed!')->required('yada')->range(25, 100)->is_valid,
ok !$validation->error('Failed!')->required('yada')->size(25, 100)->is_valid,
'not valid';
ok $validation->has_errors, 'has errors';
is_deeply [$validation->errors('yada')->each],
Expand All @@ -85,15 +88,25 @@ is $validation->topic, 'yada', 'right topic';
ok $validation->has_errors('bar'), 'has errors';

# Successful validation
$t->get_ok('/?name=sri')->status_is(200)->content_is("\n");
$t->get_ok('/?foo=ok')->status_is(200)->element_exists('form > input')
->element_exists('form > textarea')->element_exists('form > select');

# Failed validation
$t->get_ok('/?name=sebastian')->status_is(200)
->content_is("Value needs to be 2-5 characters long.\n");
$t->get_ok('/?foo=too_long&bar=too_long_too&baz=way_too_long')->status_is(200)
->element_exists_not('form > input')
->element_exists('form > div.fields_with_errors > input')
->element_exists_not('form > textarea')
->element_exists('form > div.fields_with_errors > textarea')
->element_exists_not('form > select')
->element_exists('form > div.fields_with_errors > select');

done_testing();

__DATA__
@@ index.html.ep
%= $_ for validation->errors('name')->each
%= form_for index => begin
%= text_field 'foo'
%= text_area 'bar'
%= select_field baz => [qw(yada yada)]
% end

0 comments on commit c325cb4

Please sign in to comment.