The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

Data::Transpose::Validator - Filter and validate data.

SYNOPSIS

use Data::Transpose::Validator;
my $dtv = Data::Transpose::Validator->new();
$dtv->prepare(email => {validator => 'EmailValid',
                        required => 1},
              password => {validator => 'PasswordPolicy',
                           required => 1}
             );

my $form = {
            email => "aklasdfasdf",
            password => "1234"
           };

my $clean = $dtv->transpose($form);
if ($clean) {
    # the validator says it's valid, and the hashref $clean is validated
    # $clean is the validated hash
} else {
    my $errors = $dtv->errors; # arrayref with the errors
    # old data
    my $invalid_but_filtered = $dtv->transposed_data; # hashref with the data
}

DESCRIPTION

This module provides an interface to validate and filter hashrefs, usually (but not necessarily) from HTML forms.

METHODS

new

The constructor. It accepts a hash as argument, with options:

stripwhite: strip leading and trailing whitespace from strings (default: true)

collapse_whitespace: collapse all the consecutive whitespace characters into a single space. This basically will do a s/\s+/ /gs against the value, so will remove all newlines and tabs as well. Default is false.

requireall: require all the fields of the schema (default: false)

unknown: what to do if other fields, not present in the schema, are passed.

    fail: The transposing routine will die with a message stating the unknown fields

    pass: The routine will accept them and return them in the validated hash

    skip: The routine will ignore them and not return them in the validated hash. This is the default.

missing: what to do if an optional field is missing

    pass: do nothing, don't add to the returning hash the missing keys. This is the default.

    undefine: add the key with the undef value

    empty: set it to the empty string;

option($option, [ $value ]);

Accessor to the options set. With an optional argument, set that option.

$dtv->option("requireall"); # get 
$dtv->option(requireall => 1); # set

This is another way to say $dtv->requireall(1);

option_for_field($option, $field)

Accessor to get the option for this particular field. First it looks into the fields options, then into the global ones, returning the first defined value.

$dtv->option(email => "stripwhite");

options

Accessor to get the list of the options

$dtv->options;
# -> requireall, stripwhite, unknown

prepare(%hash) or prepare([ {}, {}, ... ])

prepare takes a hash and pass the key/value pairs to field. This method can accept an hash or an array reference. When an arrayref is passed, the output of the errors will keep the provided sorting (this is the only difference).

You can call prepare as many times you want before the transposing. Fields are added or replaced, but you could end up with messy errors if you provide duplicates, so please just don't do it (but feel free to add the fields at different time as long you don't overwrite them.

To prevent bad configuration, as of version 0.0005 overwriting an existing field raises an exception.

$dtv->prepare([
                { name => "country" ,
                  required => 1,
                },
                {
                 name => "country2",
                 validator => 'String'},
                {
                 name => "email",
                 validator => "EmailValid"
                },
               ]
              );

or

$dtv->prepare(
              country => {
                          required => 1,
                         },
              country2 => {
                           validator => "String"
                          }
             );

## other code here

$dtv->prepare(
             email => {
                       validator => "EmailValid"
                      }
             );

The validator value can be an string, a hashref or a coderef.

When a string is passed, the class which will be loaded will be prefixed by Data::Transpose::Validator:: and initialized without arguments.

If a coderef is passed as value of validator, a new object Data::Transpose::Validator::Subrefs is created, with the coderef as validator.

If a hashref is passed as value of validator, it must contains the key class and optionally options as an hashref. As with the string, the class will be prefixed by Data::Transpose::Validator::, unless you pass the absolute key set to a true value.

$dtv->prepare(
        email => {
            validator => "EmailValid",
             },

        # ditto
        email2 => {
             validator => {
                     class => "EmailValid",
                    }
            },

        # tritto
        email3 => {
             validator => {
                     class => "Data::Transpose::Validator::EmailValid",
                     absolute => 1,
                    }
            },

        # something more elaborate
        password => {
               validator => {
                     class => PasswordPolicy,
                     options => {
                           minlength => 10,
                           maxlength => 50,
                           disabled => {
                                  username => 1,
                                 }
                          }
                    }
            }
       );

Groups

You can set the groups either calling group (see below) or with prepare, using the validator Group with fields.

Using an arrayref:

$dtv->prepare([
               {
                 name => 'password',
                 required => 1,
                },
                {
                 name => 'confirm_password',
                 required => 1,
                },
                {
                 name => 'passwords',
                 validator => 'Group',
                 fields => [
                            qw/password confirm_password/,
                           ],
                 equal => 1,
                },
               ]
               );

Or using an hash

$dtv->prepare(password => { required => 1 },
              confirm_password => { required => 1 },
              passwords_matching => {
                                     validator => 'Group',
                                     fields => [ "password", "confirm_password" ]
                                    });

By default, if a group is set, it will be checked if all the fields match. So using the above schema, you'll get:

ok $dtv->transpose({ password => "a", confirm_password => "a" });
ok !$dtv->transpose({ password => "a", confirm_password => "b" });

Bundled classes

Each class has its own documentation for the available options. The options are passed to the new constructor of the validator's class.

CreditCard

See Data::Transpose::Validator::CreditCard

Options: types and country

EmailValid

See Data::Transpose::EmailValid (no special options)

NumericRange

See Data::Transpose::Validator::NumericRange

Options: min, max, integer

PasswordPolicy

See Data::Transpose::PasswordPolicy (plenty of options, refers to the documentation).

Set

See Data::Transpose::Validator::Set.

Options: list pointing to an arrayref and the multiple boolean (to validate an arrayref).

String

See Data::Transpose::Validator::String (no special options).

URL

See Data::Transpose::Validator::URL (no special options).

field($field)

This accessor sets the various fields and their options. It's intended to be used only internally, but you can add individual fields with it

$dtv->field(email => { required => 1 });

If the second argument is a string, it is assumed as the validator name. E.g.

$dtv->field(email => 'EmailValid');

This by itself use the EmailValid with the default settings. If you want fine control you need to pass an hashref. Also note that unless you specified requireall as true in the constructor, you need to set the require.

So these syntaxes do the same:

$dtv->field(email => { required => 1,
                       validator => 'EmailValid',
                     });
$dtv->field(email => 'EmailValid')->required(1);

With 1 argument retrieves the object responsible for the validation of that field, so you can call methods on them:

$dtv->field(email => { required => 0 })->required(1);
$dtv->field('email')->required # return true

You can also pass options for the validator, e.g.:

$dtv->field('month' => { validator => 'NumericRange',
                         options => {
                             min => 1,
                             max => 12,
                             integer => 1
                         },
                        });

WARNING: Earlier versions of this method without any argument would have retrieved the whole structure. Now it dies instead.

group (name => $field1, $field2, $field3, ...)

Create a named group of fields and schedule them for validation.

The logic is:

First, the individual fields are normally checked according to the rules provided with prepare or field.

If they pass the test, the group operation are checked.

Group by itself returns a Data::Transpose::Validator::Group object, so you can call methods on them to set the rules.

E.g. $self->group("passwords")->equal(1) # not needed it's the default

groups

Retrieve the list of the group objects scheduled for validation

transpose

The main method. It validates the hash and return a validated one or nothing if there were errors.

success

Returns true on success, 0 on failure and undef validation didn't take place.

transposed_data

Accessor to the transposed hash. This is handy if you want to retrieve the filtered data after a failure (because transpose will return undef in that case).

errors

Accessor to set or retrieve the errors (returned as an arrayref of hashes). Each element has the key field set to the fieldname and the key errors holds the error list. This, in turn, is a list of arrays, where the first element is the error code, and the second the human format set by the module (in English). See the method belows for a more accessible way for the errors.

errors_iterator

Returns error iterator.

errors_hash

Return an hashref where each key is the name of the error field, and the value is an arrayref of hashrefs with two keys, name and value.

Example of the returned hash:

{
 year => [
          {
           value => 'Not a number',
           name => 'notanumber',
          },
          {
           name => 'notinteger',
           value => 'Not an integer',
          }
         ],
 mail => [
          {
           value => 'Missing required field mail',
           name => 'required',
          }
         ],
}

faulty_fields

Accessor to the list of fields where the validator detected errors.

errors_as_hashref_for_humans

Accessor to get a list of the failed checks. It returns an hashref with the keys set to the faulty fields, and the value as an arrayref to a list of the error messages.

errors_as_hashref

Same as above, but for machine processing. It returns the lists of error codes as values.

packed_errors($fieldsep, $separator)

As convenience, this method will join the human readable strings using the second argument, and introduced by the name of the field concatenated to the first argument. Example with the defaults (colon and comma):

password: Wrong length, No special characters, No letters in the
password, Found common password, Not enough different characters,
Found common patterns: 1234
country: My error
email2: rfc822

In scalar context it returns a string, in list context returns the errors as an array, so you still can process it easily.

field_is_required($field)

Check if the field is required. Return true unconditionally if the option requireall is set. If not, look into the schema and return the value provided in the schema.

reset_self

Clear all the internal data stored during validations, to make the reusing of the transposing possible.

This is called by transpose before doing any other operation

EXPORT

None by default.

SEE ALSO

http://xkcd.com/936/

AUTHOR

Marco Pessotto, <melmothx@gmail.com>

COPYRIGHT AND LICENSE

Copyright (C) 2013-2016 by Marco Pessotto

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.10.1 or, at your option, any later version of Perl 5 you may have available.