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

EntityProperty::__construct()   C

Complexity

Conditions 7
Paths 6

Size

Total Lines 29
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 7

Importance

Changes 0
Metric Value
dl 0
loc 29
ccs 11
cts 11
cp 1
rs 6.7272
c 0
b 0
f 0
cc 7
eloc 11
nc 6
nop 1
crap 7
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\InvalidIPAddressValueForEntityPropertyException;
12
use Zortje\MVC\Model\Table\Entity\Exception\InvalidUUIDValueForEntityPropertyException;
13
use Zortje\MVC\Model\Table\Entity\Exception\InvalidValueTypeForEntityPropertyException;
14
15
/**
16
 * Class EntityProperty
17
 *
18
 * @package Zortje\MVC\Model\Table\Entity
19
 */
20
class EntityProperty
21
{
22
23
    const STRING = 'string';
24
    const INTEGER = 'integer';
25
    const FLOAT = 'float';
26
    const DOUBLE = 'double';
27
    const BOOL = 'bool';
28
29
    const DATE = 'date';
30
    const DATETIME = 'datetime';
31
32
    const IPADDRESS = 'ipaddress';
33
34
    const UUID = 'uuid';
35
36
    const ENUM = 'enum';
37
38
    /**
39
     * @var string Entity property type
40
     */
41
    protected $type;
42
43
    /**
44
     * @var int Entity property max length
45
     */
46
    protected $length;
47
48
    /**
49
     * @var array Allowed values
50
     */
51
    protected $values;
52
53
    /**
54
     * @param string|array $type
55
     */
56 13
    public function __construct($type)
57
    {
58 13
        if (is_array($type)) {
59
            /**
60
             * Type
61
             */
62 3
            if (!isset($type['type'])) {
63 1
                throw new \InvalidArgumentException('Index "type" not found in parameter array');
64
            }
65
66 2
            $this->setType($type['type']);
67
68
            /**
69
             * Length
70
             */
71 2
            if (isset($type['length']) && is_numeric($type['length'])) {
72 1
                $this->length = (int)$type['length'];
73
            }
74
75
            /**
76
             * Values
77
             */
78 2
            if (isset($type['values']) && is_array($type['values'])) {
79 2
                $this->values = array_fill_keys($type['values'], true);
80
            }
81
        } else {
82 10
            $this->setType($type);
83
        }
84 12
    }
85
86
    /**
87
     * Set entity property type
88
     *
89
     * @param string $type
90
     *
91
     * @throws EntityPropertyTypeNonexistentException
92
     */
93 13
    protected function setType(string $type)
94
    {
95 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...
96 1
            throw new EntityPropertyTypeNonexistentException([$type]);
97
        }
98
99 12
        $this->type = $type;
100 12
    }
101
102
    /**
103
     * Validate value for entity property
104
     *
105
     * @param mixed $value Entity property value
106
     *
107
     * @return bool TRUE if valid, otherwise FALSE
108
     *
109
     * @throws EntityPropertyTypeNotImplementedException If entity property type is not implemented
110
     * @throws EntityPropertyValueExceedingLengthException If value is exceeding allowed length for entity property
111
     * @throws InvalidENUMValueForEntityPropertyException If ENUM value is invalid for entity property
112
     * @throws InvalidUUIDValueForEntityPropertyException If UUID value is invalid for entity property
113
     * @throws InvalidValueTypeForEntityPropertyException If value is invalid for entity property
114
     * @throws InvalidIPAddressValueForEntityPropertyException If IP address value is invalid
115
     */
116 24
    public function validateValue($value): bool
117
    {
118 24
        if (is_null($value)) {
119 1
            return true;
120
        }
121
122 23
        switch ($this->type) {
123 23
            case self::STRING:
124 3
                if (!is_string($value)) {
125 1
                    throw new InvalidValueTypeForEntityPropertyException([$this->type, gettype($value)]);
126
                }
127
128
                /**
129
                 * Check length
130
                 */
131 2
                $length = strlen($value);
132
133 2
                if (!is_null($this->length) && $length > $this->length) {
134 1
                    throw new EntityPropertyValueExceedingLengthException([$value, $this->length]);
135
                }
136
137 1
                break;
138
139 20
            case self::INTEGER:
140 2
                if (!is_int($value)) {
141 1
                    throw new InvalidValueTypeForEntityPropertyException([$this->type, gettype($value)]);
142
                }
143
144 1
                break;
145
146 18
            case self::FLOAT:
147 2
                if (!is_float($value)) {
148 1
                    throw new InvalidValueTypeForEntityPropertyException([$this->type, gettype($value)]);
149
                }
150
151 1
                break;
152
153 16
            case self::DOUBLE:
154 2
                if (!is_double($value)) {
155 1
                    throw new InvalidValueTypeForEntityPropertyException([$this->type, gettype($value)]);
156
                }
157
158 1
                break;
159
160 14
            case self::BOOL:
161 2
                if (!is_bool($value)) {
162 1
                    throw new InvalidValueTypeForEntityPropertyException([$this->type, gettype($value)]);
163
                }
164
165 1
                break;
166
167 12
            case self::DATE:
168 10
            case self::DATETIME:
169 4
                if (!is_object($value) || (is_object($value) && get_class($value) !== \DateTime::class)) {
170 2
                    throw new InvalidValueTypeForEntityPropertyException([$this->type, gettype($value)]);
171
                }
172
173 2
                break;
174
175 8
            case self::IPADDRESS:
176 2
                if (filter_var($value, FILTER_VALIDATE_IP) === false) {
177 1
                    throw new InvalidIPAddressValueForEntityPropertyException([$value]);
178
                }
179
180 1
                break;
181
182 6
            case self::UUID:
183 3
                if (!is_string($value)) {
184 1
                    throw new InvalidValueTypeForEntityPropertyException(['string', gettype($value)]);
185
                }
186
187
                /**
188
                 * Check UUID
189
                 */
190 2
                if (!Uuid::isValid($value)) {
191 1
                    throw new InvalidUUIDValueForEntityPropertyException([$value]);
192
                }
193
194 1
                break;
195
196 3
            case self::ENUM:
197 3
                if (!is_string($value)) {
198 1
                    throw new InvalidValueTypeForEntityPropertyException(['string', gettype($value)]);
199
                }
200
201
                /**
202
                 * Check values
203
                 */
204 2
                if (!isset($this->values[$value])) {
205 1
                    throw new InvalidENUMValueForEntityPropertyException([$value]);
206
                }
207
208 1
                break;
209
        }
210
211 10
        return true;
212
    }
213
214
    /**
215
     * Format value according to entity property type
216
     *
217
     * @param mixed $value Value
218
     *
219
     * @return mixed Value
220
     *
221
     * @throws EntityPropertyTypeNotImplementedException If entity property type is not implemented
222
     */
223 8
    public function formatValueForEntity($value)
224
    {
225 8
        if (is_null($value)) {
226 1
            return null;
227
        }
228
229 7
        switch ($this->type) {
230 7
            case self::STRING:
231 6
            case self::UUID:
232 6
            case self::ENUM:
233 1
                $value = "$value";
234 1
                break;
235
236 6
            case self::INTEGER:
237 1
                $value = (int)$value;
238 1
                break;
239
240 5
            case self::FLOAT:
241 4
            case self::DOUBLE:
242 1
                $value = (float)$value;
243 1
                break;
244
245 4
            case self::DATE:
246 3
            case self::DATETIME:
247 2
                $value = new \DateTime($value);
248 2
                break;
249
250 2
            case self::IPADDRESS:
251 1
                $value = inet_ntop($value);
252 1
                break;
253
254 1
            case self::BOOL:
255 1
                $value = $value === '1';
256 1
                break;
257
        }
258
259 7
        return $value;
260
    }
261
262
    /**
263
     * Format value for insertion into the database
264
     *
265
     * @param mixed $value Value
266
     *
267
     * @return mixed Value
268
     */
269 4
    public function formatValueForDatabase($value)
270
    {
271 4
        switch ($this->type) {
272 4
            case self::DATE:
273
                /**
274
                 * @var \DateTime $value
275
                 */
276 1
                $value = $value->format('Y-m-d');
277 1
                break;
278
279 3
            case self::DATETIME:
280
                /**
281
                 * @var \DateTime $value
282
                 */
283 1
                $value = $value->format('Y-m-d H:i:s');
284 1
                break;
285
286 2
            case self::BOOL:
287 1
                $value = $value ? '1' : '0';
288 1
                break;
289
290 1
            case self::IPADDRESS:
291 1
                $value = inet_pton($value);
292 1
                break;
293
        }
294
295 4
        return $value;
296
    }
297
}
298