Skip to content

Commit

Permalink
Create transformers for deprecated rules
Browse files Browse the repository at this point in the history
For now, those transformers will help transition from the current major
version to the next. As I'm making so many changes to the behaviour of
the rules and renaming others, it could be overwhelming to update all of
them suddenly.

The Transformers will change the rules' specifications before the
Factory creates them, allowing us to keep the behaviour of the old rules
-- even if a little bit different -- while triggering E_USER_DEPRECATED
errors to indicate that the client needs to update their code until the
next major version.

However, those transformers will do more shortly, for example, allowing
us to prefix rules to make it easier to create complex rules, like
`notPositive()` or even `keyBetween('foo', 1, 10)` and so on.

Signed-off-by: Henrique Moody <[email protected]>
  • Loading branch information
henriquemoody committed Mar 8, 2024
1 parent fe68eab commit 1e2c1bf
Show file tree
Hide file tree
Showing 19 changed files with 767 additions and 159 deletions.
26 changes: 23 additions & 3 deletions library/Factory.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,14 @@
use Respect\Validation\Message\Parameter\Trans;
use Respect\Validation\Message\TemplateCollector;
use Respect\Validation\Message\TemplateRenderer;
use Respect\Validation\Transformers\DeprecatedAttribute;
use Respect\Validation\Transformers\DeprecatedKey;
use Respect\Validation\Transformers\DeprecatedKeyNested;
use Respect\Validation\Transformers\DeprecatedKeyValue;
use Respect\Validation\Transformers\DeprecatedMinAndMax;
use Respect\Validation\Transformers\DeprecatedType;
use Respect\Validation\Transformers\RuleSpec;
use Respect\Validation\Transformers\Transformer;

use function lcfirst;
use function sprintf;
Expand All @@ -43,13 +51,24 @@ final class Factory

private TemplateCollector $templateCollector;

private Transformer $transformer;

private static Factory $defaultInstance;

public function __construct()
{
$this->translator = static fn (string $message) => $message;
$this->processor = new Raw(new Trans($this->translator, new Stringify()));
$this->templateCollector = new TemplateCollector();
$this->transformer = new DeprecatedAttribute(
new DeprecatedKey(
new DeprecatedKeyValue(
new DeprecatedMinAndMax(
new DeprecatedKeyNested(new DeprecatedType())
)
)
)
);
}

public static function getDefaultInstance(): self
Expand Down Expand Up @@ -101,17 +120,18 @@ public function getParameterProcessor(): Processor
*/
public function rule(string $ruleName, array $arguments = []): Validatable
{
$ruleSpec = $this->transformer->transform(new RuleSpec($ruleName, $arguments));
foreach ($this->rulesNamespaces as $namespace) {
try {
/** @var class-string<Validatable> $name */
$name = $namespace . '\\' . ucfirst($ruleName);
$name = $namespace . '\\' . ucfirst($ruleSpec->name);
/** @var Validatable $rule */
$rule = $this
->createReflectionClass($name, Validatable::class)
->newInstanceArgs($arguments);
->newInstanceArgs($ruleSpec->arguments);

return $rule;
} catch (ReflectionException $exception) {
} catch (ReflectionException) {
continue;
}
}
Expand Down
72 changes: 0 additions & 72 deletions library/Rules/Type.php

This file was deleted.

65 changes: 65 additions & 0 deletions library/Transformers/DeprecatedAttribute.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?php

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

declare(strict_types=1);

namespace Respect\Validation\Transformers;

use function array_key_exists;
use function trigger_error;

use const E_USER_DEPRECATED;

final class DeprecatedAttribute implements Transformer
{
public function __construct(
private readonly Transformer $next
) {
}

public function transform(RuleSpec $ruleSpec): RuleSpec
{
if ($ruleSpec->name !== 'attribute') {
return $this->next->transform($ruleSpec);
}

$arguments = $ruleSpec->arguments;
$firstMessage = 'The attribute() rule has been deprecated and will be removed in the next major version.';
if (!array_key_exists(1, $arguments)) {
trigger_error(
$firstMessage . ' Use propertyExists() instead.',
E_USER_DEPRECATED
);
$name = 'propertyExists';
} elseif (array_key_exists(2, $arguments)) {
$name = $arguments[2] ? 'property' : 'propertyOptional';
unset($arguments[2]);

if ($name === 'propertyOptional') {
trigger_error(
$firstMessage . ' Use propertyOptional() instead.',
E_USER_DEPRECATED
);
}

if ($name === 'property') {
trigger_error(
$firstMessage . ' Use property() without it.',
E_USER_DEPRECATED
);
}
} else {
trigger_error(
$firstMessage . ' Use property() instead.',
E_USER_DEPRECATED
);
$name = 'property';
}

return new RuleSpec($name, $arguments);
}
}
63 changes: 63 additions & 0 deletions library/Transformers/DeprecatedKey.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<?php

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

declare(strict_types=1);

namespace Respect\Validation\Transformers;

use function array_key_exists;
use function trigger_error;

use const E_USER_DEPRECATED;

final class DeprecatedKey implements Transformer
{
public function __construct(
private readonly Transformer $next
) {
}

public function transform(RuleSpec $ruleSpec): RuleSpec
{
if ($ruleSpec->name !== 'key') {
return $this->next->transform($ruleSpec);
}

$name = $ruleSpec->name;
$arguments = $ruleSpec->arguments;

if (!array_key_exists(1, $arguments)) {
trigger_error(
'Calling key() without a second parameter has been deprecated, ' .
'and will be not be allowed in the next major version. Use keyExists() instead.',
E_USER_DEPRECATED
);
$name = 'keyExists';
} elseif (array_key_exists(2, $arguments)) {
$name = $arguments[2] ? 'key' : 'keyOptional';
unset($arguments[2]);

if ($name === 'keyOptional') {
trigger_error(
'Calling key() with a third parameter has been deprecated, ' .
'and will be not be allowed in the next major version. Use keyOptional() instead.',
E_USER_DEPRECATED
);
}

if ($name === 'key') {
trigger_error(
'Calling key() with a third parameter has been deprecated, ' .
'and will be not be allowed in the next major version. Use key() without it the third parameter.',
E_USER_DEPRECATED
);
}
}

return new RuleSpec($name, $arguments);
}
}
101 changes: 101 additions & 0 deletions library/Transformers/DeprecatedKeyNested.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
<?php

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

declare(strict_types=1);

namespace Respect\Validation\Transformers;

use Respect\Validation\Rules\ArrayVal;
use Respect\Validation\Rules\Key;
use Respect\Validation\Rules\KeyExists;
use Respect\Validation\Rules\KeyOptional;
use Respect\Validation\Rules\Property;
use Respect\Validation\Rules\PropertyExists;
use Respect\Validation\Rules\PropertyOptional;
use Respect\Validation\Rules\When;
use Respect\Validation\Validatable;

use function array_pop;
use function array_reduce;
use function array_reverse;
use function explode;
use function trigger_error;
use function trim;

use const E_USER_DEPRECATED;

final class DeprecatedKeyNested implements Transformer
{
public function __construct(
private readonly Transformer $next
) {
}

public function transform(RuleSpec $ruleSpec): RuleSpec
{
if ($ruleSpec->name !== 'keyNested') {
return $this->next->transform($ruleSpec);
}

trigger_error(
'The keyNested() rule is deprecated and will be removed in the next major version. ' .
'Use nested key() or property() instead.',
E_USER_DEPRECATED
);

$key = $ruleSpec->arguments[0] ?? '';
$rule = $ruleSpec->arguments[1] ?? null;
$mandatory = $ruleSpec->arguments[2] ?? true;
$pieces = array_reverse(explode('.', trim($key, '.')));
$firstKey = array_pop($pieces);
$arrayVal = new ArrayVal();
$firstRule = array_reduce(
$pieces,
fn (?Validatable $rule, string $piece) => new When(
$arrayVal,
$this->createKeyRule($piece, $mandatory, $rule),
$this->createPropertyRule($piece, $mandatory, $rule),
),
$rule,
);

return new RuleSpec(
'when',
[
$arrayVal,
$this->createKeyRule($firstKey, $mandatory, $firstRule),
$this->createPropertyRule($firstKey, $mandatory, $firstRule),
]
);
}

private function createPropertyRule(string $name, bool $mandatory, ?Validatable $rule): Validatable
{
if ($rule === null) {
return new PropertyExists($name);
}

if ($mandatory) {
return new Property($name, $rule);
}

return new PropertyOptional($name, $rule);
}

private function createKeyRule(string $key, bool $mandatory, ?Validatable $rule): Validatable
{
if ($rule === null) {
return new KeyExists($key);
}

if ($mandatory) {
return new Key($key, $rule);
}

return new KeyOptional($key, $rule);
}
}
Loading

0 comments on commit 1e2c1bf

Please sign in to comment.