Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 58 additions & 46 deletions src/Transformers/Prefix.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,75 +4,87 @@
* SPDX-License-Identifier: MIT
* SPDX-FileCopyrightText: (c) Respect Project Contributors
* SPDX-FileContributor: Henrique Moody <henriquemoody@gmail.com>
* SPDX-FileContributor: Alexandre Gomes Gaigalas <alganet@gmail.com>
*/

declare(strict_types=1);

namespace Respect\Validation\Transformers;

use function array_shift;
use function in_array;
use function str_starts_with;
use function strlen;
use function substr;
use function array_keys;
use function array_slice;
use function implode;
use function preg_match;
use function sprintf;

final class Prefix implements Transformer
{
private const array RULES_TO_SKIP = [
'all',
'allOf',
'key',
'keyExists',
'keyOptional',
'keySet',
'length',
'max',
'maxAge',
'min',
'minAge',
'not',
'emoji',
'nullOr',
'property',
'propertyExists',
'propertyOptional',
'undefOr',
private const array RULES_THAT_PREFIX_OR_STAND_ALONE = [
'all' => true,
'allOf' => true,
'emoji' => true,
'key' => true,
'keyExists' => true,
'keyOptional' => true,
'keySet' => true,
'length' => true,
'max' => true,
'maxAge' => true,
'min' => true,
'minAge' => true,
'not' => true,
'nullOr' => true,
'property' => true,
'propertyExists' => true,
'propertyOptional' => true,
'undefOr' => true,
];
private const array RULES_THAT_USE_SUFFIX_AS_ARGUMENT = [
'key' => true,
'property' => true,
];

private static string|null $regex = null;

public function transform(ValidatorSpec $validatorSpec): ValidatorSpec
{
if ($validatorSpec->wrapper !== null || in_array($validatorSpec->name, self::RULES_TO_SKIP, true)) {
$matches = $this->match($validatorSpec);
if ($matches === []) {
return $validatorSpec;
}

foreach (['all', 'length', 'max', 'min', 'not', 'nullOr', 'undefOr'] as $prefix) {
if (!str_starts_with($validatorSpec->name, $prefix)) {
continue;
}

if (!isset(self::RULES_THAT_USE_SUFFIX_AS_ARGUMENT[$matches['name']])) {
return new ValidatorSpec(
substr($validatorSpec->name, strlen($prefix)),
$matches['rest'],
$validatorSpec->arguments,
new ValidatorSpec($prefix),
new ValidatorSpec($matches['name']),
);
}

foreach (['key', 'property'] as $prefix) {
if (!str_starts_with($validatorSpec->name, $prefix)) {
continue;
}

$arguments = $validatorSpec->arguments;
array_shift($arguments);
$wrapperArguments = [$validatorSpec->arguments[0]];
return new ValidatorSpec(
$matches['rest'],
array_slice($validatorSpec->arguments, 1),
new ValidatorSpec($matches['name'], [$validatorSpec->arguments[0]]),
);
}

return new ValidatorSpec(
substr($validatorSpec->name, strlen($prefix)),
$arguments,
new ValidatorSpec($prefix, $wrapperArguments),
);
/** @return array{}|array{name: string, rest: string} */
private function match(ValidatorSpec $validatorSpec): array
{
if ($validatorSpec->wrapper !== null || isset(self::RULES_THAT_PREFIX_OR_STAND_ALONE[$validatorSpec->name])) {
return [];
}

return $validatorSpec;
preg_match(self::getRegex(), $validatorSpec->name, $matches);

return $matches;
Comment thread
alganet marked this conversation as resolved.
}

private static function getRegex(): string
{
return self::$regex ?? self::$regex = sprintf(
'/^(?<name>%s)(?<rest>.+)$/',
implode('|', array_keys(self::RULES_THAT_PREFIX_OR_STAND_ALONE)),
);
}
}
42 changes: 42 additions & 0 deletions tests/benchmark/PrefixBench.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

/*
* SPDX-License-Identifier: MIT
* SPDX-FileCopyrightText: (c) Respect Project Contributors
* SPDX-FileContributor: Alexandre Gomes Gaigalas <alganet@gmail.com>
*/

declare(strict_types=1);

namespace Respect\Validation\Benchmarks;

use PhpBench\Attributes as Bench;
use Respect\Validation\Transformers\Prefix;
use Respect\Validation\Transformers\ValidatorSpec;

final class PrefixBench
{
/** @param array{0: Prefix, 1: ValidatorSpec} $params */
#[Bench\ParamProviders(['provideTransformerSpec'])]
#[Bench\Iterations(10)]
#[Bench\RetryThreshold(5)]
#[Bench\Revs(100)]
#[Bench\Warmup(1)]
#[Bench\Subject]
public function prefixTransformer(array $params): void
{
$params[0]->transform($params[1]);
}

/** @return array<array{0: Prefix, 1: ValidatorSpec}> */
public static function provideTransformerSpec(): array
{
return [
[new Prefix(), new ValidatorSpec('keyName', ['value', 'other'])],
[new Prefix(), new ValidatorSpec('propertyTitle', ['value', 'other'])],
[new Prefix(), new ValidatorSpec('notSomething', ['value'])],
[new Prefix(), new ValidatorSpec('not')],
[new Prefix(), new ValidatorSpec('arrayVal')],
];
}
}