Test Setup Failed
Push — master ( 6aceb7...0de6fd )
by Mathieu
07:35
created

DateTimeProperty::validationMethods()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 5
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 3
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
     * AbstractProperty > set_multiple()
48
     *
49
     * Ensure multiple can not be true for DateTime property.
50
     *
51
     * @param boolean $multiple Multiple flag.
52
     * @throws InvalidArgumentException If the multiple argument is true (must be false).
53
     * @return self
54
     */
55
    public function setMultiple($multiple)
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
     * AbstractProperty > multiple()
68
     *
69
     * Multiple is always false for Date property.
70
     *
71
     * @return boolean
72
     */
73
    public function multiple()
74
    {
75
        return false;
76
    }
77
78
    /**
79
     * AbstractProperty > setVal(). Ensure `DateTime` object in val.
80
     *
81
     * @param string|DateTimeInterface $val The value to set.
82
     * @return DateTimeInterface|null
83
     */
84
    public function parseOne($val)
85
    {
86
        return $this->dateTimeVal($val);
87
    }
88
89
    /**
90
     * AbstractProperty > inputVal(). Convert `DateTime` to input-friendly string.
91
     *
92
     * @param  mixed $val The value to to convert for input.
93
     * @param  array $options Unused, optional options.
94
     * @throws Exception If the date/time is invalid.
95
     * @return string|null
96
     */
97
    public function inputVal($val. array $options=[])
0 ignored issues
show
Bug introduced by
This code did not parse for me. Apparently, there is an error somewhere around this line:

Syntax error, unexpected '.', expecting ')'
Loading history...
98
    {
99
        $val = $this->dateTimeVal($val);
100
101
        if ($val instanceof DateTimeInterface) {
102
            return $val->format('Y-m-d H:i:s');
103
        } elseif (is_string($val)) {
104
            return $val;
105
        } else {
106
            return '';
107
        }
108
    }
109
110
    /**
111
     * AbstractProperty > storageVal(). Convert `DateTime` to SQL-friendly string.
112
     *
113
     * @param string|DateTime $val Optional. Value to convert to storage format.
114
     * @throws Exception If the date/time is invalid.
115
     * @return string|null
116
     */
117
    public function storageVal($val)
118
    {
119
        $val = $this->dateTimeVal($val);
120
121
        if ($val instanceof DateTimeInterface) {
122
            return $val->format('Y-m-d H:i:s');
123
        } else {
124
            if ($this->allowNull()) {
125
                return null;
126
            } else {
127
                throw new Exception(
128
                    'Invalid date/time value. Must be a DateTimeInterface instance.'
129
                );
130
            }
131
        }
132
    }
133
134
    /**
135
     * Format `DateTime` to string.
136
     *
137
     * > Warning: Passing a value as a parameter sets this value in the objects (calls setVal())
138
     *
139
     * @param  mixed $val     The value to to convert for display.
140
     * @param  array $options Optional display options.
141
     * @return string
142
     */
143
    public function displayVal($val, array $options = [])
144
    {
145
        $val = $this->dateTimeVal($val);
146
        if ($val === null || (is_string($val) && $val === '')) {
147
            return '';
148
        }
149
150
        if (isset($options['format'])) {
151
            $format = $options['format'];
152
        } else {
153
            $format = $this->format();
154
        }
155
156
        return $val->format($format);
157
    }
158
159
    /**
160
     * @param string|DateTime|null $min The minimum allowed value.
161
     * @throws InvalidArgumentException If the date/time is invalid.
162
     * @return self
163
     */
164
    public function setMin($min)
165
    {
166
        if ($min === null) {
167
            $this->min = null;
168
            return $this;
169
        }
170
        if (is_string($min)) {
171
            try {
172
                $min = new DateTime($min);
173
            } catch (Exception $e) {
174
                throw new InvalidArgumentException(
175
                    'Can not set min: '.$e->getMessage()
176
                );
177
            }
178
        }
179
        if (!($min instanceof DateTimeInterface)) {
180
            throw new InvalidArgumentException(
181
                'Invalid min'
182
            );
183
        }
184
        $this->min = $min;
185
        return $this;
186
    }
187
188
    /**
189
     * @return DateTimeInterface|null
190
     */
191
    public function min()
192
    {
193
        return $this->min;
194
    }
195
196
    /**
197
     * @param string|DateTime|null $max The maximum allowed value.
198
     * @throws InvalidArgumentException If the date/time is invalid.
199
     * @return self
200
     */
201
    public function setMax($max)
202
    {
203
        if ($max === null) {
204
            $this->max = null;
205
            return $this;
206
        }
207
        if (is_string($max)) {
208
            try {
209
                $max = new DateTime($max);
210
            } catch (Exception $e) {
211
                throw new InvalidArgumentException(
212
                    'Can not set min: '.$e->getMessage()
213
                );
214
            }
215
        }
216
        if (!($max instanceof DateTimeInterface)) {
217
            throw new InvalidArgumentException(
218
                'Invalid max'
219
            );
220
        }
221
        $this->max = $max;
222
        return $this;
223
    }
224
225
    /**
226
     * @return DateTimeInterface|null
227
     */
228
    public function max()
229
    {
230
        return $this->max;
231
    }
232
233
    /**
234
     * @param string|null $format The date format.
235
     * @throws InvalidArgumentException If the format is not a string.
236
     * @return DateTimeProperty Chainable
237
     */
238
    public function setFormat($format)
239
    {
240
        if ($format === null) {
241
            $format = '';
242
        }
243
        if (!is_string($format)) {
244
            throw new InvalidArgumentException(
245
                'Format must be a string'
246
            );
247
        }
248
        $this->format = $format;
249
        return $this;
250
    }
251
252
    /**
253
     * @return string
254
     */
255
    public function format()
256
    {
257
        if ($this->format === null) {
258
            $this->format = self::DEFAULT_FORMAT;
259
        }
260
        return $this->format;
261
    }
262
263
    /**
264
     * @return array
265
     */
266
    public function validationMethods()
267
    {
268
        $parent_methods = parent::validationMethods();
269
        return array_merge($parent_methods, ['min', 'max']);
270
    }
271
272
    /**
273
     * @return boolean
274
     */
275
    public function validateMin()
276
    {
277
        $min = $this->min();
278
        if (!$min) {
279
            return true;
280
        }
281
        $valid = ($this->val() >= $min);
282
        if ($valid === false) {
283
            $this->validator()->error('The date is smaller than the minimum value', 'min');
284
        }
285
        return $valid;
286
    }
287
288
    /**
289
     * @return boolean
290
     */
291
    public function validateMax()
292
    {
293
        $max = $this->max();
294
        if (!$max) {
295
            return true;
296
        }
297
        $valid = ($this->val() <= $max);
298
        if ($valid === false) {
299
            $this->validator()->error('The date is bigger than the maximum value', 'max');
300
        }
301
        return $valid;
302
    }
303
304
    /**
305
     * @return string
306
     */
307
    public function sqlExtra()
308
    {
309
        return '';
310
    }
311
312
    /**
313
     * @return string
314
     */
315
    public function sqlType()
316
    {
317
        return 'DATETIME';
318
    }
319
320
    /**
321
     * @return integer
322
     */
323
    public function sqlPdoType()
324
    {
325
        return PDO::PARAM_STR;
326
    }
327
328
    /**
329
     * @param mixed $val Value to convert to DateTime.
330
     * @throws InvalidArgumentException If the value is not a valid datetime.
331
     * @return DateTimeInterface|null
332
     */
333
    private function dateTimeVal($val)
334
    {
335
        if ($val === null ||
336
            (is_string($val) && ! strlen(trim($val))) ||
337
            (is_array($val) && ! count(array_filter($val, 'strlen')))
338
        ) {
339
            return null;
340
        }
341
342
        if (is_string($val)) {
343
            $val = new DateTime($val);
344
        }
345
346
        if (!($val instanceof DateTimeInterface)) {
347
            throw new InvalidArgumentException(
348
                'Val must be a valid date'
349
            );
350
        }
351
352
        return $val;
353
    }
354
}
355