NAME
MooX::Params::CompiledValidators - A Moo::Role for using Params::ValidationCompiler.
SYNOPSIS
use Moo;
use Types::Standard qw( Str );
with 'MooX::Params::CompiledValidators';
sub any_sub {
my $self = shift;
my $arguments = $self->validate_parameters(
{
$self->parameter(customer_id => $self->Required),
},
{ @_ }
);
...
}
# Implement a local version of the ValidationTemplates
sub ValidationTemplates {
return {
customer_id => { type => Str },
};
}
DESCRIPTION
This role uses Params::ValidationCompiler to create parameter validators on a per method basis that can be used in the methods of your Moo or Moose projects.
The objective is to create a single set of validation criteria - ideally in a seperate role that can be used along side of this role - that can be used to consistently validate parameters throughout your application.
The validators created by Params::ValidationCompiler are cached after they are created the first time, so they will only be created once.
Validation-Templates
A validation-template is a structure (HashRef) that
Params::ValidationCompiler::validation_for() uses to validate the parameter
and basically contains three keys:
-
type
Params::ValidationCompilersupports a number of type systems, see their documentation. -
default
Define a default value for this parameter, either a simple scalar or a code-ref that returns a more complex value.
-
optional
By default false, required parameters are preferred by
Params::ValidationCompiler
The required ValidationTemplates() method
The objective of this module (Role) is to standardise parameter validation by
defining a single set of Validation Templates for all the parameters in a project.
This is why the MooX::Params::CompiledValidators role requires a
ValidationTemplates method in its consuming class. The ValidationTemplates
method is needed for the parameter() method that is also supplied by this
role.
This could be as simple as:
package MyTemplates;
use Moo::Role;
use Types::Standard qw(Str);
sub ValidationTemplates {
return {
customer_id => { type => Str },
username => { type => Str },
};
}
The Required method
validation_for() uses the attribute optional so this returns 0
The Optional method
validation_for() uses the attribute optional so this returns 1
The validate_parameters() method
Returns a (locked) hashref with validated parameters or die()s trying...
Given:
use Moo;
with 'MooX::Params::CompiledValidators';
sub show_user_info {
my $self = shift;
my $args = $self->validate_parameters(
{
customer_id => { type => Str, optional => 0 },
username => { type => Str, optional => 0 },
},
{ @_ }
);
return {
customer => $args->{customer_id},
username => $args->{username},
};
}
One would call this as:
my $user_info = $instance->show_user_info(
customer_id => 'Blah42',
username => 'blah42',
);
Parameters
Positional:
-
$validation_templatesA hashref with the parameter-names as keys and the "Validation-Templates" as values.
-
$valuesA hashref with the actual parameter-name/value pairs that need to be validated.
Responses
-
Success (scalar context, recommended)
A locked hashref.
-
Success (list context, only if you need to manipulate the result)
A list that can be coerced into a hash.
-
Error
Anything Params::ValidationCompiler will throw for invalid values.
The validate_positional_parameters() method
Like $instance->validate_parameters(), but now the pairs of name,
validation-template are passed in an arrayref, that is split into lists of
the names and templates. The parameters passed -as an array- will be validated
against the templates-list, and the validated results are combined back into
a hash with name/value pairs. This makes the programming interface almost the
same for both named-parameters and positional-parameters.
Returns a (locked) hashref with validated parameters or die()s trying...
Given:
use Moo;
with 'MooX::Params::CompiledValidators';
sub show_user_info {
my $self = shift;
my $args = $self->validate_positional_parameters(
[
customer_id => { type => Str, optional => 0 },
username => { type => Str, optional => 0 },
],
\@_
);
return {
customer => $args->{customer_id},
username => $args->{username},
};
}
One would call this as:
my $user_info = $instance->show_user_info('Blah42', 'blah42');
Parameters
Positional:
-
$validation_templatesA arrayref with pairs of parameter-names and "validation templates".
-
$valuesA arrayref with the actual values that need to be validated.
Responses
-
Success (list context)
A list that can be coerced into a hash.
-
Success (scalar context)
A locked hashref.
-
Error
Anything Params::ValidationCompiler will throw for invalid values.
The parameter() method
Returns a parameter_name, validation_template pair that can be used in the
parameters argument hashref for
Params::ValidationCompiler::validadion_for()
Parameters
Positional:
-
$name(Required)The name of this parameter (it must be a kind of identifier:
m{^\w+$}) -
$required(Optional)One of
$class->Requiredor$class->Optionalbut will default to$class->Required. -
$extra(Optional)This optional HashRef can contain the fields supported by the
paramsparameter ofvalidation_for(), even overriding the ones set by the$class->ValidationTemplates()for this$name- althoughoptionalis set by the previous parameter in this sub.This parameter is mostly used for the extra feature to pass a lexically scoped variable via store.
Responses
-
Success
A list of
$parameter_nameand$validation_template.
(this_parm => { optional => 0, type => Str, store => \my $this_param })
NOTE on "Unknown" parameters
Whenever $self->parameter() is called with a parameter-name that doesn't
resolve to a template in the ValidationTemplates() hash, a default "empty"
template is produced. This will mean that there will be no validation on that
value, although one could pass one as the third parameter:
use Moo;
use Types::Standard qw( StrMatch );
with qw(
MyTemplates
MooX::Params::CompiledValidators
);
sub show_user_info {
my $self = shift;
my $args = $self->validate_parameters(
{
$self->parameter(customer_id => $self->Required),
$self->parameter(
email => $self->Required,
{ type => StrMatch[ qr{^ [-.\w]+ @ [-.\w]+ $}x ] },
),
},
{@_}
);
return {
customer => $args->{customer_id},
email => $args->{email},
};
}
The extra store attribute
Both validate_parameters() and validate_positional_parameters support the
extra store attribute in a validation template that should be a
scalar-reference where we store the value after successful validation.
One can pick and mix with validation templates:
use Moo;
use Types::Standard qw( StrMatch );
with qw(
MyTemplates
MooX::Params::CompiledValidators
);
sub show_user_info {
my $self = shift;
$self->validate_parameters(
{
$self->parameter(customer_id => $self->Required, {store => \my $customer_id),
email => {
type => StrMatch[ qr{^ [-.\w]+ @ [-.\w]+ $}x ],
optional => 0,
store => \my $email
},
},
{ @_ }
);
return {
customer => $customer_id,
email => $email,
};
}
One would call this as:
my $user_info = $instance->show_user_info(
customer_id => 'Blah42',
email => 'blah42@some.tld',
);
One could argue that using (lexical) variables -instead of addressing keys of a locked hash- triggers the error caused by a typo at compile-time rather than at run-time.
NOTE: In order to keep the scope of the variable, where the value is stored,
limited, the store attribute should only be used from the per method override
option extra for $self->parameter().
AUTHOR
© MMXXI - Abe Timmerman abeltje@cpan.org
LICENSE
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.