Passed
Pull Request — master (#229)
by Wilmer
03:18
created

FormCollector::__construct()   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 1
crap 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Form;
6
7
use Exception;
8
use InvalidArgumentException;
9
use ReflectionAttribute;
10
use ReflectionNamedType;
11
use ReflectionObject;
12
use Yiisoft\Validator\RuleInterface;
13
14
final class FormCollector
15
{
16
    private array $attributes;
17
    private array $rules = [];
18
19 563
    public function __construct(private FormModelInterface $formModel)
20
    {
21 563
        [$this->attributes, $this->rules] = $this->collectAttributes();
22
    }
23
24 524
    public function attributes(): array
25
    {
26 524
        return $this->attributes;
27
    }
28
29 9
    public function getType(string $attribute): string
30
    {
31 9
        return match (isset($this->attributes[$attribute]) && is_string($this->attributes[$attribute])) {
32 8
            true => $this->attributes[$attribute],
33 9
            false => '',
34
        };
35
    }
36
37 2
    public function getRules(): array
38
    {
39 2
        return $this->rules;
40
    }
41
42
    /**
43
     * Returns the type of the given value.
44
     */
45 25
    public function phpTypeCast(string $name, mixed $value): mixed
46
    {
47 25
        if (!$this->formModel->hasAttribute($name)) {
48 4
            return null;
49
        }
50
51 23
        if ($value === null) {
52 3
            return null;
53
        }
54
55
        try {
56 21
            return match ($this->attributes[$name]) {
57 4
                'bool' => (bool) $value,
58 2
                'float' => (float) $value,
59 3
                'int' => (int) $value,
60 18
                'string' => (string) $value,
61 20
                default => $value,
62
            };
63 1
        } catch (Exception $e) {
64 1
            throw new InvalidArgumentException(
65 1
                sprintf('The value is not of type "%s".', (string) $this->attributes[$name])
66
            );
67
        }
68
    }
69
70
    /**
71
     * Returns the list of attribute types indexed by attribute names.
72
     *
73
     * By default, this method returns all non-static properties of the class.
74
     *
75
     * @return array list of attribute types indexed by attribute names.
76
     *
77
     * @psalm-suppress UndefinedClass
78
     */
79 563
    private function collectAttributes(): array
80
    {
81 563
        $reflection = new ReflectionObject($this->formModel);
82 563
        $attributes = [];
83 563
        $rules = [];
84
85 563
        foreach ($reflection->getProperties() as $property) {
86 558
            if ($property->isStatic() === false) {
87
                /** @var ReflectionNamedType|null $type */
88 558
                $type = $property->getType();
89 558
                $attributes[$property->getName()] = $type !== null ? $type->getName() : '';
90 558
                $attributeRules = $property->getAttributes(RuleInterface::class, ReflectionAttribute::IS_INSTANCEOF);
91
92 558
                foreach ($attributeRules as $attributeRule) {
93 1
                    $rules[$property->getName()][] = $attributeRule->newInstance();
94
                }
95
            }
96
        }
97
98 563
        return [$attributes, $rules];
99
    }
100
}
101