Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
84.62% covered (warning)
84.62%
22 / 26
88.89% covered (warning)
88.89%
8 / 9
CRAP
0.00% covered (danger)
0.00%
0 / 1
FromProperty
84.62% covered (warning)
84.62%
22 / 26
88.89% covered (warning)
88.89%
8 / 9
20.31
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getTypehint
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
12
 isOptional
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
3
 fromNative
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 fillField
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 fillMissingField
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
5
 isInitialized
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getValue
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 toNative
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2namespace Apie\Core\ValueObjects\Fields;
3
4use Apie\Core\Attributes\Optional;
5use Apie\Core\Exceptions\InvalidTypeException;
6use Apie\Core\ValueObjects\Interfaces\ValueObjectInterface;
7use Apie\Core\ValueObjects\Utils;
8use ReflectionIntersectionType;
9use ReflectionNamedType;
10use ReflectionProperty;
11use ReflectionUnionType;
12use UnitEnum;
13
14/**
15 * FieldInterface implementation that reads a property from an object with reflection.
16 */
17final class FromProperty implements FieldInterface
18{
19    private ReflectionProperty $property;
20
21    public function __construct(ReflectionProperty $property)
22    {
23        $this->property = $property;
24    }
25
26    public function getTypehint(): string
27    {
28        $type = $this->property->getType();
29        if ($type instanceof ReflectionNamedType) {
30            return ($type->allowsNull() ? $type->getName() : ($type->getName() . '|null'));
31        }
32        return (string) $type;
33    }
34
35    public function isOptional(): bool
36    {
37        return $this->property->hasDefaultValue()
38            || !empty($this->property->getAttributes(Optional::class))
39            || $this->property->getType()->allowsNull();
40    }
41
42    public function fromNative(ValueObjectInterface $instance, mixed $value): void
43    {
44        $type = $this->property->getType();
45        if ($type instanceof ReflectionUnionType || $type instanceof ReflectionNamedType) {
46            self::fillField($instance, Utils::toTypehint($type, $value));
47            return;
48        }
49        throw new InvalidTypeException($type, 'ReflectionUnionType|ReflectionNamedType');
50    }
51
52    public function fillField(ValueObjectInterface $instance, mixed $value): void
53    {
54        $this->property->setValue($instance, $value);
55    }
56
57    public function fillMissingField(ValueObjectInterface $instance): void
58    {
59        if (!$this->isOptional()) {
60            $type = $this->property->getType();
61            if (null === $type || $type instanceof ReflectionIntersectionType) {
62                throw new InvalidTypeException($type, 'ReflectionUnionType|ReflectionNamedType');
63            }
64            throw new InvalidTypeException('(missing value)', (string) $type);
65        }
66        if (!empty($this->property->getAttributes(Optional::class))) {
67            return;
68        }
69        $this->property->setValue($instance, $this->property->getDefaultValue());
70    }
71
72    public function isInitialized(ValueObjectInterface $instance): bool
73    {
74        return $this->property->isInitialized($instance);
75    }
76
77    public function getValue(ValueObjectInterface $instance): mixed
78    {
79        return $this->property->getValue($instance);
80    }
81
82    public function toNative(ValueObjectInterface $instance): null|array|string|int|float|bool|UnitEnum
83    {
84        $value = $this->getValue($instance);
85        return Utils::toNative($value);
86    }
87}