Passed
Pull Request — master (#322)
by
unknown
03:09
created

ObjectDataSet::hasAttribute()   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 0
Metric Value
eloc 1
c 0
b 0
f 0
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
cc 1
nc 1
nop 1
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 bool $dataSetProvided;
24
25
    /**
26
     * @var ReflectionProperty[]
27
     */
28
    private array $reflectionProperties = [];
29
30
    private iterable $rules;
31
32 43
    public function __construct(
33
        private object $object,
34
        private int $propertyVisibility = ReflectionProperty::IS_PRIVATE|ReflectionProperty::IS_PROTECTED|ReflectionProperty::IS_PUBLIC
35
    ) {
36 43
        $this->parseObject();
37
    }
38
39 4
    public function getObject(): object
40
    {
41 4
        return $this->object;
42
    }
43
44 35
    public function getRules(): iterable
45
    {
46 35
        return $this->rules;
47
    }
48
49 28
    public function getAttributeValue(string $attribute): mixed
50
    {
51 28
        if ($this->dataSetProvided) {
52 2
            return $this->object->getAttributeValue($attribute);
53
        }
54
55 26
        return isset($this->reflectionProperties[$attribute])
56 26
            ? $this->reflectionProperties[$attribute]->getValue($this->object)
57 26
            : null;
58
    }
59
60 9
    public function hasAttribute(string $attribute): bool
61
    {
62 9
        return true;
63
    }
64
65 7
    public function getData(): array
66
    {
67 7
        if ($this->dataSetProvided) {
68 2
            return $this->object->getData();
69
        }
70
71 5
        $data = [];
72 5
        foreach ($this->reflectionProperties as $name => $property) {
73 5
            $data[$name] = $property->getValue($this->object);
74
        }
75 5
        return $data;
76
    }
77
78
    // TODO: use Generator to collect attributes
79 43
    private function parseObject(): void
80
    {
81 43
        $objectHasRules = $this->object instanceof RulesProviderInterface;
82 43
        $this->rules = $objectHasRules ? $this->object->getRules() : [];
83
84 43
        $this->dataSetProvided = $this->object instanceof DataSetInterface;
85 43
        if ($this->dataSetProvided) {
86 2
            return;
87
        }
88
89 41
        $reflection = new ReflectionObject($this->object);
90 41
        foreach ($reflection->getProperties($this->propertyVisibility) as $property) {
91 40
            if (PHP_VERSION_ID < 80100) {
92 40
                $property->setAccessible(true);
93
            }
94 40
            $this->reflectionProperties[$property->getName()] = $property;
95
96 40
            if ($objectHasRules === true) {
97 6
                continue;
98
            }
99
100 35
            $attributes = $property->getAttributes(RuleInterface::class, ReflectionAttribute::IS_INSTANCEOF);
101 35
            foreach ($attributes as $attribute) {
102 32
                $rule = $attribute->newInstance();
103 32
                $this->rules[$property->getName()][] = $rule;
104
105 32
                if ($rule instanceof AttributeEventInterface) {
106 4
                    $rule->afterInitAttribute($this);
107
                }
108
            }
109
        }
110
    }
111
}
112