Skip to content

Commit

Permalink
Only pass the necessary parameters to the exceptions
Browse files Browse the repository at this point in the history
Currently, we convert the properties of a rule into parameters and pass
them to the exceptions. That complicates things for a few reasons:

1. The exception knows too much: there's a lot of information in an
   object, and the exception would only need a few parameters to work
   correctly.

2. Any variable change becomes a backward compatibility break: if we
   change the name of the variable type in a rule, even if it's a
   private one, we may need to change the template, which is a backward
   compatibility break.

3. The factory is bloated because of introspection tricks: it reads the
   properties from the class, even from the parent, and then passes it
   to the exception.

Of course, that means we introduce another method to `Validatable`, but
in most cases, extending `AbstractRule` is enough to create a new rule.

Signed-off-by: Henrique Moody <[email protected]>
  • Loading branch information
henriquemoody committed Jan 29, 2024
1 parent dd896bb commit 2b59e3d
Show file tree
Hide file tree
Showing 43 changed files with 298 additions and 106 deletions.
30 changes: 1 addition & 29 deletions library/Factory.php
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ public function exception(Validatable $validatable, mixed $input, array $extraPa
$formatter = new Formatter($this->translator, $this->parameterStringifier);
$reflection = new ReflectionObject($validatable);
$ruleName = $reflection->getShortName();
$params = ['input' => $input] + $extraParams + $this->extractPropertiesValues($validatable, $reflection);
$params = ['input' => $input] + $extraParams + $validatable->getParams();
$id = lcfirst($ruleName);
if ($validatable->getName() !== null) {
$id = $params['name'] = $validatable->getName();
Expand Down Expand Up @@ -181,32 +181,4 @@ private function createReflectionClass(string $name, string $parentName): Reflec

return $reflection;
}

/**
* @param ReflectionObject|ReflectionClass<Validatable> $reflection
* @return mixed[]
*/
private function extractPropertiesValues(Validatable $validatable, ReflectionClass $reflection): array
{
$values = [];
foreach ($reflection->getProperties() as $property) {
if (!$property->isInitialized($validatable)) {
continue;
}

$propertyValue = $property->getValue($validatable);
if ($propertyValue === null) {
continue;
}

$values[$property->getName()] = $propertyValue;
}

$parentReflection = $reflection->getParentClass();
if ($parentReflection !== false) {
return $values + $this->extractPropertiesValues($validatable, $parentReflection);
}

return $values;
}
}
8 changes: 8 additions & 0 deletions library/Rules/AbstractAge.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,14 @@ public function validate(mixed $input): bool
return $this->isValidWithFormat($this->format, (string) $input);
}

/**
* @return array<string, int>
*/
public function getParams(): array
{
return ['age' => $this->age];
}

private function isValidWithoutFormat(string $dateTime): bool
{
$timestamp = strtotime($dateTime);
Expand Down
8 changes: 8 additions & 0 deletions library/Rules/AbstractComparison.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,12 @@ public function validate(mixed $input): bool

return $this->compare($left, $right);
}

/**
* @return array<string, mixed>
*/
public function getParams(): array
{
return ['compareTo' => $this->compareTo];
}
}
8 changes: 8 additions & 0 deletions library/Rules/AbstractFilterRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,14 @@ public function getTemplate(mixed $input): string
return $this->template ?? ($this->additionalChars ? self::TEMPLATE_EXTRA : self::TEMPLATE_STANDARD);
}

/**
* @return array<string, mixed>
*/
public function getParams(): array
{
return ['additionalChars' => $this->additionalChars];
}

private function filter(string $input): string
{
return str_replace(str_split($this->additionalChars), '', $input);
Expand Down
8 changes: 8 additions & 0 deletions library/Rules/AbstractRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,14 @@ public function getTemplate(mixed $input): string
return $this->template ?? self::TEMPLATE_STANDARD;
}

/**
* @return array<string, mixed>
*/
public function getParams(): array
{
return [];
}

public function __invoke(mixed $input): bool
{
return $this->validate($input);
Expand Down
8 changes: 8 additions & 0 deletions library/Rules/Base.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,12 @@ public function validate(mixed $input): bool

return (bool) preg_match('@^[' . $valid . ']+$@', (string) $input);
}

/**
* @return array<string, int>
*/
public function getParams(): array
{
return ['base' => $this->base];
}
}
8 changes: 8 additions & 0 deletions library/Rules/Call.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,14 @@ public function validate(mixed $input): bool
return true;
}

/**
* @return array<string, callable>
*/
public function getParams(): array
{
return ['callable' => $this->callable];
}

private function setErrorHandler(mixed $input): void
{
set_error_handler(function () use ($input): void {
Expand Down
8 changes: 8 additions & 0 deletions library/Rules/Charset.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,12 @@ public function validate(mixed $input): bool
{
return in_array(mb_detect_encoding($input, $this->charset, true), $this->charset, true);
}

/**
* @return array<string, array<string>>
*/
public function getParams(): array
{
return ['charset' => $this->charset];
}
}
8 changes: 8 additions & 0 deletions library/Rules/Contains.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,14 @@ public function validate(mixed $input): bool
return $this->validateString((string) $input, (string) $this->containsValue);
}

/**
* @return array<string, mixed>
*/
public function getParams(): array
{
return ['containsValue' => $this->containsValue];
}

private function validateString(string $haystack, string $needle): bool
{
if ($needle === '') {
Expand Down
8 changes: 8 additions & 0 deletions library/Rules/CreditCard.php
Original file line number Diff line number Diff line change
Expand Up @@ -92,4 +92,12 @@ public function getTemplate(mixed $input): string

return self::TEMPLATE_BRANDED;
}

/**
* @return array<string, string>
*/
public function getParams(): array
{
return ['brand' => $this->brand];
}
}
12 changes: 8 additions & 4 deletions library/Rules/Date.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@ final class Date extends AbstractRule
{
use CanValidateDateTime;

private readonly string $sample;

/**
* @throws ComponentException
*/
Expand All @@ -33,8 +31,6 @@ public function __construct(
if (!preg_match('/^[djSFmMnYy\W]+$/', $format)) {
throw new ComponentException(sprintf('"%s" is not a valid date format', $format));
}

$this->sample = date($format, strtotime('2005-12-30'));
}

public function validate(mixed $input): bool
Expand All @@ -45,4 +41,12 @@ public function validate(mixed $input): bool

return $this->isDateTime($this->format, (string) $input);
}

/**
* @return array<string, mixed>
*/
public function getParams(): array
{
return ['sample' => date($this->format, strtotime('2005-12-30'))];
}
}
11 changes: 8 additions & 3 deletions library/Rules/DateTime.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,9 @@ final class DateTime extends AbstractRule

public const TEMPLATE_FORMAT = 'format';

private readonly string $sample;

public function __construct(
private readonly ?string $format = null
) {
$this->sample = date($format ?: 'c', strtotime('2005-12-30 01:02:03'));
}

public function validate(mixed $input): bool
Expand All @@ -51,4 +48,12 @@ public function getTemplate(mixed $input): string
{
return $this->template ?? ($this->format !== null ? self::TEMPLATE_FORMAT : self::TEMPLATE_STANDARD);
}

/**
* @return array<string, mixed>
*/
public function getParams(): array
{
return ['sample' => date($this->format ?: 'c', strtotime('2005-12-30 01:02:03'))];
}
}
8 changes: 8 additions & 0 deletions library/Rules/Decimal.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@ public function validate(mixed $input): bool
return $this->toFormattedString($input) === $this->toRawString($input);
}

/**
* @return array<string, int>
*/
public function getParams(): array
{
return ['decimals' => $this->decimals];
}

private function toRawString(mixed $input): string
{
if (is_string($input)) {
Expand Down
8 changes: 8 additions & 0 deletions library/Rules/EndsWith.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@ public function validate(mixed $input): bool
return $this->validateEquals($input);
}

/**
* @return array<string, mixed>
*/
public function getParams(): array
{
return ['endValue' => $this->endValue];
}

private function validateEquals(mixed $input): bool
{
if (is_array($input)) {
Expand Down
11 changes: 3 additions & 8 deletions library/Rules/Equals.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,10 @@

namespace Respect\Validation\Rules;

final class Equals extends AbstractRule
final class Equals extends AbstractComparison
{
public function __construct(
private readonly mixed $compareTo
) {
}

public function validate(mixed $input): bool
protected function compare(mixed $left, mixed $right): bool
{
return $input == $this->compareTo;
return $left == $right;
}
}
8 changes: 8 additions & 0 deletions library/Rules/Equivalent.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,14 @@ public function validate(mixed $input): bool
return $input == $this->compareTo;
}

/**
* @return array<string, mixed>
*/
public function getParams(): array
{
return ['compareTo' => $this->compareTo];
}

private function isStringEquivalent(string $input): bool
{
if (!is_scalar($this->compareTo)) {
Expand Down
8 changes: 8 additions & 0 deletions library/Rules/Extension.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,12 @@ public function validate(mixed $input): bool

return $this->extension === pathinfo($input, PATHINFO_EXTENSION);
}

/**
* @return array<string, string>
*/
public function getParams(): array
{
return ['extension' => $this->extension];
}
}
8 changes: 8 additions & 0 deletions library/Rules/Factor.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,12 @@ public function validate(mixed $input): bool
// factor of the dividend.
return is_integer($dividend / $input);
}

/**
* @return array<string, int>
*/
public function getParams(): array
{
return ['dividend' => $this->dividend];
}
}
11 changes: 3 additions & 8 deletions library/Rules/Identical.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,10 @@

namespace Respect\Validation\Rules;

final class Identical extends AbstractRule
final class Identical extends AbstractComparison
{
public function __construct(
private readonly mixed $compareTo
) {
}

public function validate(mixed $input): bool
protected function compare(mixed $left, mixed $right): bool
{
return $input === $this->compareTo;
return $left === $right;
}
}
8 changes: 8 additions & 0 deletions library/Rules/In.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@ public function validate(mixed $input): bool
return $this->validateEquals($input);
}

/**
* @return array<string, mixed>
*/
public function getParams(): array
{
return ['haystack' => $this->haystack];
}

private function validateEquals(mixed $input): bool
{
if (is_array($this->haystack)) {
Expand Down
8 changes: 8 additions & 0 deletions library/Rules/Instance.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,12 @@ public function validate(mixed $input): bool
{
return $input instanceof $this->instanceName;
}

/**
* @return array<string, mixed>
*/
public function getParams(): array
{
return ['instanceName' => $this->instanceName];
}
}
8 changes: 8 additions & 0 deletions library/Rules/Ip.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,14 @@ public function getTemplate(mixed $input): string
return $this->template ?? ($this->range ? self::TEMPLATE_NETWORK_RANGE : self::TEMPLATE_STANDARD);
}

/**
* @return array<string, mixed>
*/
public function getParams(): array
{
return ['range' => $this->range];
}

private function createRange(): ?string
{
if ($this->startAddress && $this->endAddress) {
Expand Down
11 changes: 11 additions & 0 deletions library/Rules/KeySet.php
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,17 @@ public function getTemplate(mixed $input): string
return KeySet::TEMPLATE_STRUCTURE;
}

/**
* @return array<string, mixed>
*/
public function getParams(): array
{
return [
'keys' => $this->keys,
'extraKeys' => $this->extraKeys,
];
}

/**
* @throws ComponentException
*/
Expand Down
Loading

0 comments on commit 2b59e3d

Please sign in to comment.