MagicResource::ensurePropertiesConsistency()   A
last analyzed

Complexity

Conditions 4
Paths 3

Size

Total Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 4

Importance

Changes 0
Metric Value
dl 0
loc 12
ccs 8
cts 8
cp 1
rs 9.8666
c 0
b 0
f 0
cc 4
nc 3
nop 0
crap 4
1
<?php
2
3
/**
4
 * This file is part of sensorario/resources repository
5
 *
6
 * (c) Simone Gentili <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Sensorario\Resources;
13
14
use Sensorario\Resources\Configurator;
15
use Sensorario\Resources\Exceptions\FactoryMethodException;
16
use Sensorario\Resources\Validators\ResourcesValidator;
17
18
/**
19
 * @method array defaults() returns resource's default values
20
 * @method array rules() returns resource's rules
21
 */
22
abstract class MagicResource
23
{
24
    protected $properties = [];
25
26
    protected $validator;
27
28
    protected $configuration;
29
30
    private static $methodWhiteList = [
31
        'box',
32
        'allowedValues'
33
    ];
34
35 3
    public function __call($functionName, $arguments)
36
    {
37 3
        $propertyName = strtolower($functionName);
38
39 3
        if ($this->hasProperty($propertyName)) {
40 1
            return $this->get($propertyName);
41
        }
42
43 2
        if (isset($this->defaults()[$propertyName])) {
44 1
            return $this->defaults()[$propertyName];
45
        }
46
47 1
        throw new \Sensorario\Resources\Exceptions\UndefinedMethodException(
48 1
            'Method `' . get_class($this)
49 1
            . '::' . $functionName
50 1
            . '()` is not yet implemented'
51
        );
52
    }
53
54
    abstract public function applyConfiguration(Configurator $configurator);
55
56 43
    public function __construct(
57
        array $properties,
58
        ResourcesValidator $validator,
59
        Configurator $configuration = null
60
    ) {
61 43
        $this->properties    = $properties;
62 43
        $this->validator     = $validator;
63 43
        $this->configuration = $configuration;
64
65 43
        if ($configuration) {
66 24
            $this->applyConfiguration(
67 24
                $configuration
68
            );
69
        }
70
71 43
        $this->init();
72 27
    }
73
74 43
    private function init()
75
    {
76 43
        $this->ensurePropertiesConsistency();
77 42
        $this->validate();
78 27
    }
79
80 43
    public static function __callStatic($methodName, array $args)
81
    {
82 43
        $isMethodAllowed = in_array($methodName, self::$methodWhiteList);
83 43
        $configuration = null;
84
85 43
        if (isset($args[1]) && 'Sensorario\Resources\Configurator' == get_class($args[1])) {
86 24
            $configuration = new Configurator($args[1]->resourceName(), $args[1]->container());
87
        }
88
89 43
        if ($isMethodAllowed) {
90 42
            return new static($args[0] ?? [], new ResourcesValidator(), $configuration);
91
        }
92
93 1
        throw new FactoryMethodException('Invalid factory method ' . '`' . $methodName . '`');
94
    }
95
96 32
    final public function hasProperty($propertyName)
97
    {
98
        return isset(
99 32
            $this->properties[$propertyName]
100
        );
101
    }
102
103 1
    final public function set($propertyName, $propertValue) 
104
    {
105 1
        $this->properties[$propertyName] = $propertValue;
106 1
    }
107
108 24
    final public function get($propertyName)
109
    {
110 24
        $this->ensurePropertyNameIsNotEmpty($propertyName);
111
112 23
        if ($this->hasNotProperty($propertyName)) {
113 3
            if ($prop = $this->defaults()[$propertyName] ?? false) {
114 2
                return $prop;
115
            }
116
117 1
            throw new \Sensorario\Resources\Exceptions\NoValuesException(
118
                'No value nor method `'
119 1
                . $propertyName
120 1
                . '` found in this resource'
121
            );
122
        }
123
124 20
        return $this->properties[$propertyName];
125
    }
126
127 28
    final public function hasNotProperty($propertyName)
128
    {
129 28
        return !$this->hasProperty($propertyName);
130
    }
131
132 2
    final public function hasProperties(array $properties)
133
    {
134 2
        foreach ($properties as $property) {
135 2
            if ($this->hasNotProperty($property)) {
136 2
                return false;
137
            }
138
        }
139
140 1
        return true;
141
    }
142
143 42
    final public function properties()
144
    {
145 42
        $properties = $this->properties;
146
147 42
        foreach ($properties as $k => $v) {
148 33
            if ('object' === gettype($v)) {
149 5
                $this->ensurePropertyIsAnObjectDefined($k);
150
151 4
                if ($this->rules()[$k]['object'] === '\\Sensorario\\Resources\\Resource') {
152 32
                    $properties[$k] = $v->properties();
153
                }
154
            }
155
        }
156
157 41
        return $properties;
158
    }
159
160 42
    public function validate()
161
    {
162 42
        $this->validator->validate($this);
163 27
    }
164
165 43
    public function ensurePropertiesConsistency()
166
    {
167 43
        foreach ($this->properties as $k => $v) {
168 34
            if ('object' === gettype($v) && !isset($this->rules()[$k])) {
169 1
                throw new \Sensorario\Resources\Exceptions\PropertyWithoutRuleException(
170 1
                    'When property `' . $k . '` is an object class, must be defined in Resources::rules()' .
171 1
                    ' but rules here are equals to ' . var_export($this->rules(), true)
172 34
                    . ' And properties are ' . var_export($this->properties, true)
173
                );
174
            }
175
        }
176 42
    }
177
178 24
    public function ensurePropertyNameIsNotEmpty($propertyName)
179
    {
180 24
        if ('' == $propertyName) {
181 1
            throw new \Sensorario\Resources\Exceptions\PropertyNameEmptyException(
182 1
                'Oops! Property name requested is empty string!!'
183
            );
184
        }
185 23
    }
186
187 5
    public function ensurePropertyIsAnObjectDefined($k)
188
    {
189 5
        if (!isset($this->rules()[$k]['object'])) {
190 1
            throw new \Sensorario\Resources\Exceptions\PropertyWithoutRuleException(
191 1
                'Property ' . $k . ' is an object but is not defined in rules'
192
            );
193
        }
194 4
    }
195
}
196