Respect / Validation

The most awesome validation engine ever created for PHP
https://respect-validation.readthedocs.io
MIT License
5.75k stars 774 forks source link

Formatter inconsequently stringifies values #1426

Closed jonsa closed 4 months ago

jonsa commented 1 year ago

Is it intended behaviour for Formatter to use the stringify() function instead of the the class parameter $parameterStringifier when converting the the name parameter?

Personally I think it's a bug since I tried to replace the ParameterStringifier using the Factory but the name passes through the default built-in stringifier instead of the one I provided.

My use case was that I wanted to replace the DateTimeStringifier from respect/stringifer:0.2.0 that this project uses, since the value is rather poorly formatted. This has been fixed in 2.0.0 but I can't use it because of the requirements of this project.

alganet commented 1 year ago

@jonsa sorry for the delay answering this. I need some more time to investigate this.

If you are able to provide some code samples of the usage you intend, that would be super helpful!

Thanks for reporting! I'll get back at this soon.

jonsa commented 1 year ago

This is a somewhat lengthy example. I could probably bake everything into MyParameterStringifier but I wanted to keep the essence of the structure used in this project and my own solution intact.

<?php

declare(strict_types=1);

use Respect\Stringifier\Stringifier;
use Respect\Stringifier\Stringifiers;
use Respect\Validation\Message\ParameterStringifier;

require_once __DIR__ . '/vendor/autoload.php';

class MyDateStringifier implements Stringifier
{
    public function stringify($raw, int $depth): ?string
    {
        return $raw instanceof \DateTimeInterface
            ? $raw->format('Y-m-d')
            : null;
    }
}

class MyStringifier implements Stringifier
{
    private array $stringifiers;

    public function __construct()
    {
        $this->stringifiers = [
            new MyDateStringifier(),
            new Stringifiers\JsonParsableStringifier(),
        ];
    }

    public function stringify($raw, int $depth): ?string
    {
        foreach ($this->stringifiers as $stringifier) {
            $string = $stringifier->stringify($raw, $depth);

            if (null === $string) {
                continue;
            }

            return $string;
        }

        return null;
    }
}

class MyParameterStringifier implements ParameterStringifier
{
    private MyStringifier $stringifier;

    public function __construct()
    {
        $this->stringifier = new MyStringifier();
    }

    public function stringify(string $name, $value): string
    {
        if ($name === 'name' && is_string($value)) {
            return $value;
        }

        return $this->stringifier->stringify($value, 0);
    }
}

Respect\Validation\Factory::setDefaultInstance(
    Respect\Validation\Factory::getDefaultInstance()
        ->withParameterStringifier(new MyParameterStringifier())
);

$v = Respect\Validation\Validator::between(new DateTime('2023-01-01'), new DateTime('2023-12-31'));

try {
    $v->assert(new DateTime('2022-06-01'));
} catch (Respect\Validation\Exceptions\AllOfException $e) {
    var_export($e->getMessages());
}

This will result in

array (
  'between' => '`[date-time] (DateTime: "2022-06-01T00:00:00+02:00")` must be between 2023-01-01 and 2023-12-31',
)

As you can see the value is passed through DateTimeStringifier which I defined not to be used.

In my attempts to fix the issue I found that editing Formatter.php#40 to be

$parameters['name'] = $parameters['name'] ?? $this->parameterStringifier->stringify('name', $input);

solves my issue.

henriquemoody commented 4 months ago

Hey @jonsa!

I'm sorry about my delay... What you were describing is really a bug.

However, we've upgraded the version of respect/stringifer. How are you experiencing it now?

henriquemoody commented 4 months ago

I just merged fb322df1dac40c890faf40652089ea653f103c14, I should release a patch version soon.

henriquemoody commented 4 months ago

This fix is available on version 2.3.3

henriquemoody commented 4 months ago

Thank you for reporting, @jonsa! 🐼