NAME

Valiant::Validator::Object - Verify a related object

SYNOPSIS

    package Local::Test::Address;

    use Moo;
    use Valiant::Validations;

    has street => (is=>'ro');
    has city => (is=>'ro');
    has country => (is=>'ro');

    validates ['street', 'city'],
      presence => 1,
      length => [3, 40];

    validates 'country',
      presence => 1,
      inclusion => [qw/usa uk canada japan/];

    package Local::Test::Person;

    use Moo;
    use Valiant::Validations;

    has name => (is=>'ro');
    has address => (is=>'ro');
    has car => (is=>'ro');

    validates name => (
      length => [2,30],
      format => qr/[A-Za-z]+/, #yes no unicode names for this test...
    );

    validates address => (
      presence => 1,
      object => {
        nested => 1,
        isa => 'Local::Test::Address',
      }
    );

DESCRIPTION

Runs validations on an object which is assigned as an attribute and aggregates those errors (if any) onto the parent object.

Useful when you need to validate an object graph or nested forms.

If your nested object has a nested object it will follow all the way down the rabbit hole Just don't make self referential nested objects; that's not tested and likely to end poorly. Patches welcomed.

ATTRIBUTES

This validator supports the following attributes:

nested

A boolean that specifies if we should run 'validates' on the object. Default is false.

type_constraint

Reference to a Type::Tiny style type constraint. If specified then the object must pass the constraint.

type_constraint_violation_msg

The message we return when 'type_constraint' fails. We pass 'display_name' and 'error_message' as options to the tag.

isa

The name of a class that the object should inherit from

wrong_inheritance_msg

The message we return when 'isa' fails. We pass 'parent' (the name of the class we require inheritance from) as options to the tag.

role

A role that the object is expected to consume

not_role_msg

The message we return when 'role' fails. We pass 'rolw' (the name of the role we require to consume from) as options to the tag.

invalid_msg

The error message returned when the object has nested validation errors.

not_blessed_msg

The error returned when the value is not an object

SHORTCUT FORM

This validator supports the follow shortcut forms:

    validates attribute => ( object => 1, ... );

Which is the same as:

    validates attribute => (
      object => {
        nested => 1,
      }
    );

<Note: you can use the 'nested' alias for '1' here if you want.

You can also specify a type constraint:

    use use Types::Standard 'Str';

    validates attribute => ( object => Str, ... );

Which is the same as:

    use use Types::Standard 'Str';

    validates attribute => (
      object => {
        type_constraint => Str,
      }
    );

AGGREGATED ERROR MESSAGES

When you nest a object with validations as in the following example any error messages in the nested object are imported into the parent object:

    package Local::Test::Address;

    use Moo;
    use Valiant::Validations;

    has street => (is=>'ro');
    has city => (is=>'ro');
    has country => (is=>'ro');

    validates ['street', 'city'],
      presence => 1,
      length => [3, 40];

    validates 'country',
      presence => 1,
      inclusion => [qw/usa uk canada japan/];

    package Local::Test::Person;

    use Moo;
    use Valiant::Validations;

    has name => (is=>'ro');
    has address => (is=>'ro');

    validates name => (
      length => [2,30],
      format => qr/[A-Za-z]+/, #yes no unicode names for this test...
    );

    validates address => (
      presence => 1,
      object => {
        nested => 1,
      }
    );

    my $address = Local::Test::Address->new(
      city => 'NY',
      country => 'Russia'
    );

    my $person = Local::Test::Person->new(
      name => '12234',
      address => $address,
    );

    my $address_errors = +{ $person->address->errors->to_hash(full_messages=>1) };

    # $address_errors = +{
    #    'country' => [
    #         'Country is not in the list'
    #    ],
    #    'city' => [
    #         'City is too short (minimum is 3 characters)'
    #    ],
    #    'street' => [
    #         'Street can\'t be blank',
    #         'Street is too short (minimum is 3 characters)'
    #    ],
    # };

    my $person_errors = +{ $person->errors->to_hash(full_messages=>1) };

    # $address_errors = +{
    #   name => [
    #       "Name does not match the required pattern",
    #     ],
    #   address => [
    #       "Address Is Invalid",
    #     ],
    #   "address.city" => [
    #       "Address City is too short (minimum is 3 characters)",
    #     ],
    #   "address.country" => [
    #       "Address Country is not in the list",
    #     ],
    #   "address.street" => [
    #       "Address Street can't be blank",
    #       "Address Street is too short (minimum is 3 characters)",
    #     ],
    };

When accessing errors for display you'll have to choose which access approach is best for your application.

Please note that you can have objects nested inside of objects so this can lead to very complex error messaging.

GLOBAL PARAMETERS

This validator supports all the standard shared parameters: if, unless, message, strict, allow_undef, allow_blank.

SEE ALSO

Valiant, Valiant::Validator, Valiant::Validator::Each.

AUTHOR

See Valiant

COPYRIGHT & LICENSE

See Valiant