Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Documentation - Provide an exhaustive exemple of use #2

Open
drupol opened this issue Dec 11, 2021 · 6 comments
Open

Documentation - Provide an exhaustive exemple of use #2

drupol opened this issue Dec 11, 2021 · 6 comments

Comments

@drupol
Copy link
Contributor

drupol commented Dec 11, 2021

Ciao Marco,

Do you think you could provide an example on how to use this library?

Do you think it would be possible to use this class (or this one) containing some validators as an example?

Thanks.

@marcosh
Copy link
Owner

marcosh commented Dec 11, 2021

There is already https://github.com/marcosh/lamphpda-validation/blob/main/spec/UserValidatorSpec.php

I would like to expand on that using some of the newly implemented validators (like associativeArray and nullable)

@drupol drupol closed this as completed Dec 12, 2021
@drupol
Copy link
Contributor Author

drupol commented Dec 12, 2021

Thanks

@drupol
Copy link
Contributor Author

drupol commented Dec 12, 2021

Do you have an example on how to use ->or() ?

Example code:

protected function hasValidRule(string $tin): bool
{
    return $this->isFollowBelgiumRule1AndIsDateValid($tin) || $this->isFollowBelgiumRule2AndIsDateValid($tin);
}

I re-created the Belgium TIN validator using this library at: https://gist.github.com/drupol/ce865ce88e4734668f1140b77da3e54e

However, I feel that I could improve this part:

->then(
    V::satisfies(
        static fn (string $tin): bool => $isFollowBelgiumRule1AndIsDateValid($tin) || $isFollowBelgiumRule2AndIsDateValid($tin),
        false
    )
)

What's your point of view on this? Should it be done this way ?

class ExceptionMonoid extends \Exception implements Monoid
{
    public function mempty()
    {
        // What to do here?
    }

    /**
     * @param \Throwable $a
     * @param \Throwable $b
     * 
     * @return ExceptionMonoid
     */
    public function append($a, $b)
    {
        return new self($a->getMessage(), 0, $b);
    }
}

$r = V::valid()
    ->then(V::isString(new \Exception('Invalid data type.')))
    ->then(V::satisfies($hasValidLength, new \Exception('Invalid length.')))
    ->then(V::satisfies($hasValidPattern, new \Exception('Invalid pattern.')))
    ->then(V::satisfies($hasValidDateType, new \Exception('Invalid date.')));

$r1 = $r->then(V::satisfies($isFollowBelgiumRule1AndIsDateValid, new \Exception('Invalid rule1')));
$r2 = $r->then(V::satisfies($isFollowBelgiumRule2AndIsDateValid, new \Exception('Invalid rule2')));

$r1_or_r2 = $r1->or(new ExceptionMonoid(), $r2);

$r = $r1_or_r2
    ->validate($input)
    ->eval(
        static fn (\Throwable $i): string => $i->getMessage(),
        static fn (string $i): string => $i
    );

var_dump($r);

@drupol drupol reopened this Dec 12, 2021
@marcosh
Copy link
Owner

marcosh commented Dec 13, 2021

There are examples on how to use or in the tests (

describe('Or', function () {
) and in the nullable implementation (
return $validation->rmap($f)->or($eMonoid, $nullValidation);
).

You simply use it by providing two validators (one of them is used to call the or method) and a monoid on E which describes how to compose the errors if both validations fail. If you don't know which monoid to use, the easy choice is using ConcatenationMonoid on lists of strings.

Some notes regarding your implementations:

  • no need to start from V::valid, you can start from V::isString
  • use then only if you need sequentiality of validations. Otherwise use all which collects errors.
  • pay attention to the type of the errors. Choose one and keep it consistent; in the gist you use strings and booleans.
  • I'd recommend not to use exceptions as the error type, usually list of strings are enough

@drupol
Copy link
Contributor Author

drupol commented Dec 13, 2021

Thanks!

I updated my local test file based on your feedback.
I guess the way to use the OR was good in the first example.

I'm now using this:

$input = '81023011101'; // Invalid input - date invalid

$r = V::all(
    new ConcatenationMonoid,
    new FirstSemigroup,
    [
        V::isString(['TIN type must be a string.']),
        V::satisfies($hasValidLength, ['TIN length is invalid.']),
        V::satisfies($hasValidPattern, ['TIN pattern is invalid.']),
        V::satisfies($hasValidDateType, ['TIN date is invalid.']),
    ]
);

$r1 = $r->then(V::satisfies($isFollowBelgiumRule1AndIsDateValid, ['TIN validation of rule 1 failed.']));
$r2 = $r->then(V::satisfies($isFollowBelgiumRule2AndIsDateValid, ['TIN validation of rule 2 failed.']));

$r = $r1->or(new ConcatenationMonoid, $r2)
    ->validate($input)
    ->eval(
        static fn (array $i): array => $i,
        static fn (string $i): string => $i
    );

However, when I run the test, the error "TIN date is invalid" is printed twice.

... Investigating :)

@marcosh
Copy link
Owner

marcosh commented Dec 13, 2021

careful, before checking the length, you probably need to know that the input is a string, so in that case you need the sequentiality and therefore it's best to use then.

When both the validators in or fail, you get both errors reported. I guess that is why you get it twice

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants