Completed
Pull Request — master (#2)
by René
04:40 queued 02:14
created

EntityProperty::validateValue()   D

Complexity

Conditions 26
Paths 24

Size

Total Lines 95
Code Lines 47

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 46
CRAP Score 26.0065

Importance

Changes 0
Metric Value
dl 0
loc 95
ccs 46
cts 47
cp 0.9787
rs 4.5382
c 0
b 0
f 0
cc 26
eloc 47
nc 24
nop 1
crap 26.0065

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
declare(strict_types = 1);
3
4
namespace Zortje\MVC\Model\Table\Entity;
5
6
use Ramsey\Uuid\Uuid;
7
use Zortje\MVC\Model\Table\Entity\Exception\EntityPropertyTypeNonexistentException;
8
use Zortje\MVC\Model\Table\Entity\Exception\EntityPropertyTypeNotImplementedException;
9
use Zortje\MVC\Model\Table\Entity\Exception\EntityPropertyValueExceedingLengthException;
10
use Zortje\MVC\Model\Table\Entity\Exception\InvalidENUMValueForEntityPropertyException;
11
use Zortje\MVC\Model\Table\Entity\Exception\InvalidUUIDValueForEntityPropertyException;
12
use Zortje\MVC\Model\Table\Entity\Exception\InvalidValueTypeForEntityPropertyException;
13
14
/**
15
 * Class EntityProperty
16
 *
17
 * @package Zortje\MVC\Model\Table\Entity
18
 */
19
class EntityProperty
20
{
21
22
    const STRING = 'string';
23
    const INTEGER = 'integer';
24
    const FLOAT = 'float';
25
    const DOUBLE = 'double';
26
    const BOOL = 'bool';
27
28
    const DATE = 'date';
29
    const DATETIME = 'datetime';
30
31
    const VARBINARY = 'varbinary';
32
33
    const UUID = 'uuid';
34
35
    const ENUM = 'enum';
36
37
    /**
38
     * @var string Entity property type
39
     */
40
    protected $type;
41
42
    /**
43
     * @var int Entity property max length
44
     */
45
    protected $length;
46
47
    /**
48
     * @var array Allowed values
49
     */
50
    protected $values;
51
52
    /**
53
     * @param string|array $type
54
     */
55 13
    public function __construct($type)
56
    {
57 13
        if (is_array($type)) {
58
            /**
59
             * Type
60
             */
61 3
            if (!isset($type['type'])) {
62 1
                throw new \InvalidArgumentException('Index "type" not found in parameter array');
63
            }
64
65 2
            $this->setType($type['type']);
66
67
            /**
68
             * Length
69
             */
70 2
            if (isset($type['length']) && is_numeric($type['length'])) {
71 1
                $this->length = (int)$type['length'];
72
            }
73
74
            /**
75
             * Values
76
             */
77 2
            if (isset($type['values']) && is_array($type['values'])) {
78 2
                $this->values = array_fill_keys($type['values'], true);
79
            }
80
        } else {
81 10
            $this->setType($type);
82
        }
83 12
    }
84
85
    /**
86
     * Set entity property type
87
     *
88
     * @param string $type
89
     *
90
     * @throws EntityPropertyTypeNonexistentException
91
     */
92 13
    protected function setType(string $type)
93
    {
94 13
        if (!defined(EntityProperty::class . '::' . strtoupper($type))) {
0 ignored issues
show
Coding Style introduced by
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
95 1
            throw new EntityPropertyTypeNonexistentException([$type]);
96
        }
97
98 12
        $this->type = $type;
99 12
    }
100
101
    /**
102
     * Validate value for entity property
103
     *
104
     * @param mixed $value Entity property value
105
     *
106
     * @return bool TRUE if valid, otherwise FALSE
107
     *
108
     * @throws EntityPropertyTypeNotImplementedException If entity property type is not implemented
109
     * @throws EntityPropertyValueExceedingLengthException If value is exceeding allowed length for entity property
110
     * @throws InvalidENUMValueForEntityPropertyException If ENUM value is invalid for entity property
111
     * @throws InvalidUUIDValueForEntityPropertyException If UUID value is invalid for entity property
112
     * @throws InvalidValueTypeForEntityPropertyException If value is invalid for entity property
113
     */
114 22
    public function validateValue($value): bool
115
    {
116 22
        if (is_null($value)) {
117 1
            return true;
118
        }
119
120 21
        switch ($this->type) {
121 21
            case self::STRING:
122 3
                if (!is_string($value)) {
123 1
                    throw new InvalidValueTypeForEntityPropertyException([$this->type, gettype($value)]);
124
                }
125
126
                /**
127
                 * Check length
128
                 */
129 2
                $length = strlen($value);
130
131 2
                if (!is_null($this->length) && $length > $this->length) {
132 1
                    throw new EntityPropertyValueExceedingLengthException([$value, $this->length]);
133
                }
134
135 1
                break;
136
137 18
            case self::INTEGER:
138 2
                if (!is_int($value)) {
139 1
                    throw new InvalidValueTypeForEntityPropertyException([$this->type, gettype($value)]);
140
                }
141
142 1
                break;
143
144 16
            case self::FLOAT:
145 2
                if (!is_float($value)) {
146 1
                    throw new InvalidValueTypeForEntityPropertyException([$this->type, gettype($value)]);
147
                }
148
149 1
                break;
150
151 14
            case self::DOUBLE:
152 2
                if (!is_double($value)) {
153 1
                    throw new InvalidValueTypeForEntityPropertyException([$this->type, gettype($value)]);
154
                }
155
156 1
                break;
157
158 12
            case self::BOOL:
159 2
                if (!is_bool($value)) {
160 1
                    throw new InvalidValueTypeForEntityPropertyException([$this->type, gettype($value)]);
161
                }
162
163 1
                break;
164
165 10
            case self::DATE:
166 8
            case self::DATETIME:
167 4
                if (!is_object($value) || (is_object($value) && get_class($value) !== \DateTime::class)) {
168 2
                    throw new InvalidValueTypeForEntityPropertyException([$this->type, gettype($value)]);
169
                }
170
171 2
                break;
172
173 6
            case self::VARBINARY:
174
                // @todo Implement this
175
176
                break;
177
178 6
            case self::UUID:
179 3
                if (!is_string($value)) {
180 1
                    throw new InvalidValueTypeForEntityPropertyException(['string', gettype($value)]);
181
                }
182
183
                /**
184
                 * Check UUID
185
                 */
186 2
                if (!Uuid::isValid($value)) {
187 1
                    throw new InvalidUUIDValueForEntityPropertyException([$value]);
188
                }
189
190 1
                break;
191
192 3
            case self::ENUM:
193 3
                if (!is_string($value)) {
194 1
                    throw new InvalidValueTypeForEntityPropertyException(['string', gettype($value)]);
195
                }
196
197
                /**
198
                 * Check values
199
                 */
200 2
                if (!isset($this->values[$value])) {
201 1
                    throw new InvalidENUMValueForEntityPropertyException([$value]);
202
                }
203
204 1
                break;
205
        }
206
207 9
        return true;
208
    }
209
210
    /**
211
     * Format value according to entity property type
212
     *
213
     * @param mixed $value Value
214
     *
215
     * @return mixed Value
216
     *
217
     * @throws EntityPropertyTypeNotImplementedException If entity property type is not implemented
218
     */
219 7
    public function formatValueForEntity($value)
220
    {
221 7
        if (is_null($value)) {
222 1
            return null;
223
        }
224
225 6
        switch ($this->type) {
226 6
            case self::STRING:
227 5
            case self::UUID:
228 5
            case self::ENUM:
229 1
                $value = "$value";
230 1
                break;
231
232 5
            case self::INTEGER:
233 1
                $value = (int)$value;
234 1
                break;
235
236 4
            case self::FLOAT:
237 3
            case self::DOUBLE:
238 1
                $value = (float)$value;
239 1
                break;
240
241 3
            case self::DATE:
242 2
            case self::DATETIME:
243 2
                $value = new \DateTime($value);
244 2
                break;
245
246 1
            case self::VARBINARY:
247
                // @todo Implement this
248
249
                break;
250
251 1
            case self::BOOL:
252 1
                $value = $value === '1';
253 1
                break;
254
        }
255
256 6
        return $value;
257
    }
258
259
    /**
260
     * Format value for insertion into the database
261
     *
262
     * @param mixed $value Value
263
     *
264
     * @return mixed Value
265
     */
266 3
    public function formatValueForDatabase($value)
267
    {
268 3
        switch ($this->type) {
269 3
            case self::DATE:
270
                /**
271
                 * @var \DateTime $value
272
                 */
273 1
                $value = $value->format('Y-m-d');
274 1
                break;
275
276 2
            case self::DATETIME:
277
                /**
278
                 * @var \DateTime $value
279
                 */
280 1
                $value = $value->format('Y-m-d H:i:s');
281 1
                break;
282
283 1
            case self::BOOL:
284 1
                $value = $value ? '1' : '0';
285 1
                break;
286
        }
287
288 3
        return $value;
289
    }
290
}
291