Passed
Pull Request — master (#291)
by Sergei
02:18
created

ObjectDataSet   A

Complexity

Total Complexity 22

Size/Duplication

Total Lines 90
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 2
Bugs 1 Features 0
Metric Value
wmc 22
eloc 40
c 2
b 1
f 0
dl 0
loc 90
ccs 40
cts 40
cp 1
rs 10

6 Methods

Rating   Name   Duplication   Size   Complexity  
B parseObject() 0 26 8
A getAttributeValue() 0 9 3
A getData() 0 11 3
A isUseProperty() 0 5 6
A getRules() 0 3 1
A __construct() 0 7 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Validator\DataSet;
6
7
use ReflectionAttribute;
8
use ReflectionObject;
9
use ReflectionProperty;
10
use Yiisoft\Validator\DataSetInterface;
11
use Yiisoft\Validator\RuleInterface;
12
use Yiisoft\Validator\RulesProviderInterface;
13
14
/**
15
 * This data set makes use of attributes introduced in PHP 8. It simplifies rules configuration process, especially for
16
 * nested data and relations. Please refer to the guide for example.
17
 *
18
 * @link https://www.php.net/manual/en/language.attributes.overview.php
19
 */
20
final class ObjectDataSet implements RulesProviderInterface, DataSetInterface
21
{
22
    private object $object;
23
24
    private bool $dataSetProvided;
25
26
    private int $propertyVisibility;
27
28
    /**
29
     * @var ReflectionProperty[]
30
     */
31
    private array $reflectionProperties = [];
32
33
    private iterable $rules;
34
35 19
    public function __construct(
36
        object $object,
37
        int $propertyVisibility = ReflectionProperty::IS_PRIVATE|ReflectionProperty::IS_PROTECTED|ReflectionProperty::IS_PUBLIC
38
    ) {
39 19
        $this->object = $object;
40 19
        $this->propertyVisibility = $propertyVisibility;
41 19
        $this->parseObject();
42
    }
43
44 14
    public function getRules(): iterable
45
    {
46 14
        return $this->rules;
47
    }
48
49 9
    public function getAttributeValue(string $attribute): mixed
50
    {
51 9
        if ($this->dataSetProvided) {
52 2
            return $this->object->getAttributeValue($attribute);
53
        }
54
55 7
        return isset($this->reflectionProperties[$attribute])
56 7
            ? $this->reflectionProperties[$attribute]->getValue($this->object)
57 7
            : null;
58
    }
59
60 5
    public function getData(): array
61
    {
62 5
        if ($this->dataSetProvided) {
63 2
            return $this->object->getData();
64
        }
65
66 3
        $data = [];
67 3
        foreach ($this->reflectionProperties as $name => $property) {
68 3
            $data[$name] = $property->getValue($this->object);
69
        }
70 3
        return $data;
71
    }
72
73
    // TODO: use Generator to collect attributes
74 19
    private function parseObject(): void
75
    {
76 19
        $objectProvidedRules = $this->object instanceof RulesProviderInterface;
77 19
        $this->dataSetProvided = $this->object instanceof DataSetInterface;
78
79 19
        $this->rules = $objectProvidedRules ? $this->object->getRules() : [];
80
81 19
        if ($this->dataSetProvided) {
82 2
            return;
83
        }
84
85 17
        $reflection = new ReflectionObject($this->object);
86 17
        foreach ($reflection->getProperties() as $property) {
87 16
            if (!$this->isUseProperty($property)) {
88 1
                continue;
89
            }
90
91 16
            if (PHP_VERSION_ID < 80100) {
92 16
                $property->setAccessible(true);
93
            }
94 16
            $this->reflectionProperties[$property->getName()] = $property;
95
96 16
            if (!$objectProvidedRules) {
97 12
                $attributes = $property->getAttributes(RuleInterface::class, ReflectionAttribute::IS_INSTANCEOF);
98 12
                foreach ($attributes as $attribute) {
99 9
                    $this->rules[$property->getName()][] = $attribute->newInstance();
100
                }
101
            }
102
        }
103
    }
104
105 16
    private function isUseProperty(ReflectionProperty $property): bool
106
    {
107 16
        return ($property->isPublic() && ($this->propertyVisibility&ReflectionProperty::IS_PUBLIC))
108 14
            || ($property->isPrivate() && ($this->propertyVisibility&ReflectionProperty::IS_PRIVATE))
109 16
            || ($property->isProtected() && ($this->propertyVisibility&ReflectionProperty::IS_PROTECTED));
110
    }
111
}
112