NAME

Valiant::Filters - Role that adds class and instance methods supporting field filters

SYNOPSIS

    package Local::Test::User;

    use Moo;

    with 'Valiant::Util::Ancestors',
      'Valiant::Filterable';

    has 'name' => (is=>'ro', required=>1);
    has 'last' => (is=>'ro', required=>1);

    __PACKAGE__->filters(last => (Trim=>1));

    __PACKAGE__->filters_with(sub {
      my ($class, $attrs, $opts) = @_;
      $attrs = +{
        map {
          my $value = $attrs->{$_};
          $value =~ s/^\s+|\s+$//g;
          $_ => $value;
        } keys %$attrs
      };
      $attrs->{name} = "$opts->{a}$attrs->{name}$opts->{b}";
      return $attrs;
    }, a=>1, b=>2);

    __PACKAGE__->filters_with(Foo => (a=>1,b=>2));

    __PACKAGE__->filters(last => (
      uc_first => 1,
      with => sub {
        my ($class, $attrs, $name) = @_;
        return $attrs->{$name} . "XXX";
      },
      sub {
        my ($class, $attrs, $name) = @_;
        return $attrs->{$name} . "AAA";
      },
    ));

DESCRIPTION

This is a role that adds class level filtering to you Moo or Moose classes. Generally you may prefer to us Valiant::Filters since that gives you a nice DSL for applying filters to your classes but if you have very special or custom needs (or you need to extend the filter API itself) you might need to use the role directly.

CLASS METHODS

filters

Used to declare filters on an attribute. The first argument is either a scalar or arrayref of scalars which should be attributes on your object:

    __PACKAGE__->filters( name => (...) );
    __PACKAGE__->filters(['name', 'age'] => (...));

Following arguments should be in one of two forms: a coderef or subroutine reference that contains filter rules or a key - value pair which is a class and its arguments:

    __PACKAGE__->filters( name => (
      trim => 1,
      with => sub { my ($class, $attrs, $name) = @_; },
      sub { my ($class, $attrs, $name) = @_; }m
    ));

When you use a Filter class (such as trim = { maximum => 25 }>) we resolve the class name trim in the following way. We first camel case the name and then look for a 'Filter' package in the current class namespace. If we don't find a match we check each namespace up the hierarchy and then check the two global namespaces Valiant::FilterX and Validate::Filters. For example if you declare filters as in the example class Local::Model::User we would look for the following:

    Local::Model::User::Filter::Trim
    Local::Model:::Filter::Trim
    Local::Filter::Trim
    Validator::Trim
    Valiant::FilterX::Trim
    Valiant::Filter:::Trim

These get checked in the order above and loaded and instantiated once at setup time.

NOTE: The namespace Valiant::Filter is reserved for filters that ship with Valiant. The Valiant::FilterX namespace is reserved for additional filters on CPAN that are packaged separately from Valiant. If you wish to share a custom fiter that you wrote the proper namespace to use on CPAN is Valiant::FilterX.

You can also prepend your filter name with '+' which will cause Valiant to ignore the namespace resolution and try to load the class directly. For example:

    __PACKAGE__->filters(name => ('+App::MyFilter' => {}), );

Will try to load the class App::MyFilter and use it as a filter directly (or throw an exception if it fails to load).

filters_with

filters_with is intended to process filters that are on the class as a whole, or which are very complex and can't easily be assigned to a single attribute. It accepts either a subroutine reference with an optional hash of key value pair options (which are passed to $opts) or a scalar name which should be a stand alone filter class (basically a class that does the filters method although you should consume the Validate::Filter role to enforce the contract).

    __PACKAGE__->filters_with(sub {
      my ($self, $class, $attrs)) = @_;
      ...
    });

    __PACKAGE__->filters_with(\&check_object => (arg1=>'foo', arg2=>'bar'));

    sub filters_with {
      my ($self, $class, $attrs) = @_;
      ...
    }

    __PACKAGE__->filters_with( 'Custom' => (arg1=>'foo', arg2=>'bar'));

If you pass a string that is a filter class we resolve its namespace using the same approach as detailed above for filters. Any arguments are passed to the new method of the found class.

AUTHOR

John Napiorkowski email:jjnapiork@cpan.org

SEE ALSO

Valiant::Filters

COPYRIGHT & LICENSE

Copyright 2020, John Napiorkowski email:jjnapiork@cpan.org

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.