Passed
Push — master ( 1c9156...45c19c )
by Simone
02:07
created

MagicResource::ensurePropertyNameIsNotEmpty()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 8
ccs 5
cts 5
cp 1
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 4
nc 2
nop 1
crap 2
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\Validators\ResourcesValidator;
16
17
/**
18
 * @method array defaults() returns resource's default values
19
 * @method array rules() returns resource's rules
20
 */
21
abstract class MagicResource
22
{
23
    protected $properties = [];
24
25
    protected $validator;
26
27
    private static $methodWhiteList = [
28
        'box',
29
        'allowedValues'
30
    ];
31
32 3
    public function __call($functionName, $arguments)
33
    {
34 3
        $propertyName = strtolower($functionName);
35
36 3
        if ($this->hasProperty($propertyName)) {
37 1
            return $this->get($propertyName);
38
        }
39
40 2
        if (isset($this->defaults()[$propertyName])) {
41 1
            return $this->defaults()[$propertyName];
42
        }
43
44 1
        throw new \Sensorario\Resources\Exceptions\UndefinedMethodException(
45 1
            'Method `' . get_class($this)
46 1
            . '::' . $functionName 
47 1
            . '()` is not yet implemented'
48
        );
49
    }
50
51
    abstract public function applyConfiguration(Configurator $configurator);
52
53 39
    public function __construct(
54
        array $properties,
55
        ResourcesValidator $validator,
56
        Configurator $configuration = null
57
    ) {
58 39
        $this->properties    = $properties;
59 39
        $this->validator     = $validator;
60 39
        $this->configuration = $configuration;
0 ignored issues
show
Bug introduced by
The property configuration does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
61
62 39
        if ($configuration) {
63 21
            $this->applyConfiguration(
64 21
                $configuration
65
            );
66
        }
67
68 39
        $this->init();
69 24
    }
70
71 39
    private function init()
72
    {
73 39
        $this->ensurePropertiesConsistency();
74 38
        $this->validate();
75 24
    }
76
77 39
    public static function __callStatic($methodName, array $args)
78
    {
79 39
        $isMethodAllowed = in_array(
80 39
            $methodName,
81 39
            self::$methodWhiteList
82
        );
83
84 39
        $configuration = null;
85
86
        if (
87 39
            isset($args[1])
88 22
            && 'Sensorario\Resources\Configurator' == get_class($args[1])
89
        ) {
90 21
            $configuration = new Configurator(
91 21
                $args[1]->resourceName(),
92 21
                $args[1]->container()
93
            );
94
        }
95
96 39
        if ($isMethodAllowed) {
97 38
            return new static(
98 38
                $args[0] ?? [],
99 38
                new ResourcesValidator(),
100 38
                $configuration
101
            );
102
        }
103
104 1
        throw new \Sensorario\Resources\Exceptions\FactoryMethodException(
105
            'Invalid factory method '
106 1
            . '`' . $methodName . '`'
107
        );
108
    }
109
110 31
    final public function hasProperty($propertyName)
111
    {
112
        return isset(
113 31
            $this->properties[$propertyName]
114
        );
115
    }
116
117 1
    final public function set($propertyName, $propertValue) 
118
    {
119 1
        $this->properties[$propertyName] = $propertValue;
120 1
    }
121
122 24
    final public function get($propertyName)
123
    {
124 24
        $this->ensurePropertyNameIsNotEmpty($propertyName);
125
126 23
        if ($this->hasNotProperty($propertyName)) {
127 3
            if ($prop = $this->defaults()[$propertyName] ?? false) {
128 2
                return $prop;
129
            }
130
131 1
            throw new \Sensorario\Resources\Exceptions\NoValuesException(
132
                'No value nor method `'
133 1
                . $propertyName
134 1
                . '` found in this resource'
135
            );
136
        }
137
138 20
        return $this->properties[$propertyName];
139
    }
140
141 29
    final public function hasNotProperty($propertyName)
142
    {
143 29
        return !$this->hasProperty($propertyName);
144
    }
145
146 2
    final public function hasProperties(array $properties)
147
    {
148 2
        foreach ($properties as $property) {
149 2
            if ($this->hasNotProperty($property)) {
150 1
                return false;
151
            }
152
        }
153
154 1
        return true;
155
    }
156
157 38
    final public function properties()
158
    {
159 38
        $properties = $this->properties;
160
161 38
        foreach ($properties as $k => $v) {
162 30
            if ('object' === gettype($v)) {
163 5
                if (!isset($this->rules()[$k]['object'])) {
164 1
                    throw new \Sensorario\Resources\Exceptions\PropertyWithoutRuleException(
165 1
                        'Property ' . $k . ' is an object but is not defined in rules'
166
                    );
167
                }
168
169 4
                if ($this->rules()[$k]['object'] === '\\Sensorario\\Resources\\Resource') {
170 1
                    $properties[$k] = $v->properties();
171
                }
172
173 4
                if ($this->rules()[$k]['object'] === 'array') {
174
                    $properties[$k] = (array) $v;
175
                }
176
            }
177
        }
178
179 37
        return $properties;
180
    }
181
182 38
    public function validate()
183
    {
184 38
        $this->validator->validate($this);
0 ignored issues
show
Compatibility introduced by
$this of type object<Sensorario\Resources\MagicResource> is not a sub-type of object<Sensorario\Resources\Resource>. It seems like you assume a child class of the class Sensorario\Resources\MagicResource to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
185 24
    }
186
187 39
    public function ensurePropertiesConsistency()
188
    {
189 39
        foreach ($this->properties as $k => $v) {
190 31
            if ('object' === gettype($v) && !isset($this->rules()[$k])) {
191 1
                throw new \Sensorario\Resources\Exceptions\PropertyWithoutRuleException(
192 1
                    'When property `' . $k . '` is an object class, must be defined in Resources::rules()' .
193 1
                    ' but rules here are equals to ' . var_export($this->rules(), true)
194 1
                    . ' And properties are ' . var_export($this->properties, true)
195
                );
196
            }
197
        }
198 38
    }
199
200 24
    public function ensurePropertyNameIsNotEmpty($propertyName)
201
    {
202 24
        if ('' == $propertyName) {
203 1
            throw new \Sensorario\Resources\Exceptions\PropertyNameEmptyException(
204 1
                'Oops! Property name requested is empty string!!'
205
            );
206
        }
207 23
    }
208
}
209