PropertyFactory::checkRemainingProperties()   A
last analyzed

Complexity

Conditions 5
Paths 5

Size

Total Lines 14
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 5

Importance

Changes 0
Metric Value
eloc 9
dl 0
loc 14
ccs 10
cts 10
cp 1
rs 9.6111
c 0
b 0
f 0
cc 5
nc 5
nop 1
crap 5
1
<?php
2
3
namespace Larapie\DataTransferObject\Factories;
4
5
use ReflectionClass;
6
use ReflectionProperty;
7
use Larapie\DataTransferObject\Property\Property;
8
use Larapie\DataTransferObject\Contracts\DtoContract;
9
use Larapie\DataTransferObject\Contracts\AdditionalProperties;
10
use Larapie\DataTransferObject\Contracts\WithAdditionalProperties;
11
use Larapie\DataTransferObject\Exceptions\UnknownPropertiesDtoException;
12
13
class PropertyFactory
14
{
15
    /**
16
     * @var DtoContract
17
     */
18
    protected $dto;
19
20
    /**
21
     * @var Property[]
22
     */
23
    private static $cache = [];
24
25
    /**
26
     * PropertyValueFactory constructor.
27
     * @param DtoContract $dto
28
     */
29 51
    public function __construct(DtoContract &$dto)
30
    {
31 51
        $this->dto = $dto;
32 51
    }
33
34 51
    public function build(array $parameters)
35
    {
36 51
        $properties = [];
37 51
        foreach ($this->getProperties() as $property) {
38 44
            if (array_key_exists($property->getName(), $parameters)) {
39 40
                $property->set($parameters[$property->getName()]);
40
            }
41
42
            /* add the property to an associative array with the name as key */
43 44
            $properties[$property->getName()] = $property;
44
45
            /* remove the property from the value object and parameters array  */
46 44
            unset($parameters[$property->getName()], $this->dto->{$property->getName()});
47
        }
48
49 50
        $this->checkRemainingProperties($parameters);
50
51 47
        return $properties;
52
    }
53
54 51
    protected function getDtoClass(): string
55
    {
56 51
        return get_class($this->dto);
57
    }
58
59 42
    protected function buildProperties()
60
    {
61 42
        $class = new ReflectionClass($this->dto);
62
63 42
        $properties = [];
64 42
        foreach ($class->getProperties(ReflectionProperty::IS_PUBLIC) as $reflectionProperty) {
65 36
            $property = new Property($reflectionProperty);
66
67
            //Set default value
68 35
            $property->setDefault($default = $reflectionProperty->getValue($this->dto));
69 35
            if ($default !== null) {
70 2
                $property->set($default);
71
            }
72
73
            //If property is immutable make sure all nested values are also immutable
74 35
            if ($property->isImmutable()) {
75 2
                $property->chainImmutable(true);
76
            }
77
78 35
            $properties[$reflectionProperty->getName()] = $property;
79
        }
80
81 41
        return $properties;
82
    }
83
84 51
    protected function dtoIsCached()
85
    {
86 51
        return isset(self::$cache[$this->getDtoClass()]);
87
    }
88
89 51
    protected function getProperties(): array
90
    {
91 51
        if (! $this->dtoIsCached()) {
92 42
            $properties = $this->buildProperties();
93
94 41
            self::$cache[$this->getDtoClass()] = $properties;
95
96 41
            return $properties;
97
        }
98
99 15
        return $this->getFreshProperties();
100
    }
101
102 15
    protected function getFreshProperties()
103
    {
104 15
        $properties = [];
105 15
        foreach (self::$cache[$this->getDtoClass()] as $key => $property) {
106 15
            $property = clone $property;
107 15
            $property->reset();
108 15
            $properties[$key] = $property;
109
        }
110
111 15
        return $properties;
112
    }
113
114 50
    protected function checkRemainingProperties(array $parameters)
115
    {
116 50
        if (empty($parameters)) {
117 45
            return;
118 5
        } elseif ($this->dto instanceof WithAdditionalProperties) {
119 1
            foreach ($parameters as $name => $parameter) {
120 1
                $this->dto->with($name, $parameter);
121
            }
122
123 1
            return;
124 4
        } elseif ($this->dto instanceof AdditionalProperties) {
125 1
            return;
126
        }
127 3
        throw new UnknownPropertiesDtoException($parameters, $this->getDtoClass());
128
    }
129
}
130