Skip to content

Commit

Permalink
Allow templates to have raw and translatable params
Browse files Browse the repository at this point in the history
In some cases, a user would like to show the parameter just as it is,
and in other cases, they need to translate a specific parameter. This
change creates that capability by adding a template-style modifier to a
parameter in the template.

Signed-off-by: Henrique Moody <[email protected]>
  • Loading branch information
henriquemoody committed Feb 14, 2024
1 parent 04b2722 commit 26e9fb9
Show file tree
Hide file tree
Showing 32 changed files with 351 additions and 117 deletions.
6 changes: 3 additions & 3 deletions library/Exceptions/ValidationException.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
namespace Respect\Validation\Exceptions;

use InvalidArgumentException;
use Respect\Validation\Message\Formatter;
use Respect\Validation\Message\Template;
use Respect\Validation\Message\TemplateRenderer;

use function count;

Expand All @@ -37,7 +37,7 @@ public function __construct(
private array $params,
private string $template,
array $templates,
private readonly Formatter $formatter
private readonly TemplateRenderer $formatter
) {
if (count($templates) === 0) {
$templates = [new Template('{{name}} must be valid', '{{name}} must not be valid')];
Expand Down Expand Up @@ -104,7 +104,7 @@ private function getTemplateString(): string

private function createMessage(): string
{
return $this->formatter->format($this->getTemplateString(), $this->input, $this->params);
return $this->formatter->render($this->getTemplateString(), $this->input, $this->params);
}

public function __toString(): string
Expand Down
4 changes: 2 additions & 2 deletions library/Factory.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@
use Respect\Validation\Exceptions\ComponentException;
use Respect\Validation\Exceptions\InvalidClassException;
use Respect\Validation\Exceptions\ValidationException;
use Respect\Validation\Message\Formatter;
use Respect\Validation\Message\ParameterStringifier;
use Respect\Validation\Message\Stringifier\KeepOriginalStringName;
use Respect\Validation\Message\TemplateCollector;
use Respect\Validation\Message\TemplateRenderer;

use function count;
use function lcfirst;
Expand Down Expand Up @@ -121,7 +121,7 @@ public function exception(Validatable $validatable, mixed $input, array $extraPa
}
$template = $validatable->getTemplate($input);
$templates = $this->templateCollector->extract($validatable);
$formatter = new Formatter($this->translator, $this->parameterStringifier);
$formatter = new TemplateRenderer($this->translator, $this->parameterStringifier);

$attributes = $reflection->getAttributes(ExceptionClass::class);
if (count($attributes) === 0) {
Expand Down
49 changes: 0 additions & 49 deletions library/Message/Formatter.php

This file was deleted.

74 changes: 74 additions & 0 deletions library/Message/TemplateRenderer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
<?php

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

declare(strict_types=1);

namespace Respect\Validation\Message;

use Respect\Validation\Exceptions\ComponentException;
use Throwable;

use function call_user_func;
use function is_scalar;
use function preg_replace_callback;
use function Respect\Stringifier\stringify;
use function sprintf;

final class TemplateRenderer
{
/** @var callable */
private $translator;

public function __construct(
callable $translator,
private readonly ParameterStringifier $parameterStringifier
) {
$this->translator = $translator;
}

/**
* @param mixed[] $parameters
*/
public function render(string $template, mixed $input, array $parameters): string
{
$parameters['name'] ??= $this->parameterStringifier->stringify('input', $input);

return (string) preg_replace_callback(
'/{{(\w+)(\|(trans|raw))?}}/',
function (array $matches) use ($parameters): string {
if (!isset($parameters[$matches[1]])) {
return $matches[0];
}

$modifier = $matches[3] ?? null;
if ($modifier === 'raw' && is_scalar($parameters[$matches[1]])) {
return (string) $parameters[$matches[1]];
}

if ($modifier === 'trans') {
return $this->translate($parameters[$matches[1]]);
}

return $this->parameterStringifier->stringify($matches[1], $parameters[$matches[1]]);
},
$this->translate($template)
);
}

private function translate(mixed $message): string
{
if (!is_scalar($message)) {
throw new ComponentException(sprintf('Cannot translate scalar value "%s"', stringify($message)));
}

try {
return call_user_func($this->translator, (string) $message);
} catch (Throwable $throwable) {
throw new ComponentException(sprintf('Failed to translate "%s"', $message), 0, $throwable);
}
}
}
4 changes: 2 additions & 2 deletions library/Rules/Base.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
use function sprintf;

#[Template(
'{{name}} must be a number in the base {{base}}',
'{{name}} must not be a number in the base {{base}}',
'{{name}} must be a number in the base {{base|raw}}',
'{{name}} must not be a number in the base {{base|raw}}',
)]
final class Base extends AbstractRule
{
Expand Down
4 changes: 2 additions & 2 deletions library/Rules/Charset.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
use function mb_list_encodings;

#[Template(
'{{name}} must be in the {{charset}} charset',
'{{name}} must not be in the {{charset}} charset',
'{{name}} must be in the {{charset|raw}} charset',
'{{name}} must not be in the {{charset|raw}} charset',
)]
final class Charset extends AbstractRule
{
Expand Down
8 changes: 4 additions & 4 deletions library/Rules/CreditCard.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@
use function sprintf;

#[Template(
'{{name}} must be a valid Credit Card number',
'{{name}} must not be a valid Credit Card number',
'{{name}} must be a valid credit card number',
'{{name}} must not be a valid credit card number',
self::TEMPLATE_STANDARD,
)]
#[Template(
'{{name}} must be a valid {{brand}} Credit Card number',
'{{name}} must not be a valid {{brand}} Credit Card number',
'{{name}} must be a valid {{brand|raw}} credit card number',
'{{name}} must not be a valid {{brand|raw}} credit card number',
self::TEMPLATE_BRANDED,
)]
final class CreditCard extends AbstractRule
Expand Down
4 changes: 2 additions & 2 deletions library/Rules/Factor.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
use function is_numeric;

#[Template(
'{{name}} must be a factor of {{dividend}}',
'{{name}} must not be a factor of {{dividend}}',
'{{name}} must be a factor of {{dividend|raw}}',
'{{name}} must not be a factor of {{dividend|raw}}',
)]
final class Factor extends AbstractRule
{
Expand Down
4 changes: 2 additions & 2 deletions library/Rules/Instance.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
use Respect\Validation\Message\Template;

#[Template(
'{{name}} must be an instance of {{instanceName}}',
'{{name}} must not be an instance of {{instanceName}}',
'{{name}} must be an instance of `{{instanceName|raw}}`',
'{{name}} must not be an instance of `{{instanceName|raw}}`',
)]
final class Instance extends AbstractRule
{
Expand Down
4 changes: 2 additions & 2 deletions library/Rules/Ip.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@
self::TEMPLATE_STANDARD,
)]
#[Template(
'{{name}} must be an IP address in the {{range}} range',
'{{name}} must not be an IP address in the {{range}} range',
'{{name}} must be an IP address in the {{range|raw}} range',
'{{name}} must not be an IP address in the {{range|raw}} range',
self::TEMPLATE_NETWORK_RANGE,
)]
final class Ip extends AbstractRule
Expand Down
4 changes: 2 additions & 2 deletions library/Rules/LanguageCode.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
use function sprintf;

#[Template(
'{{name}} must be a valid ISO 639 {{set}} language code',
'{{name}} must not be a valid ISO 639 {{set}} language code',
'{{name}} must be a valid ISO 639 {{set|raw}} language code',
'{{name}} must not be a valid ISO 639 {{set|raw}} language code',
)]
final class LanguageCode extends AbstractEnvelope
{
Expand Down
4 changes: 2 additions & 2 deletions library/Rules/MaxAge.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
use Respect\Validation\Message\Template;

#[Template(
'{{name}} must be {{age}} years or less',
'{{name}} must not be {{age}} years or less',
'{{name}} must be {{age|raw}} years or less',
'{{name}} must not be {{age|raw}} years or less',
)]
final class MaxAge extends AbstractAge
{
Expand Down
4 changes: 2 additions & 2 deletions library/Rules/MinAge.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
use Respect\Validation\Message\Template;

#[Template(
'{{name}} must be {{age}} years or more',
'{{name}} must not be {{age}} years or more',
'{{name}} must be {{age|raw}} years or more',
'{{name}} must not be {{age|raw}} years or more',
)]
final class MinAge extends AbstractAge
{
Expand Down
4 changes: 2 additions & 2 deletions library/Rules/Phone.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@
self::TEMPLATE_INTERNATIONAL,
)]
#[Template(
'{{name}} must be a valid telephone number for country {{countryName}}',
'{{name}} must not be a valid telephone number for country {{countryName}}',
'{{name}} must be a valid telephone number for country {{countryName|trans}}',
'{{name}} must not be a valid telephone number for country {{countryName|trans}}',
self::TEMPLATE_FOR_COUNTRY,
)]
final class Phone extends AbstractRule
Expand Down
4 changes: 2 additions & 2 deletions library/Rules/Printable.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
self::TEMPLATE_STANDARD,
)]
#[Template(
'{{name}} must contain only printable characters and "{{additionalChars}}"',
'{{name}} must not contain printable characters or "{{additionalChars}}"',
'{{name}} must contain only printable characters and {{additionalChars}}',
'{{name}} must not contain printable characters or {{additionalChars}}',
self::TEMPLATE_EXTRA,
)]
final class Printable extends AbstractFilterRule
Expand Down
4 changes: 2 additions & 2 deletions library/Rules/Regex.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
use function preg_match;

#[Template(
'{{name}} must validate against {{regex}}',
'{{name}} must not validate against {{regex}}',
'{{name}} must validate against `{{regex|raw}}`',
'{{name}} must not validate against `{{regex|raw}}`',
)]
final class Regex extends AbstractRule
{
Expand Down
4 changes: 2 additions & 2 deletions library/Rules/SubdivisionCode.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@
use function str_replace;

#[Template(
'{{name}} must be a subdivision code of {{countryName}}',
'{{name}} must not be a subdivision code of {{countryName}}',
'{{name}} must be a subdivision code of {{countryName|trans}}',
'{{name}} must not be a subdivision code of {{countryName|trans}}',
)]
final class SubdivisionCode extends AbstractSearcher
{
Expand Down
4 changes: 2 additions & 2 deletions library/Rules/Uuid.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
self::TEMPLATE_STANDARD,
)]
#[Template(
'{{name}} must be a valid UUID version {{version}}',
'{{name}} must not be a valid UUID version {{version}}',
'{{name}} must be a valid UUID version {{version|raw}}',
'{{name}} must not be a valid UUID version {{version|raw}}',
self::TEMPLATE_VERSION,
)]
final class Uuid extends AbstractRule
Expand Down
4 changes: 2 additions & 2 deletions library/Rules/VideoUrl.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@
self::TEMPLATE_STANDARD,
)]
#[Template(
'{{name}} must be a valid {{service}} video URL',
'{{name}} must not be a valid {{service}} video URL',
'{{name}} must be a valid {{service|raw}} video URL',
'{{name}} must not be a valid {{service|raw}} video URL',
self::TEMPLATE_SERVICE,
)]
final class VideoUrl extends AbstractRule
Expand Down
8 changes: 4 additions & 4 deletions tests/integration/rules/creditCard.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ exceptionFullMessage(static fn() => v::creditCard('MasterCard')->assert(35660020
exceptionFullMessage(static fn() => v::not(v::creditCard())->assert(5555444433331111));
?>
--EXPECT--
3566002020360505 must be a valid "Discover" Credit Card number
4024007153361885 must not be a valid "Visa" Credit Card number
- 3566002020360505 must be a valid "MasterCard" Credit Card number
- 5555444433331111 must not be a valid Credit Card number
3566002020360505 must be a valid Discover credit card number
4024007153361885 must not be a valid Visa credit card number
- 3566002020360505 must be a valid MasterCard credit card number
- 5555444433331111 must not be a valid credit card number
8 changes: 4 additions & 4 deletions tests/integration/rules/ip.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ if (!extension_loaded('bcmath')) {
--EXPECT--
"257.0.0.1" must be an IP address
"127.0.0.1" must not be an IP address
"127.0.0.1" must be an IP address in the "127.0.1.0-127.0.1.255" range
"127.0.1.1" must not be an IP address in the "127.0.1.0-127.0.1.255" range
"127.0.0.1" must be an IP address in the 127.0.1.0-127.0.1.255 range
"127.0.1.1" must not be an IP address in the 127.0.1.0-127.0.1.255 range
- "257.0.0.1" must be an IP address
- "127.0.0.1" must not be an IP address
- "127.0.0.1" must be an IP address in the "127.0.1.0-127.0.1.255" range
- "127.0.1.1" must not be an IP address in the "127.0.1.0-127.0.1.255" range
- "127.0.0.1" must be an IP address in the 127.0.1.0-127.0.1.255 range
- "127.0.1.1" must not be an IP address in the 127.0.1.0-127.0.1.255 range
8 changes: 4 additions & 4 deletions tests/integration/rules/languageCode.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ exceptionFullMessage(static fn() => v::languageCode()->assert('por'));
exceptionFullMessage(static fn() => v::not(v::languageCode())->assert('en'));
?>
--EXPECT--
`null` must be a valid ISO 639 "alpha-2" language code
"pt" must not be a valid ISO 639 "alpha-2" language code
- "por" must be a valid ISO 639 "alpha-2" language code
- "en" must not be a valid ISO 639 "alpha-2" language code
`null` must be a valid ISO 639 alpha-2 language code
"pt" must not be a valid ISO 639 alpha-2 language code
- "por" must be a valid ISO 639 alpha-2 language code
- "en" must not be a valid ISO 639 alpha-2 language code
8 changes: 4 additions & 4 deletions tests/integration/rules/regex.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ exceptionFullMessage(static fn() => v::regex('/^w+$/')->assert(new stdClass()));
exceptionFullMessage(static fn() => v::not(v::regex('/^[a-z]+$/i'))->assert('wPoiur'));
?>
--EXPECT--
"w poiur" must validate against "/^w+$/"
"wpoiur" must not validate against "/^[a-z]+$/"
- `stdClass {}` must validate against "/^w+$/"
- "wPoiur" must not validate against "/^[a-z]+$/i"
"w poiur" must validate against `/^w+$/`
"wpoiur" must not validate against `/^[a-z]+$/`
- `stdClass {}` must validate against `/^w+$/`
- "wPoiur" must not validate against `/^[a-z]+$/i`
Loading

0 comments on commit 26e9fb9

Please sign in to comment.