Passed
Pull Request — master (#322)
by
unknown
02:36
created

ObjectDataSet::getRules()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

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