Remove "Wrapper" abstract class

With PHP's promoted properties, there is little reason to have an
abstract class that only provides a constructor and a proxy method.
The greater part of the classes that extended Wrapper had their own
implementation of evaluate(), hence it made very little sense to keep
Wrapper in the codebase.

Assisted-by: Claude Code (Opus 4.5)
This commit is contained in:
Henrique Moody 2026-01-31 00:04:34 +01:00
commit b352f17718
No known key found for this signature in database
GPG key ID: 221E9281655813A6
19 changed files with 73 additions and 144 deletions

View file

@ -556,7 +556,6 @@ final class Custom implements Validator
Base classes available in `Respect\Validation\Validators\Core`:
- `Simple` - For validators with simple boolean logic
- `Wrapper` - For validators that wrap another validator
- `Composite` - For validators that combine multiple validators
- `Envelope` - For validators that modify how another validator works

View file

@ -26,7 +26,7 @@ use function is_callable;
use function is_string;
/** @mixin Builder */
final readonly class ValidatorBuilder implements Validator, Nameable
final readonly class ValidatorBuilder implements Nameable
{
/** @var array<Validator> */
private array $validators;

View file

@ -12,13 +12,19 @@ declare(strict_types=1);
namespace Respect\Validation\Validators\Core;
use Respect\Validation\Result;
use Respect\Validation\Validator;
use Respect\Validation\Validators\IterableType;
use function is_array;
use function iterator_to_array;
abstract class FilteredArray extends Wrapper
abstract class FilteredArray implements Validator
{
public function __construct(
protected Validator $validator,
) {
}
public function evaluate(mixed $input): Result
{
$iterableResult = (new IterableType())->evaluate($input);

View file

@ -15,8 +15,9 @@ declare(strict_types=1);
namespace Respect\Validation\Validators\Core;
use Respect\Validation\Name;
use Respect\Validation\Validator;
interface Nameable
interface Nameable extends Validator
{
public function getName(): Name|null;
}

View file

@ -10,13 +10,21 @@ declare(strict_types=1);
namespace Respect\Validation\Validators\Core;
use Respect\Validation\Result;
use Respect\Validation\Validator;
use Respect\Validation\Validators\AllOf;
final class Reducer extends Wrapper
final readonly class Reducer implements Validator
{
private Validator $validator;
public function __construct(Validator $validator1, Validator ...$validators)
{
parent::__construct($validators === [] ? $validator1 : new AllOf($validator1, ...$validators));
$this->validator = $validators === [] ? $validator1 : new AllOf($validator1, ...$validators);
}
public function evaluate(mixed $input): Result
{
return $this->validator->evaluate($input);
}
}

View file

@ -1,32 +0,0 @@
<?php
/*
* SPDX-License-Identifier: MIT
* SPDX-FileCopyrightText: (c) Respect Project Contributors
* SPDX-FileContributor: Henrique Moody <henriquemoody@gmail.com>
*/
declare(strict_types=1);
namespace Respect\Validation\Validators\Core;
use Respect\Validation\Result;
use Respect\Validation\Validator;
abstract class Wrapper implements Validator
{
public function __construct(
protected readonly Validator $validator,
) {
}
public function evaluate(mixed $input): Result
{
return $this->validator->evaluate($input);
}
public function getValidator(): Validator
{
return $this->validator;
}
}

View file

@ -20,16 +20,14 @@ use Respect\Validation\Path;
use Respect\Validation\Result;
use Respect\Validation\Validator;
use Respect\Validation\Validators\Core\KeyRelated;
use Respect\Validation\Validators\Core\Wrapper;
#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)]
final class Key extends Wrapper implements KeyRelated
final readonly class Key implements KeyRelated
{
public function __construct(
private readonly int|string $key,
Validator $validator,
private int|string $key,
private Validator $validator,
) {
parent::__construct($validator);
}
public function getKey(): int|string

View file

@ -15,16 +15,14 @@ use Attribute;
use Respect\Validation\Result;
use Respect\Validation\Validator;
use Respect\Validation\Validators\Core\KeyRelated;
use Respect\Validation\Validators\Core\Wrapper;
#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)]
final class KeyOptional extends Wrapper implements KeyRelated
final readonly class KeyOptional implements KeyRelated
{
public function __construct(
private readonly int|string $key,
Validator $validator,
private int|string $key,
private Validator $validator,
) {
parent::__construct($validator);
}
public function getKey(): int|string

View file

@ -22,7 +22,7 @@ use Attribute;
use Countable as PhpCountable;
use Respect\Validation\Message\Template;
use Respect\Validation\Result;
use Respect\Validation\Validators\Core\Wrapper;
use Respect\Validation\Validator;
use function count;
use function is_array;
@ -40,10 +40,15 @@ use function mb_strlen;
'{{subject}} must not be a countable value or a string',
self::TEMPLATE_WRONG_TYPE,
)]
final class Length extends Wrapper
final readonly class Length implements Validator
{
public const string TEMPLATE_WRONG_TYPE = '__wrong_type__';
public function __construct(
private Validator $validator,
) {
}
public function evaluate(mixed $input): Result
{
$length = $this->extractLength($input);

View file

@ -15,19 +15,18 @@ use Respect\Validation\Name;
use Respect\Validation\Result;
use Respect\Validation\Validator;
use Respect\Validation\Validators\Core\Nameable;
use Respect\Validation\Validators\Core\Wrapper;
use function is_string;
#[Attribute(Attribute::TARGET_PROPERTY | Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)]
final class Named extends Wrapper implements Nameable
final readonly class Named implements Nameable
{
private readonly Name $name;
public function __construct(string|Name $name, Validator $validator)
{
parent::__construct($validator);
private Name $name;
public function __construct(
string|Name $name,
private Validator $validator,
) {
$this->name = is_string($name) ? new Name($name) : $name;
}

View file

@ -19,11 +19,16 @@ namespace Respect\Validation\Validators;
use Attribute;
use Respect\Validation\Result;
use Respect\Validation\Validators\Core\Wrapper;
use Respect\Validation\Validator;
#[Attribute(Attribute::TARGET_PROPERTY | Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)]
final class Not extends Wrapper
final readonly class Not implements Validator
{
public function __construct(
private Validator $validator,
) {
}
public function evaluate(mixed $input): Result
{
$result = $this->validator->evaluate($input);

View file

@ -16,7 +16,7 @@ namespace Respect\Validation\Validators;
use Attribute;
use Respect\Validation\Message\Template;
use Respect\Validation\Result;
use Respect\Validation\Validators\Core\Wrapper;
use Respect\Validation\Validator;
use function array_map;
@ -25,8 +25,13 @@ use function array_map;
'or must be null',
'and must not be null',
)]
final class NullOr extends Wrapper
final readonly class NullOr implements Validator
{
public function __construct(
private Validator $validator,
) {
}
public function evaluate(mixed $input): Result
{
$result = $this->validator->evaluate($input);

View file

@ -22,16 +22,14 @@ use ReflectionObject;
use Respect\Validation\Path;
use Respect\Validation\Result;
use Respect\Validation\Validator;
use Respect\Validation\Validators\Core\Wrapper;
#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)]
final class Property extends Wrapper
final readonly class Property implements Validator
{
public function __construct(
private readonly string $propertyName,
Validator $validator,
private string $propertyName,
private Validator $validator,
) {
parent::__construct($validator);
}
public function evaluate(mixed $input): Result

View file

@ -14,16 +14,14 @@ namespace Respect\Validation\Validators;
use Attribute;
use Respect\Validation\Result;
use Respect\Validation\Validator;
use Respect\Validation\Validators\Core\Wrapper;
#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)]
final class PropertyOptional extends Wrapper
final readonly class PropertyOptional implements Validator
{
public function __construct(
private readonly string $propertyName,
Validator $validator,
private string $propertyName,
private Validator $validator,
) {
parent::__construct($validator);
}
public function evaluate(mixed $input): Result

View file

@ -20,7 +20,6 @@ use Respect\Validation\Exceptions\InvalidValidatorException;
use Respect\Validation\Message\Template;
use Respect\Validation\Result;
use Respect\Validation\Validator;
use Respect\Validation\Validators\Core\Wrapper;
use SplFileInfo;
use function filesize;
@ -37,7 +36,7 @@ use function is_string;
'{{subject}} must not be a filename or an instance of SplFileInfo or a PSR-7 interface',
self::TEMPLATE_WRONG_TYPE,
)]
final class Size extends Wrapper
final readonly class Size implements Validator
{
public const string TEMPLATE_WRONG_TYPE = '__wrong_type__';
@ -55,14 +54,12 @@ final class Size extends Wrapper
/** @param "B"|"KB"|"MB"|"GB"|"TB"|"PB"|"EB"|"ZB"|"YB" $unit */
public function __construct(
private readonly string $unit,
Validator $validator,
private string $unit,
private Validator $validator,
) {
if (!isset(self::DATA_STORAGE_UNITS[$unit])) {
throw new InvalidValidatorException('"%s" is not a recognized data storage unit.', $unit);
}
parent::__construct($validator);
}
public function evaluate(mixed $input): Result

View file

@ -13,18 +13,16 @@ namespace Respect\Validation\Validators;
use Attribute;
use Respect\Validation\Result;
use Respect\Validation\Validator;
use Respect\Validation\Validators\Core\Wrapper;
#[Attribute(Attribute::TARGET_PROPERTY | Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)]
final class Templated extends Wrapper
final readonly class Templated implements Validator
{
/** @param array<string, mixed> $parameters */
public function __construct(
private readonly string $template,
Validator $validator,
private readonly array $parameters = [],
private string $template,
private Validator $validator,
private array $parameters = [],
) {
parent::__construct($validator);
}
public function evaluate(mixed $input): Result

View file

@ -16,7 +16,7 @@ use Attribute;
use Respect\Validation\Helpers\CanValidateUndefined;
use Respect\Validation\Message\Template;
use Respect\Validation\Result;
use Respect\Validation\Validators\Core\Wrapper;
use Respect\Validation\Validator;
use function array_map;
@ -25,10 +25,15 @@ use function array_map;
'or must be undefined',
'and must not be undefined',
)]
final class UndefOr extends Wrapper
final readonly class UndefOr implements Validator
{
use CanValidateUndefined;
public function __construct(
private Validator $validator,
) {
}
public function evaluate(mixed $input): Result
{
$result = $this->validator->evaluate($input);

View file

@ -1,21 +0,0 @@
<?php
/*
* SPDX-License-Identifier: MIT
* SPDX-FileCopyrightText: (c) Respect Project Contributors
* SPDX-FileContributor: Alexandre Gomes Gaigalas <alganet@gmail.com>
* SPDX-FileContributor: Andy Wendt <andy@awendt.com>
* SPDX-FileContributor: Graham Campbell <graham@mineuk.com>
* SPDX-FileContributor: Henrique Moody <henriquemoody@gmail.com>
* SPDX-FileContributor: Nick Lombard <github@jigsoft.co.za>
*/
declare(strict_types=1);
namespace Respect\Validation\Test\Validators\Core;
use Respect\Validation\Validators\Core\Wrapper;
final class ConcreteWrapper extends Wrapper
{
}

View file

@ -1,38 +0,0 @@
<?php
/*
* SPDX-License-Identifier: MIT
* SPDX-FileCopyrightText: (c) Respect Project Contributors
* SPDX-FileContributor: Alexandre Gomes Gaigalas <alganet@gmail.com>
* SPDX-FileContributor: Gabriel Caruso <carusogabriel34@gmail.com>
* SPDX-FileContributor: Henrique Moody <henriquemoody@gmail.com>
* SPDX-FileContributor: Royall Spence <royall@royall.us>
*/
declare(strict_types=1);
namespace Respect\Validation\Validators\Core;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\Group;
use PHPUnit\Framework\Attributes\Test;
use Respect\Validation\Test\TestCase;
use Respect\Validation\Test\Validators\Core\ConcreteWrapper;
use Respect\Validation\Test\Validators\Stub;
#[Group('core')]
#[CoversClass(Wrapper::class)]
final class WrapperTest extends TestCase
{
#[Test]
public function shouldUseWrappedToEvaluate(): void
{
$wrapped = Stub::pass(2);
$wrapper = new ConcreteWrapper($wrapped);
$input = 'Whatever';
self::assertEquals($wrapped->evaluate($input), $wrapper->evaluate($input));
}
}