Skip to content

Commit

Permalink
Create a stringifier for "quoted" values
Browse files Browse the repository at this point in the history
The `StandardQuoter` adds backticks around strings, which indicates that
it's not a simple string but a code. With this stringifier, we can add
quotes to placeholders directly into templates.
  • Loading branch information
henriquemoody committed Dec 26, 2024
1 parent b8f4949 commit 84a0136
Show file tree
Hide file tree
Showing 7 changed files with 115 additions and 4 deletions.
23 changes: 23 additions & 0 deletions library/Message/Placeholder/Quoted.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

/*
* Copyright (c) Alexandre Gomes Gaigalas <[email protected]>
* SPDX-License-Identifier: MIT
*/

declare(strict_types=1);

namespace Respect\Validation\Message\Placeholder;

final class Quoted
{
public function __construct(
private readonly string $value
) {
}

public function getValue(): string
{
return $this->value;
}
}
5 changes: 5 additions & 0 deletions library/Message/StandardRenderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

use ReflectionClass;
use Respect\Stringifier\Stringifier;
use Respect\Validation\Message\Placeholder\Quoted;
use Respect\Validation\Mode;
use Respect\Validation\Result;
use Respect\Validation\Rule;
Expand Down Expand Up @@ -71,6 +72,10 @@ private function extractTemplates(Rule $rule): array

private function placeholder(string $name, mixed $value, Translator $translator, ?string $modifier = null): string
{
if ($modifier === 'quote' && is_string($value)) {
return $this->placeholder($name, new Quoted($value), $translator);
}

if ($modifier === 'raw' && is_scalar($value)) {
return is_bool($value) ? (string) (int) $value : (string) $value;
}
Expand Down
7 changes: 7 additions & 0 deletions library/Message/StandardStringifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
use Respect\Stringifier\Stringifiers\ResourceStringifier;
use Respect\Stringifier\Stringifiers\StringableObjectStringifier;
use Respect\Stringifier\Stringifiers\ThrowableObjectStringifier;
use Respect\Validation\Message\Stringifier\QuotedStringifier;

final class StandardStringifier implements Stringifier
{
Expand All @@ -47,6 +48,11 @@ public function __construct(
$this->stringifier = $this->createStringifier($quoter);
}

public function getQuoter(): Quoter

Check warning on line 51 in library/Message/StandardStringifier.php

View check run for this annotation

Codecov / codecov/patch

library/Message/StandardStringifier.php#L51

Added line #L51 was not covered by tests
{
return $this->quoter;

Check warning on line 53 in library/Message/StandardStringifier.php

View check run for this annotation

Codecov / codecov/patch

library/Message/StandardStringifier.php#L53

Added line #L53 was not covered by tests
}

public function stringify(mixed $raw, int $depth): string
{
return $this->stringifier->stringify($raw, $depth) ?? $this->quoter->quote('unknown', $depth);
Expand Down Expand Up @@ -86,6 +92,7 @@ private function createStringifier(Quoter $quoter): Stringifier
$stringifier->prependStringifier(new ThrowableObjectStringifier($jsonEncodableStringifier, $quoter));
$stringifier->prependStringifier(new DateTimeStringifier($quoter, DateTimeInterface::ATOM));
$stringifier->prependStringifier(new IteratorObjectStringifier($stringifier, $quoter));
$stringifier->prependStringifier(new QuotedStringifier($quoter));

return $stringifier;
}
Expand Down
31 changes: 31 additions & 0 deletions library/Message/Stringifier/QuotedStringifier.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

declare(strict_types=1);

/*
* Copyright (c) Alexandre Gomes Gaigalas <[email protected]>
* SPDX-License-Identifier: MIT
*/

namespace Respect\Validation\Message\Stringifier;

use Respect\Stringifier\Quoter;
use Respect\Stringifier\Stringifier;
use Respect\Validation\Message\Placeholder\Quoted;

final class QuotedStringifier implements Stringifier
{
public function __construct(
private readonly Quoter $quoter
) {
}

public function stringify(mixed $raw, int $depth): ?string
{
if (!$raw instanceof Quoted) {
return null;
}

return $this->quoter->quote($raw->getValue(), $depth);
}
}
4 changes: 2 additions & 2 deletions library/Rules/Instance.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@

#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)]
#[Template(
'{{name}} must be an instance of `{{class|raw}}`',
'{{name}} must not be an instance of `{{class|raw}}`',
'{{name}} must be an instance of {{class|quote}}',
'{{name}} must not be an instance of {{class|quote}}',
)]
final class Instance extends Standard
{
Expand Down
4 changes: 2 additions & 2 deletions library/Rules/Regex.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@

#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)]
#[Template(
'{{name}} must match the pattern `{{regex|raw}}`',
'{{name}} must not match the pattern `{{regex|raw}}`',
'{{name}} must match the pattern {{regex|quote}}',
'{{name}} must not match the pattern {{regex|quote}}',
)]
final class Regex extends Standard
{
Expand Down
45 changes: 45 additions & 0 deletions tests/unit/Message/Stringifier/QuotedStringifierTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

/*
* Copyright (c) Alexandre Gomes Gaigalas <[email protected]>
* SPDX-License-Identifier: MIT
*/

declare(strict_types=1);

namespace Respect\Validation\Message\Stringifier;

use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use Respect\Stringifier\Quoters\StandardQuoter;
use Respect\Validation\Message\Placeholder\Quoted;
use Respect\Validation\Test\TestCase;

#[CoversClass(QuotedStringifier::class)]
final class QuotedStringifierTest extends TestCase
{
#[Test]
#[DataProvider('providerForAnyValues')]
public function itShouldNotStringifyWhenValueIsNotAnInstanceOfQuoted(mixed $value): void
{
$quoter = new StandardQuoter(1);
$stringifier = new QuotedStringifier($quoter);

self::assertNull($stringifier->stringify($value, 0));
}

#[Test]
#[DataProvider('providerForStringTypes')]
public function itShouldStringifyWhenValueIsAnInstanceOfQuoted(string $value): void
{
$quoted = new Quoted($value);
$quoter = new StandardQuoter(1);
$stringifier = new QuotedStringifier($quoter);

$expected = $quoter->quote($quoted->getValue(), 0);
$actual = $stringifier->stringify($quoted, 0);

self::assertSame($expected, $actual);
}
}

0 comments on commit 84a0136

Please sign in to comment.