Test Setup Failed
Push — master ( 6592af...c06444 )
by Chauncey
08:19
created

DateTimeProperty::getMin()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
namespace Charcoal\Property;
4
5
use PDO;
6
use DateTime;
7
use DateTimeInterface;
8
use Exception;
9
use InvalidArgumentException;
10
11
// From 'charcoal-property'
12
use Charcoal\Property\AbstractProperty;
13
14
/**
15
 * Date/Time Property
16
 */
17
class DateTimeProperty extends AbstractProperty
18
{
19
    const DEFAULT_MIN = null;
20
    const DEFAULT_MAX = null;
21
    const DEFAULT_FORMAT = 'Y-m-d H:i:s';
22
23
    /**
24
     * @var DateTimeInterface|null
25
     */
26
    private $min = self::DEFAULT_MIN;
27
28
    /**
29
     * @var DateTimeInterface|null
30
     */
31
    private $max = self::DEFAULT_MAX;
32
33
    /**
34
     * @var string
35
     */
36
    private $format = self::DEFAULT_FORMAT;
37
38
    /**
39
     * @return string
40
     */
41
    public function type()
42
    {
43
        return 'date-time';
44
    }
45
46
    /**
47
     * Ensure multiple can not be true for DateTime property.
48
     *
49
     * @see AbstractProperty::setMultiple()
50
     *
51
     * @param  boolean $multiple Multiple flag.
52
     * @throws InvalidArgumentException If the multiple argument is true (must be false).
53
     * @return self
54
     */
55 View Code Duplication
    public function setMultiple($multiple)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
56
    {
57
        $multiple = !!$multiple;
58
        if ($multiple === true) {
59
            throw new InvalidArgumentException(
60
                'Multiple can not be TRUE for date/time property.'
61
            );
62
        }
63
        return $this;
64
    }
65
66
    /**
67
     * Multiple is always false for DateTime property.
68
     *
69
     * @see AbstractProperty::getMultiple()
70
     *
71
     * @return boolean
72
     */
73
    public function getMultiple()
74
    {
75
        return false;
76
    }
77
78
    /**
79
     * Ensure `DateTime` object in val.
80
     *
81
     * @see AbstractProperty::parseOne()
82
     * @see AbstractProperty::parseVal()
83
     *
84
     * @param  string|DateTimeInterface $val The value to set.
85
     * @return DateTimeInterface|null
86
     */
87
    public function parseOne($val)
88
    {
89
        return $this->dateTimeVal($val);
90
    }
91
92
    /**
93
     * Convert `DateTime` to input-friendly string.
94
     *
95
     * @see AbstractProperty::inputVal()
96
     *
97
     * @param  mixed $val     The value to to convert for input.
98
     * @param  array $options Unused, optional options.
99
     * @throws Exception If the date/time is invalid.
100
     * @return string|null
101
     */
102
    public function inputVal($val, array $options = [])
103
    {
104
        unset($options);
105
        $val = $this->dateTimeVal($val);
106
107
        if ($val instanceof DateTimeInterface) {
108
            return $val->format('Y-m-d H:i:s');
109
        } else {
110
            return '';
111
        }
112
    }
113
114
    /**
115
     * Convert `DateTime` to SQL-friendly string.
116
     *
117
     * @see StorablePropertyTrait::storageVal()
118
     *
119
     * @param  string|DateTime $val Optional. Value to convert to storage format.
120
     * @throws Exception If the date/time is invalid.
121
     * @return string|null
122
     */
123
    public function storageVal($val)
124
    {
125
        $val = $this->dateTimeVal($val);
126
127
        if ($val instanceof DateTimeInterface) {
128
            return $val->format('Y-m-d H:i:s');
129
        }
130
131
        if ($this['allowNull']) {
132
            return null;
133
        }
134
135
        throw new Exception(
136
            'Invalid date/time value. Must be a DateTimeInterface instance.'
137
        );
138
    }
139
140
    /**
141
     * Format a date/time object to string.
142
     *
143
     * @see AbstractProperty::displayVal()
144
     *
145
     * @param  mixed $val     The value to to convert for display.
146
     * @param  array $options Optional display options.
147
     * @return string
148
     */
149
    public function displayVal($val, array $options = [])
150
    {
151
        $val = $this->dateTimeVal($val);
152
        if ($val === null) {
153
            return '';
154
        }
155
156
        if (isset($options['format'])) {
157
            $format = $options['format'];
158
        } else {
159
            $format = $this->getFormat();
160
        }
161
162
        return $val->format($format);
163
    }
164
165
    /**
166
     * @param  string|DateTime|null $min The minimum allowed value.
167
     * @throws InvalidArgumentException If the date/time is invalid.
168
     * @return self
169
     */
170 View Code Duplication
    public function setMin($min)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
171
    {
172
        if ($min === null) {
173
            $this->min = null;
174
            return $this;
175
        }
176
177
        if (is_string($min)) {
178
            try {
179
                $min = new DateTime($min);
180
            } catch (Exception $e) {
181
                throw new InvalidArgumentException(
182
                    'Can not set min: '.$e->getMessage()
183
                );
184
            }
185
        }
186
187
        if (!($min instanceof DateTimeInterface)) {
188
            throw new InvalidArgumentException(
189
                'Invalid min'
190
            );
191
        }
192
193
        $this->min = $min;
194
        return $this;
195
    }
196
197
    /**
198
     * @return DateTimeInterface|null
199
     */
200
    public function getMin()
201
    {
202
        return $this->min;
203
    }
204
205
    /**
206
     * @param  string|DateTime|null $max The maximum allowed value.
207
     * @throws InvalidArgumentException If the date/time is invalid.
208
     * @return self
209
     */
210 View Code Duplication
    public function setMax($max)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
211
    {
212
        if ($max === null) {
213
            $this->max = null;
214
            return $this;
215
        }
216
217
        if (is_string($max)) {
218
            try {
219
                $max = new DateTime($max);
220
            } catch (Exception $e) {
221
                throw new InvalidArgumentException(
222
                    'Can not set min: '.$e->getMessage()
223
                );
224
            }
225
        }
226
227
        if (!($max instanceof DateTimeInterface)) {
228
            throw new InvalidArgumentException(
229
                'Invalid max'
230
            );
231
        }
232
233
        $this->max = $max;
234
        return $this;
235
    }
236
237
    /**
238
     * @return DateTimeInterface|null
239
     */
240
    public function getMax()
241
    {
242
        return $this->max;
243
    }
244
245
    /**
246
     * @param  string|null $format The date format.
247
     * @throws InvalidArgumentException If the format is not a string.
248
     * @return DateTimeProperty Chainable
249
     */
250 View Code Duplication
    public function setFormat($format)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
251
    {
252
        if ($format === null) {
253
            $format = '';
254
        }
255
        if (!is_string($format)) {
256
            throw new InvalidArgumentException(
257
                'Format must be a string'
258
            );
259
        }
260
        $this->format = $format;
261
        return $this;
262
    }
263
264
    /**
265
     * @return string
266
     */
267
    public function getFormat()
268
    {
269
        return $this->format;
270
    }
271
272
    /**
273
     * @return array
274
     */
275
    public function validationMethods()
276
    {
277
        $parentMethods = parent::validationMethods();
278
279
        return array_merge($parentMethods, [
280
            'min',
281
            'max',
282
        ]);
283
    }
284
285
    /**
286
     * @return boolean
287
     */
288 View Code Duplication
    public function validateMin()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
289
    {
290
        $min = $this->getMin();
291
        if (!$min) {
292
            return true;
293
        }
294
        $valid = ($this->val() >= $min);
0 ignored issues
show
Deprecated Code introduced by
The method Charcoal\Property\AbstractProperty::val() has been deprecated.

This method has been deprecated.

Loading history...
295
        if ($valid === false) {
296
            $this->validator()->error('The date is smaller than the minimum value', 'min');
0 ignored issues
show
Unused Code introduced by
The call to ValidatorInterface::error() has too many arguments starting with 'min'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
297
        }
298
        return $valid;
299
    }
300
301
    /**
302
     * @return boolean
303
     */
304 View Code Duplication
    public function validateMax()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
305
    {
306
        $max = $this->getMax();
307
        if (!$max) {
308
            return true;
309
        }
310
        $valid = ($this->val() <= $max);
0 ignored issues
show
Deprecated Code introduced by
The method Charcoal\Property\AbstractProperty::val() has been deprecated.

This method has been deprecated.

Loading history...
311
        if ($valid === false) {
312
            $this->validator()->error('The date is bigger than the maximum value', 'max');
0 ignored issues
show
Unused Code introduced by
The call to ValidatorInterface::error() has too many arguments starting with 'max'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
313
        }
314
        return $valid;
315
    }
316
317
    /**
318
     * @see StorablePropertyTrait::sqlType()
319
     * @return string
320
     */
321
    public function sqlType()
322
    {
323
        return 'DATETIME';
324
    }
325
326
    /**
327
     * @see StorablePropertyTrait::sqlPdoType()
328
     * @return integer
329
     */
330
    public function sqlPdoType()
331
    {
332
        return PDO::PARAM_STR;
333
    }
334
335
    /**
336
     * @param  mixed $val Value to convert to DateTime.
337
     * @throws InvalidArgumentException If the value is not a valid datetime.
338
     * @return DateTimeInterface|null
339
     */
340
    private function dateTimeVal($val)
341
    {
342
        if ($val === null ||
343
            (is_string($val) && ! strlen(trim($val))) ||
344
            (is_array($val) && ! count(array_filter($val, 'strlen')))
345
        ) {
346
            return null;
347
        }
348
349
        if (is_int($val) && $this->isValidTimeStamp($val)) {
350
            $dateTime = new DateTime();
351
            $val = $dateTime->setTimestamp($val);
352
        }
353
354
        if (is_string($val)) {
355
            $val = new DateTime($val);
356
        }
357
358
        if (!($val instanceof DateTimeInterface)) {
359
            throw new InvalidArgumentException(
360
                'Val must be a valid date'
361
            );
362
        }
363
364
        return $val;
365
    }
366
367
    /**
368
     * @param  integer|string $timestamp Timestamp.
369
     * @return boolean
370
     */
371
    private function isValidTimeStamp($timestamp)
372
    {
373
        return (is_int($timestamp))
374
            && ($timestamp <= PHP_INT_MAX)
375
            && ($timestamp >= ~PHP_INT_MAX);
376
    }
377
}
378