Validation icon indicating copy to clipboard operation
Validation copied to clipboard

Formatter inconsequently stringifies values

Open jonsa opened this issue 1 year ago • 2 comments

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.

jonsa avatar May 03 '23 21:05 jonsa

@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.

alganet avatar Jun 14 '23 00:06 alganet

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.

jonsa avatar Jun 14 '23 12:06 jonsa

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 avatar Mar 08 '24 23:03 henriquemoody

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

henriquemoody avatar Mar 11 '24 19:03 henriquemoody

This fix is available on version 2.3.3

henriquemoody avatar Mar 11 '24 21:03 henriquemoody

Thank you for reporting, @jonsa! 🐼

henriquemoody avatar Mar 11 '24 21:03 henriquemoody