respect-validation/library/Rules/Property.php
Henrique Moody 0d4a5fe2be
Enable validating private properties of parent classes
All validators related to object properties only consider the properties
of the object being validated, not those of its parent object. That's
because PHP reflection only gets the properties visible to the current
class (public or protected). The problem with that is that when there's
a private property in the parent class, we're completely unaware of it.

This commit will modify those rules by retrieving properties from the
parent class, ensuring we capture all properties that require
validation.
2025-12-23 16:44:04 +01:00

57 lines
1.6 KiB
PHP

<?php
/*
* Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
* SPDX-License-Identifier: MIT
*/
declare(strict_types=1);
namespace Respect\Validation\Rules;
use Attribute;
use ReflectionClass;
use ReflectionObject;
use Respect\Validation\Path;
use Respect\Validation\Result;
use Respect\Validation\Rule;
use Respect\Validation\Rules\Core\Wrapper;
#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)]
final class Property extends Wrapper
{
public function __construct(
private readonly string $propertyName,
Rule $rule,
) {
parent::__construct($rule);
}
public function evaluate(mixed $input): Result
{
$propertyExistsResult = (new PropertyExists($this->propertyName))->evaluate($input);
if (!$propertyExistsResult->hasPassed) {
return $propertyExistsResult->withNameFrom($this->rule);
}
return $this->rule
->evaluate($this->getPropertyValue($input, $this->propertyName))
->withPath(new Path($this->propertyName));
}
private function getPropertyValue(object $object, string $propertyName): mixed
{
$reflection = new ReflectionObject($object);
while ($reflection instanceof ReflectionClass) {
if ($reflection->hasProperty($propertyName)) {
$property = $reflection->getProperty($propertyName);
return $property->isInitialized($object) ? $property->getValue($object) : null;
}
$reflection = $reflection->getParentClass();
}
return null;
}
}