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

ObjectDataSet::parseObject()   B

Complexity

Conditions 8
Paths 18

Size

Total Lines 26
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 8

Importance

Changes 2
Bugs 1 Features 0
Metric Value
eloc 16
c 2
b 1
f 0
dl 0
loc 26
ccs 17
cts 17
cp 1
rs 8.4444
cc 8
nc 18
nop 0
crap 8
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 13
    public function __construct(
36
        object $object,
37
        int $propertyVisibility = ReflectionProperty::IS_PRIVATE|ReflectionProperty::IS_PROTECTED|ReflectionProperty::IS_PUBLIC
38
    ) {
39 13
        $this->object = $object;
40 13
        $this->propertyVisibility = $propertyVisibility;
41 13
        $this->parseObject();
42
    }
43
44 12
    public function getRules(): iterable
45
    {
46 12
        return $this->rules;
47
    }
48
49 5
    public function getAttributeValue(string $attribute): mixed
50
    {
51 5
        if ($this->dataSetProvided) {
52 2
            return $this->object->getAttributeValue($attribute);
53
        }
54
55 3
        return isset($this->reflectionProperties[$attribute])
56 3
            ? $this->reflectionProperties[$attribute]->getValue($this->object)
57 3
            : 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 13
    private function parseObject(): void
75
    {
76 13
        $objectProvidedRules = $this->object instanceof RulesProviderInterface;
77 13
        $this->dataSetProvided = $this->object instanceof DataSetInterface;
78
79 13
        $this->rules = $objectProvidedRules ? $this->object->getRules() : [];
80
81 13
        if ($this->dataSetProvided) {
82 2
            return;
83
        }
84
85 11
        $reflection = new ReflectionObject($this->object);
86 11
        foreach ($reflection->getProperties() as $property) {
87 10
            if (!$this->isUseProperty($property)) {
88 1
                continue;
89
            }
90
91 10
            if (PHP_VERSION_ID < 80100) {
92 10
                $property->setAccessible(true);
93
            }
94 10
            $this->reflectionProperties[$property->getName()] = $property;
95
96 10
            if (!$objectProvidedRules) {
97 9
                $attributes = $property->getAttributes(RuleInterface::class, ReflectionAttribute::IS_INSTANCEOF);
98 9
                foreach ($attributes as $attribute) {
99 6
                    $this->rules[$property->getName()][] = $attribute->newInstance();
100
                }
101
            }
102
        }
103
    }
104
105 10
    private function isUseProperty(ReflectionProperty $property): bool
106
    {
107 10
        return ($property->isPublic() && ($this->propertyVisibility&ReflectionProperty::IS_PUBLIC))
108 8
            || ($property->isPrivate() && ($this->propertyVisibility&ReflectionProperty::IS_PRIVATE))
109 10
            || ($property->isProtected() && ($this->propertyVisibility&ReflectionProperty::IS_PROTECTED));
110
    }
111
}
112