Skip to content

Commit

Permalink
Extract parameter processor into multiple classes
Browse files Browse the repository at this point in the history
By extracting them into different processors, the code in the rendered
becomes much more straightforward, and the design makes it possible to
create processors easily. This change will allow users to customize that
behavior if they want to.

Signed-off-by: Henrique Moody <[email protected]>
  • Loading branch information
henriquemoody committed Feb 22, 2024
1 parent 955a554 commit d25557c
Show file tree
Hide file tree
Showing 17 changed files with 409 additions and 147 deletions.
20 changes: 12 additions & 8 deletions library/Factory.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@
use Respect\Validation\Exceptions\ComponentException;
use Respect\Validation\Exceptions\InvalidClassException;
use Respect\Validation\Exceptions\ValidationException;
use Respect\Validation\Message\ParameterStringifier;
use Respect\Validation\Message\Stringifier\KeepOriginalStringName;
use Respect\Validation\Message\Parameter\Processor;
use Respect\Validation\Message\Parameter\Raw;
use Respect\Validation\Message\Parameter\Stringify;
use Respect\Validation\Message\Parameter\Trans;
use Respect\Validation\Message\TemplateCollector;
use Respect\Validation\Message\TemplateRenderer;

Expand All @@ -37,17 +39,18 @@ final class Factory
/**
* @var callable
*/
private $translator = 'strval';
private $translator;

private ParameterStringifier $parameterStringifier;
private Processor $processor;

private TemplateCollector $templateCollector;

private static Factory $defaultInstance;

public function __construct()
{
$this->parameterStringifier = new KeepOriginalStringName();
$this->translator = static fn (string $message) => $message;
$this->processor = new Raw(new Trans($this->translator, new Stringify()));
$this->templateCollector = new TemplateCollector();
}

Expand All @@ -72,14 +75,15 @@ public function withTranslator(callable $translator): self
{
$clone = clone $this;
$clone->translator = $translator;
$clone->processor = new Raw(new Trans($translator, new Stringify()));

return $clone;
}

public function withParameterStringifier(ParameterStringifier $parameterStringifier): self
public function withParameterProcessor(Processor $processor): self
{
$clone = clone $this;
$clone->parameterStringifier = $parameterStringifier;
$clone->processor = $processor;

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

$attributes = $reflection->getAttributes(ExceptionClass::class);
if (count($attributes) === 0) {
Expand Down
15 changes: 15 additions & 0 deletions library/Message/Parameter/Processor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

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

declare(strict_types=1);

namespace Respect\Validation\Message\Parameter;

interface Processor
{
public function process(string $name, mixed $value, ?string $modifier = null): string;
}
30 changes: 30 additions & 0 deletions library/Message/Parameter/Raw.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

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

declare(strict_types=1);

namespace Respect\Validation\Message\Parameter;

use function is_bool;
use function is_scalar;

final class Raw implements Processor
{
public function __construct(
private readonly Processor $nextProcessor,
) {
}

public function process(string $name, mixed $value, ?string $modifier = null): string
{
if ($modifier === 'raw' && is_scalar($value)) {
return is_bool($value) ? (string) (int) $value : (string) $value;
}

return $this->nextProcessor->process($name, $value, $modifier);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,14 @@

declare(strict_types=1);

namespace Respect\Validation\Message\Stringifier;

use Respect\Validation\Message\ParameterStringifier;
namespace Respect\Validation\Message\Parameter;

use function is_string;
use function Respect\Stringifier\stringify;

final class KeepOriginalStringName implements ParameterStringifier
final class Stringify implements Processor
{
public function stringify(string $name, mixed $value): string
public function process(string $name, mixed $value, ?string $modifier = null): string
{
if ($name === 'name' && is_string($value)) {
return $value;
Expand Down
35 changes: 35 additions & 0 deletions library/Message/Parameter/Trans.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

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

declare(strict_types=1);

namespace Respect\Validation\Message\Parameter;

use function call_user_func;
use function is_string;

final class Trans implements Processor
{
/** @var callable */
private $translator;

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

public function process(string $name, mixed $value, ?string $modifier = null): string
{
if ($modifier === 'trans' && is_string($value)) {
return call_user_func($this->translator, $value);
}

return $this->nextProcessor->process($name, $value, $modifier);
}
}
15 changes: 0 additions & 15 deletions library/Message/ParameterStringifier.php

This file was deleted.

26 changes: 6 additions & 20 deletions library/Message/TemplateRenderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,11 @@
namespace Respect\Validation\Message;

use Respect\Validation\Exceptions\ComponentException;
use Respect\Validation\Message\Parameter\Processor;
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
Expand All @@ -25,7 +24,7 @@ final class TemplateRenderer

public function __construct(
callable $translator,
private readonly ParameterStringifier $parameterStringifier
private readonly Processor $processor
) {
$this->translator = $translator;
}
Expand All @@ -35,36 +34,23 @@ public function __construct(
*/
public function render(string $template, mixed $input, array $parameters): string
{
$parameters['name'] ??= $this->parameterStringifier->stringify('input', $input);
$parameters['name'] ??= $this->processor->process('input', $input);

return (string) preg_replace_callback(
'/{{(\w+)(\|(trans|raw))?}}/',
function (array $matches) use ($parameters): string {
'/{{(\w+)(\|([^}]+))?}}/',
function (array $matches) use ($parameters) {
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]]);
return $this->processor->process($matches[1], $parameters[$matches[1]], $matches[3] ?? null);
},
$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) {
Expand Down
27 changes: 27 additions & 0 deletions tests/library/Message/Parameter/TestingProcessor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

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

declare(strict_types=1);

namespace Respect\Validation\Test\Message\Parameter;

use Respect\Validation\Message\Parameter\Processor;

use function json_encode;
use function sprintf;

final class TestingProcessor implements Processor
{
public function process(string $name, mixed $value, ?string $modifier = null): string
{
if ($modifier !== null) {
return sprintf('%s(<%s:%s>)', $modifier, $name, $modifier);
}

return sprintf('<%s:%s>', $name, json_encode($value));
}
}
23 changes: 0 additions & 23 deletions tests/library/Message/TestingParameterStringifier.php

This file was deleted.

4 changes: 2 additions & 2 deletions tests/library/Stubs/CompositeSub.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

namespace Respect\Validation\Test\Stubs;

use Respect\Validation\Message\Stringifier\KeepOriginalStringName;
use Respect\Validation\Message\Parameter\Stringify;
use Respect\Validation\Message\TemplateRenderer;
use Respect\Validation\Rules\AbstractComposite;
use Respect\Validation\Test\Exceptions\CompositeStubException;
Expand All @@ -33,7 +33,7 @@ public function reportError(mixed $input, array $extraParameters = []): Composit
params: $extraParameters,
template: Validatable::TEMPLATE_STANDARD,
templates: [],
formatter: new TemplateRenderer(static fn ($value) => $value, new KeepOriginalStringName())
formatter: new TemplateRenderer(static fn ($value) => $value, new Stringify())
);
}
}
Loading

0 comments on commit d25557c

Please sign in to comment.