package HTML::FormFu::Constraint;
use strict;
use base 'HTML::FormFu::Processor';
use Class::C3;
use HTML::FormFu::Exception::Constraint;
use Scalar::Util qw/ blessed /;
use Carp qw/ croak /;
__PACKAGE__->mk_accessors(qw/ not force_errors when /);
sub process {
my ( $self, $params ) = @_;
my $value = $self->get_nested_hash_value( $params, $self->nested_name );
my @errors;
# check when condition
return unless $self->_process_when($params);
if ( ref $value eq 'ARRAY' ) {
push @errors, eval { $self->constrain_values( $value, $params ); };
if ($@) {
push @errors,
$self->mk_errors( {
pass => 0,
message => $@,
} );
}
}
else {
my $ok = eval { $self->constrain_value( $value, $params ); };
push @errors,
$self->mk_errors( {
pass => ( $@ || !$ok ) ? 0 : 1,
message => $@,
} );
}
return @errors;
}
sub constrain_values {
my ( $self, $values, $params ) = @_;
my @errors;
for my $value (@$values) {
my $ok = eval { $self->constrain_value( $value, $params ); };
push @errors,
$self->mk_errors( {
pass => ( $@ || !$ok ) ? 0 : 1,
message => $@,
} );
}
return @errors;
}
sub constrain_value {
croak "constrain_value() should be overridden";
}
sub mk_errors {
my ( $self, $args ) = @_;
my $pass = $args->{pass};
my $message = $args->{message};
my @errors;
my $force = $self->force_errors || $self->parent->force_errors;
if ( !$pass || $force ) {
my $error = $self->mk_error($message);
$error->forced(1) if $pass;
push @errors, $error;
}
return @errors;
}
sub mk_error {
my ( $self, $err ) = @_;
if ( !blessed $err || !$err->isa('HTML::FormFu::Exception::Constraint') ) {
$err = HTML::FormFu::Exception::Constraint->new;
}
return $err;
}
sub _process_when {
my ( $self, $params ) = @_;
# returns 1 if when condition is fullfilled or not defined
# returns 0 if when condition is defined and not fullfilled
# If it's a callback, return callback's return value (so when
# condition is met if callback returns a true value)
# get when condition
my $when = $self->when;
return 1 if !defined $when;
# check type of 'when'
croak "Parameter 'when' is not a hash ref" if ref $when ne 'HASH';
# field or callback must be defined
my $when_field = $when->{field};
my $when_callback = $when->{callback};
croak "Parameter 'field' or 'callback' is not defined"
if !defined $when_field && !defined $when_callback;
# Callback will be the preferred thing
if ($when_callback) {
no strict 'refs';
return $when_callback->($params);
}
# nothing to constrain if field doesn't exist
my $when_field_value = $params->{$when_field};
return 0 if !defined $when_field_value;
# a compare value must be defined
my @values;
my $compare_value = $when->{value};
push @values, $compare_value if defined $compare_value;
my $compare_values = $when->{values};
push @values, @$compare_values if ref $compare_values eq 'ARRAY';
croak "Parameter 'value' or 'values' are not defined" unless @values;
# determine if condition is fullfilled
my $fullfilled = grep { $when_field_value eq $_ } @values;
# invert when condition if asked for
$fullfilled = $when->{not} ? !$fullfilled : $fullfilled;
return $fullfilled;
}
1;
__END__
=head1 NAME
HTML::FormFu::Constraint - Constrain User Input
=head1 SYNOPSIS
---
elements:
- type: Text
name: foo
constraints:
- type: Length
min: 8
when:
field: bar
values: [ 1, 3, 5 ]
- type: Text
name: bar
constraints:
- Integer
- Required
constraints:
- SingleValue
=head1 DESCRIPTION
User input is processed in the following order:
=over
=item L
=item L
=item L
=item L
=item L
=back
See L for further details.
L can be called on any L