Test Failed
Pull Request — master (#147)
by Simone
01:55
created

MagicResource::ensurePropertyNameIsNotEmpty()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2.2559

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 8
ccs 3
cts 5
cp 0.6
rs 9.4285
cc 2
eloc 4
nc 2
nop 1
crap 2.2559
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
    public function __call($functionName, $arguments)
33
    {
34
        $propertyName = strtolower($functionName);
35
36
        if ($this->hasProperty($propertyName)) {
37
            return $this->get($propertyName);
38
        }
39
40
        if (isset($this->defaults()[$propertyName])) {
41
            return $this->defaults()[$propertyName];
42
        }
43
44
        throw new \Sensorario\Resources\Exceptions\UndefinedMethodException(
45
            'Method `' . get_class($this)
46
            . '::' . $functionName 
47
            . '()` is not yet implemented'
48
        );
49
    }
50
51
    abstract public function applyConfiguration(Configurator $configurator);
52
53 18
    public function __construct(
54
        array $properties,
55
        ResourcesValidator $validator,
56
        Configurator $configuration = null
57
    ) {
58 18
        $this->properties    = $properties;
59 18
        $this->validator     = $validator;
60 18
        $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 18
        if ($configuration) {
63
            $this->applyConfiguration(
64
                $configuration
65
            );
66
        }
67
68 18
        $this->init();
69 12
    }
70
71 18
    private function init()
72
    {
73 18
        $this->ensurePropertiesConsistency();
74 17
        $this->validate();
75 12
    }
76
77 18
    public static function __callStatic($methodName, array $args)
78
    {
79 18
        $isMethodAllowed = in_array(
80 18
            $methodName,
81 18
            self::$methodWhiteList
82
        );
83
84 18
        $configuration = null;
85
86
        if (
87 18
            isset($args[1])
88 1
            && 'Sensorario\Resources\Configurator' == get_class($args[1])
89
        ) {
90
            $configuration = new Configurator(
91
                $args[1]->resourceName(),
92
                $args[1]->container()
93
            );
94
        }
95
96 18
        if ($isMethodAllowed) {
97 17
            return new static(
98 17
                $args[0] ?? [],
99 17
                new ResourcesValidator(),
100 17
                $configuration
101
            );
102
        }
103
104 1
        throw new \Sensorario\Resources\Exceptions\FactoryMethodException(
105
            'Invalid factory method '
106 1
            . '`' . $methodName . '`'
107
        );
108
    }
109
110 15
    final public function hasProperty($propertyName)
111
    {
112
        return isset(
113 15
            $this->properties[$propertyName]
114
        );
115
    }
116
117
    final public function set($propertyName, $propertValue) 
118
    {
119
        $this->properties[$propertyName] = $propertValue;
120
    }
121
122 13
    final public function get($propertyName)
123
    {
124 13
        $this->ensurePropertyNameIsNotEmpty($propertyName);
125
126 13
        if ($this->hasNotProperty($propertyName)) {
127 2
            if ($prop = $this->defaults()[$propertyName] ?? false) {
128 1
                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 11
        return $this->properties[$propertyName];
139
    }
140
141 14
    final public function hasNotProperty($propertyName)
142
    {
143 14
        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 17
    final public function properties()
158
    {
159 17
        $properties = $this->properties;
160
161 17
        foreach ($properties as $k => $v) {
162 13
            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 16
        return $properties;
180
    }
181
182 17
    public function validate()
183
    {
184 17
        $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 12
    }
186
187 18
    public function ensurePropertiesConsistency()
188
    {
189 18
        foreach ($this->properties as $k => $v) {
190 14
            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 17
    }
199
200 13
    public function ensurePropertyNameIsNotEmpty($propertyName)
201
    {
202 13
        if ('' == $propertyName) {
203
            throw new \Sensorario\Resources\Exceptions\PropertyNameEmptyException(
204
                'Oops! Property name requested is empty string!!'
205
            );
206
        }
207 13
    }
208
}
209