GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

FieldDate   F
last analyzed

Complexity

Total Complexity 122

Size/Duplication

Total Lines 801
Duplicated Lines 0 %

Importance

Changes 8
Bugs 0 Features 0
Metric Value
eloc 343
c 8
b 0
f 0
dl 0
loc 801
rs 2
wmc 122

32 Methods

Rating   Name   Duplication   Size   Complexity  
A createTable() 0 4 1
A canPrePopulate() 0 3 1
A isSortable() 0 3 1
A fetchSuggestionTypes() 0 3 1
A findDefaults() 0 4 2
A getParameterPoolValue() 0 3 1
A canFilter() 0 3 1
A allowDatasourceParamOutput() 0 3 1
A allowDatasourceOutputGrouping() 0 3 1
A buildSortingSelectSQL() 0 3 1
A fetchFilterableOperators() 0 47 1
A formatDate() 0 8 2
B buildRangeFilterSQL() 0 34 9
A appendFormattedElement() 0 12 3
A commit() 0 19 6
B processRawFieldData() 0 30 7
B groupRecords() 0 41 8
B parseDate() 0 57 9
B prepareExportValue() 0 28 7
A getExportModes() 0 6 1
A getImportModes() 0 5 1
A buildSortingSQL() 0 15 2
A cleanFilterString() 0 5 1
A checkPostFieldData() 0 19 5
B prepareImportValue() 0 33 9
A __construct() 0 10 1
C parseFilter() 0 83 16
A isEqualTo() 0 13 3
B displayPublishPanel() 0 53 9
B buildDSRetrievalSQL() 0 30 7
A displaySettingsPanel() 0 20 2
A prepareTextValue() 0 9 2

How to fix   Complexity   

Complex Class

Complex classes like FieldDate often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use FieldDate, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * @package toolkit
5
 */
6
7
/**
8
 * A simple Date field that stores a full ISO date. Symphony will attempt
9
 * to localize the date on a per Author basis. The field essentially maps to
10
 * PHP's `strtotime`, so it is very flexible in terms of what an Author can
11
 * input into it.
12
 */
13
class FieldDate extends Field implements ExportableField, ImportableField
14
{
15
    const SIMPLE = 0;
16
    const REGEXP = 1;
17
    const RANGE = 3;
18
    const ERROR = 4;
19
20
    private $key;
21
22
    protected static $min_date = '1000-01-01 00:00:00';
23
    protected static $max_date = '9999-12-31 23:59:59';
24
25
    public function __construct()
26
    {
27
        parent::__construct();
28
        $this->_name = __('Date');
0 ignored issues
show
Bug Best Practice introduced by
The property _name does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
29
        $this->_required = true;
30
        $this->key = 1;
31
32
        $this->set('pre_populate', 'now');
33
        $this->set('required', 'no');
34
        $this->set('location', 'sidebar');
35
    }
36
37
    /*-------------------------------------------------------------------------
38
        Definition:
39
    -------------------------------------------------------------------------*/
40
41
    public function canFilter()
42
    {
43
        return true;
44
    }
45
46
    public function isSortable()
47
    {
48
        return true;
49
    }
50
51
    public function canPrePopulate()
52
    {
53
        return true;
54
    }
55
56
    public function allowDatasourceOutputGrouping()
57
    {
58
        return true;
59
    }
60
61
    public function allowDatasourceParamOutput()
62
    {
63
        return true;
64
    }
65
66
    public function fetchFilterableOperators()
67
    {
68
        return array(
69
            array(
70
                'title' => 'is',
71
                'filter' => ' ',
72
                'help' => __('Find values that are an exact match for the given string.')
73
            ),
74
            array(
75
                'filter' => 'sql: NOT NULL',
76
                'title' => 'is not empty',
77
                'help' => __('Find entries where any value is selected.')
78
            ),
79
            array(
80
                'filter' => 'sql: NULL',
81
                'title' => 'is empty',
82
                'help' => __('Find entries where no value is selected.')
83
            ),
84
            array(
85
                'title' => 'contains',
86
                'filter' => 'regexp: ',
87
                'help' => __('Find values that match the given <a href="%s">MySQL regular expressions</a>.', array(
88
                    'https://dev.mysql.com/doc/mysql/en/regexp.html'
89
                ))
90
            ),
91
            array(
92
                'title' => 'does not contain',
93
                'filter' => 'not-regexp: ',
94
                'help' => __('Find values that do not match the given <a href="%s">MySQL regular expressions</a>.', array(
95
                    'https://dev.mysql.com/doc/mysql/en/regexp.html'
96
                ))
97
            ),
98
            array(
99
                'title' => 'later than',
100
                'filter' => 'later than '
101
            ),
102
            array(
103
                'title' => 'earlier than',
104
                'filter' => 'earlier than '
105
            ),
106
            array(
107
                'title' => 'equal to or later than',
108
                'filter' => 'equal to or later than '
109
            ),
110
            array(
111
                'title' => 'equal to or earlier than',
112
                'filter' => 'equal to or earlier than '
113
            ),
114
        );
115
    }
116
117
    public function fetchSuggestionTypes()
118
    {
119
        return array('date');
120
    }
121
122
    /*-------------------------------------------------------------------------
123
        Setup:
124
    -------------------------------------------------------------------------*/
125
126
    public function createTable()
127
    {
128
        return Symphony::Database()->query(
129
            "CREATE TABLE IF NOT EXISTS `tbl_entries_data_" . $this->get('id') . "` (
0 ignored issues
show
Coding Style Comprehensibility introduced by
The string literal CREATE TABLE IF NOT EXISTS `tbl_entries_data_ does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
Coding Style Comprehensibility introduced by
The string literal ` (\n `id` ...OLLATE=utf8_unicode_ci; does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
Bug introduced by
Are you sure $this->get('id') of type array|mixed|null can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

129
            "CREATE TABLE IF NOT EXISTS `tbl_entries_data_" . /** @scrutinizer ignore-type */ $this->get('id') . "` (
Loading history...
130
              `id` int(11) unsigned NOT null auto_increment,
131
              `entry_id` int(11) unsigned NOT null,
132
              `value` varchar(80) default null,
133
              `date` DATETIME default null,
134
              PRIMARY KEY  (`id`),
135
              UNIQUE KEY `entry_id` (`entry_id`),
136
              KEY `value` (`value`),
137
              KEY `date` (`date`)
138
            ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;"
139
        );
140
    }
141
142
    /*-------------------------------------------------------------------------
143
        Utilities:
144
    -------------------------------------------------------------------------*/
145
146
    /**
147
     * Given a string, this function builds the range of dates that match it.
148
     * The strings should be in ISO8601 style format, or a natural date, such
149
     * as 'last week' etc.
150
     *
151
     * @since Symphony 2.2.2
152
     * @param array $string
153
     *  The date string to be parsed
154
     * @param string $direction
155
     *  Either later or earlier, defaults to null.
156
     * @param boolean $equal_to
157
     *  If the filter is equal_to or not, defaults to false.
158
     * @return array
159
     *  An associative array containing a date in ISO8601 format (or natural)
160
     *  with two keys, start and end.
161
     */
162
    public static function parseDate($string, $direction = null, $equal_to = false)
0 ignored issues
show
Coding Style introduced by
Incorrect spacing between argument "$direction" and equals sign; expected 0 but found 1
Loading history...
Coding Style introduced by
Incorrect spacing between default value and equals sign for argument "$direction"; expected 0 but found 1
Loading history...
Coding Style introduced by
Incorrect spacing between argument "$equal_to" and equals sign; expected 0 but found 1
Loading history...
Coding Style introduced by
Incorrect spacing between default value and equals sign for argument "$equal_to"; expected 0 but found 1
Loading history...
163
    {
164
        $parts = array(
165
            'start' => null,
166
            'end' => null
167
        );
168
169
        // Year
170
        if (preg_match('/^\d{1,4}$/', $string, $matches)) {
0 ignored issues
show
Bug introduced by
$string of type array is incompatible with the type string expected by parameter $subject of preg_match(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

170
        if (preg_match('/^\d{1,4}$/', /** @scrutinizer ignore-type */ $string, $matches)) {
Loading history...
171
            $year = current($matches);
172
173
            $parts['start'] = "$year-01-01 00:00:00";
0 ignored issues
show
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $year instead of interpolation.

It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.

// Instead of
$x = "foo $bar $baz";

// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
Loading history...
174
            $parts['end'] = "$year-12-31 23:59:59";
0 ignored issues
show
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $year instead of interpolation.

It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.

// Instead of
$x = "foo $bar $baz";

// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
Loading history...
175
176
            $parts = self::isEqualTo($parts, $direction, $equal_to);
177
178
            // Year/Month/Day/Time
179
        } elseif (preg_match('/^\d{1,4}[-\/]\d{1,2}[-\/]\d{1,2}\s\d{1,2}:\d{2}/', $string, $matches)) {
180
            // Handles the case of `to` filters
181
            if ($equal_to || is_null($direction)) {
182
                $parts['start'] = $parts['end'] = DateTimeObj::get('Y-m-d H:i:s', $string);
0 ignored issues
show
Bug introduced by
$string of type array is incompatible with the type null|string expected by parameter $timestamp of DateTimeObj::get(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

182
                $parts['start'] = $parts['end'] = DateTimeObj::get('Y-m-d H:i:s', /** @scrutinizer ignore-type */ $string);
Loading history...
183
            } else {
184
                $parts['start'] = DateTimeObj::get('Y-m-d H:i:s', $string . ' - 1 second');
0 ignored issues
show
Bug introduced by
Are you sure $string of type array can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

184
                $parts['start'] = DateTimeObj::get('Y-m-d H:i:s', /** @scrutinizer ignore-type */ $string . ' - 1 second');
Loading history...
185
                $parts['end'] = DateTimeObj::get('Y-m-d H:i:s', $string . ' + 1 second');
186
            }
187
188
            // Year/Month/Day
189
        } elseif (preg_match('/^\d{1,4}[-\/]\d{1,2}[-\/]\d{1,2}$/', $string, $matches)) {
190
            $year_month_day = current($matches);
191
192
            $parts['start'] = "$year_month_day 00:00:00";
0 ignored issues
show
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $year_month_day instead of interpolation.

It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.

// Instead of
$x = "foo $bar $baz";

// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
Loading history...
193
            $parts['end'] = "$year_month_day 23:59:59";
0 ignored issues
show
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $year_month_day instead of interpolation.

It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.

// Instead of
$x = "foo $bar $baz";

// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
Loading history...
194
195
            $parts = self::isEqualTo($parts, $direction, $equal_to);
196
197
            // Year/Month
198
        } elseif (preg_match('/^\d{1,4}[-\/]\d{1,2}$/', $string, $matches)) {
199
            $year_month = current($matches);
200
201
            $parts['start'] = "$year_month-01 00:00:00";
0 ignored issues
show
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $year_month instead of interpolation.

It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.

// Instead of
$x = "foo $bar $baz";

// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
Loading history...
202
            $parts['end'] = DateTimeObj::get('Y-m-t', $parts['start']) . " 23:59:59";
0 ignored issues
show
Bug introduced by
Are you sure DateTimeObj::get('Y-m-t', $parts['start']) of type false|string can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

202
            $parts['end'] = /** @scrutinizer ignore-type */ DateTimeObj::get('Y-m-t', $parts['start']) . " 23:59:59";
Loading history...
Coding Style Comprehensibility introduced by
The string literal 23:59:59 does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
203
204
            $parts = self::isEqualTo($parts, $direction, $equal_to);
205
206
            // Relative date, aka '+ 3 weeks'
207
        } else {
208
            // Handles the case of `to` filters
209
210
            if ($equal_to || is_null($direction)) {
211
                $parts['start'] = $parts['end'] = DateTimeObj::get('Y-m-d H:i:s', $string);
212
            } else {
213
                $parts['start'] = DateTimeObj::get('Y-m-d H:i:s', $string . ' - 1 second');
214
                $parts['end'] = DateTimeObj::get('Y-m-d H:i:s', $string . ' + 1 second');
215
            }
216
        }
217
218
        return $parts;
219
    }
220
221
    /**
222
     * Builds the correct date array depending if the filter should include
223
     * the filter as well, ie. later than 2011, is effectively the same as
224
     * equal to or later than 2012.
225
     *
226
     * @since Symphony 2.2.2
227
     * @param array $parts
228
     *  An associative array containing a date in ISO8601 format (or natural)
229
     *  with two keys, start and end.
230
     * @param string $direction
231
     *  Either later or earlier, defaults to null.
232
     * @param boolean $equal_to
233
     *  If the filter is equal_to or not, defaults to false.
234
     * @return array
235
     */
236
    public static function isEqualTo(array $parts, $direction, $equal_to = false)
0 ignored issues
show
Coding Style introduced by
Incorrect spacing between argument "$equal_to" and equals sign; expected 0 but found 1
Loading history...
Coding Style introduced by
Incorrect spacing between default value and equals sign for argument "$equal_to"; expected 0 but found 1
Loading history...
237
    {
238
        if (!$equal_to) {
239
            return $parts;
240
        }
241
242
        if ($direction == 'later') {
243
            $parts['end'] = $parts['start'];
244
        } else {
245
            $parts['start'] = $parts['end'];
246
        }
247
248
        return $parts;
249
    }
250
251
    public static function parseFilter(&$string)
252
    {
253
        $string = self::cleanFilterString($string);
254
255
        // Relative check, earlier or later
256
        if (preg_match('/^(equal to or )?(earlier|later) than (.*)$/i', $string, $match)) {
257
            $string = $match[3];
258
259
            // Validate date
260
            if (!DateTimeObj::validate($string)) {
261
                return self::ERROR;
262
            }
263
264
            // Date is equal to or earlier/later than
265
            // Date is earlier/later than
266
            $parts = self::parseDate($string, $match[2], $match[1] == "equal to or ");
0 ignored issues
show
Coding Style Comprehensibility introduced by
The string literal equal to or does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
267
268
            $earlier = $parts['start'];
269
            $later = $parts['end'];
270
271
            // Switch between earlier than and later than logic
272
            // The earlier/later range is defined by MySQL's support. RE: #1560
273
            // @link https://dev.mysql.com/doc/refman/en/datetime.html
274
            switch ($match[2]) {
275
                case 'later':
276
                    $string = $later . ' to ' . self::$max_date;
277
                    break;
278
                case 'earlier':
279
                    $string = self::$min_date . ' to ' . $earlier;
280
                    break;
281
            }
282
283
            // Look to see if its a shorthand date (year only), and convert to full date
284
            // Look to see if the give date is a shorthand date (year and month) and convert it to full date
285
            // Match single dates
286
        } elseif (
0 ignored issues
show
Coding Style introduced by
Expected 0 spaces after opening bracket; newline found
Loading history...
287
            preg_match('/^(1|2)\d{3}$/i', $string)
288
            || preg_match('/^(1|2)\d{3}[-\/]\d{1,2}$/i', $string)
289
            || !preg_match('/\s+to\s+/i', $string)
290
        ) {
291
            // Validate
292
            if (!DateTimeObj::validate($string)) {
293
                return self::ERROR;
294
            }
295
296
            $parts = self::parseDate($string);
0 ignored issues
show
Bug introduced by
$string of type string is incompatible with the type array expected by parameter $string of FieldDate::parseDate(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

296
            $parts = self::parseDate(/** @scrutinizer ignore-type */ $string);
Loading history...
297
            $string = $parts['start'] . ' to ' . $parts['end'];
298
299
            // Match date ranges
300
        } elseif (preg_match('/\s+to\s+/i', $string)) {
301
            if (!$parts = preg_split('/\s+to\s+/', $string, 2, PREG_SPLIT_NO_EMPTY)) {
302
                return self::ERROR;
303
            }
304
305
            foreach ($parts as $i => &$part) {
306
                // Validate
307
                if (!DateTimeObj::validate($part)) {
308
                    return self::ERROR;
309
                }
310
311
                $part = self::parseDate($part);
312
            }
313
314
            $string = $parts[0]['start'] . " to " . $parts[1]['end'];
0 ignored issues
show
Coding Style Comprehensibility introduced by
The string literal to does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
315
        }
316
317
        // Parse the full date range and return an array
318
        if (!$parts = preg_split('/\s+to\s+/i', $string, 2, PREG_SPLIT_NO_EMPTY)) {
319
            return self::ERROR;
320
        }
321
322
        $parts = array_map(array('self', 'cleanFilterString'), $parts);
323
324
        list($start, $end) = $parts;
325
326
        // Validate
327
        if (!DateTimeObj::validate($start) || !DateTimeObj::validate($end)) {
328
            return self::ERROR;
329
        }
330
331
        $string = array('start' => $start, 'end' => $end);
332
333
        return self::RANGE;
334
    }
335
336
    public static function cleanFilterString($string)
337
    {
338
        $string = trim($string, ' -/');
339
340
        return urldecode($string);
341
    }
342
343
    public function buildRangeFilterSQL($data, &$joins, &$where, $andOperation = false)
0 ignored issues
show
Coding Style introduced by
Incorrect spacing between argument "$andOperation" and equals sign; expected 0 but found 1
Loading history...
Coding Style introduced by
Incorrect spacing between default value and equals sign for argument "$andOperation"; expected 0 but found 1
Loading history...
344
    {
345
        $field_id = $this->get('id');
346
347
        if (empty($data)) {
348
            return;
349
        }
350
351
        if ($andOperation) {
352
            foreach ($data as $date) {
353
                // Prevent the DateTimeObj creating a range that isn't supported by MySQL.
354
                $start = ($date['start'] === self::$min_date) ? self::$min_date : DateTimeObj::getGMT('Y-m-d H:i:s', $date['start']);
355
                $end = ($date['end'] === self::$max_date) ? self::$max_date : DateTimeObj::getGMT('Y-m-d H:i:s', $date['end']);
356
357
                $joins .= " LEFT JOIN `tbl_entries_data_$field_id` AS `t$field_id".$this->key."` ON `e`.`id` = `t$field_id".$this->key."`.entry_id ";
0 ignored issues
show
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $field_id instead of interpolation.

It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.

// Instead of
$x = "foo $bar $baz";

// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
Loading history...
Coding Style Comprehensibility introduced by
The string literal `.entry_id does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
358
                $where .= " AND (`t$field_id".$this->key."`.date >= '" . $start . "' AND `t$field_id".$this->key."`.date <= '" . $end . "') ";
0 ignored issues
show
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $field_id instead of interpolation.

It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.

// Instead of
$x = "foo $bar $baz";

// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
Loading history...
359
360
                $this->key++;
361
            }
362
        } else {
363
            $tmp = array();
364
365
            foreach ($data as $date) {
366
                // Prevent the DateTimeObj creating a range that isn't supported by MySQL.
367
                $start = ($date['start'] === self::$min_date) ? self::$min_date : DateTimeObj::getGMT('Y-m-d H:i:s', $date['start']);
368
                $end = ($date['end'] === self::$max_date) ? self::$max_date : DateTimeObj::getGMT('Y-m-d H:i:s', $date['end']);
369
370
                $tmp[] = "`t$field_id".$this->key."`.date >= '" . $start . "' AND `t$field_id".$this->key."`.date <= '" . $end . "' ";
0 ignored issues
show
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $field_id instead of interpolation.

It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.

// Instead of
$x = "foo $bar $baz";

// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
Loading history...
371
            }
372
373
            $joins .= " LEFT JOIN `tbl_entries_data_$field_id` AS `t$field_id".$this->key."` ON `e`.`id` = `t$field_id".$this->key."`.entry_id ";
0 ignored issues
show
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $field_id instead of interpolation.

It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.

// Instead of
$x = "foo $bar $baz";

// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
Loading history...
Coding Style Comprehensibility introduced by
The string literal `.entry_id does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
374
            $where .= " AND (".implode(' OR ', $tmp).") ";
0 ignored issues
show
Coding Style Comprehensibility introduced by
The string literal AND ( does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
Coding Style Comprehensibility introduced by
The string literal ) does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
375
376
            $this->key++;
377
        }
378
    }
379
380
    /**
381
     * Format the $data parameter according to this field's settings.
382
     *
383
     * @since Symphony 2.6.0
384
     * @param array $date
385
     *  The date to format
386
     * @return string
387
     */
388
    public function formatDate($date)
389
    {
390
        // Get format
391
        $format = 'date_format';
392
        if ($this->get('time') === 'yes') {
393
            $format = 'datetime_format';
394
        }
0 ignored issues
show
Coding Style introduced by
No blank line found after control structure
Loading history...
395
        return DateTimeObj::format($date, DateTimeObj::getSetting($format));
0 ignored issues
show
Bug Best Practice introduced by
The expression return DateTimeObj::form...j::getSetting($format)) could also return false which is incompatible with the documented return type string. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
Bug introduced by
$date of type array is incompatible with the type string expected by parameter $string of DateTimeObj::format(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

395
        return DateTimeObj::format(/** @scrutinizer ignore-type */ $date, DateTimeObj::getSetting($format));
Loading history...
Bug introduced by
It seems like DateTimeObj::getSetting($format) can also be of type array; however, parameter $format of DateTimeObj::format() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

395
        return DateTimeObj::format($date, /** @scrutinizer ignore-type */ DateTimeObj::getSetting($format));
Loading history...
396
    }
397
398
    /*-------------------------------------------------------------------------
399
        Settings:
400
    -------------------------------------------------------------------------*/
401
402
    public function findDefaults(array &$settings)
403
    {
404
        if (!isset($settings['pre_populate'])) {
405
            $settings['pre_populate'] = $this->get('pre_populate');
406
        }
407
    }
408
409
    public function displaySettingsPanel(XMLElement &$wrapper, $errors = null)
0 ignored issues
show
Coding Style introduced by
Incorrect spacing between argument "$errors" and equals sign; expected 0 but found 1
Loading history...
Coding Style introduced by
Incorrect spacing between default value and equals sign for argument "$errors"; expected 0 but found 1
Loading history...
410
    {
411
        parent::displaySettingsPanel($wrapper, $errors);
412
413
        // Default date
414
        $label = Widget::Label(__('Default date'));
415
        $help = new XMLElement('i', __('optional, accepts absolute or relative dates'));
416
        $input = Widget::Input('fields['.$this->get('sortorder').'][pre_populate]', $this->get('pre_populate') ? $this->get('pre_populate') : '', 'input');
0 ignored issues
show
Bug introduced by
Are you sure $this->get('sortorder') of type array|mixed|null can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

416
        $input = Widget::Input('fields['./** @scrutinizer ignore-type */ $this->get('sortorder').'][pre_populate]', $this->get('pre_populate') ? $this->get('pre_populate') : '', 'input');
Loading history...
Bug introduced by
It seems like $this->get('pre_populate...et('pre_populate') : '' can also be of type array; however, parameter $value of Widget::Input() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

416
        $input = Widget::Input('fields['.$this->get('sortorder').'][pre_populate]', /** @scrutinizer ignore-type */ $this->get('pre_populate') ? $this->get('pre_populate') : '', 'input');
Loading history...
417
        $label->appendChild($help);
418
        $label->appendChild($input);
419
        $wrapper->appendChild($label);
420
421
        // Display settings
422
        $div = new XMLElement('div', null, array('class' => 'two columns'));
423
        $this->createCheckboxSetting($div, 'time', __('Display time'));
424
        $this->createCheckboxSetting($div, 'calendar', __('Show calendar'));
425
        $wrapper->appendChild($div);
426
427
        // Requirements and table display
428
        $this->appendStatusFooter($wrapper);
429
    }
430
431
    public function commit()
432
    {
433
        if (!parent::commit()) {
434
            return false;
435
        }
436
437
        $id = $this->get('id');
438
439
        if ($id === false) {
440
            return false;
441
        }
442
443
        $fields = array();
444
445
        $fields['pre_populate'] = ($this->get('pre_populate') ? $this->get('pre_populate') : '');
446
        $fields['time'] = ($this->get('time') ? $this->get('time') : 'no');
447
        $fields['calendar'] = ($this->get('calendar') ? $this->get('calendar') : 'no');
448
449
        return FieldManager::saveSettings($id, $fields);
0 ignored issues
show
Bug introduced by
It seems like $id can also be of type array; however, parameter $field_id of FieldManager::saveSettings() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

449
        return FieldManager::saveSettings(/** @scrutinizer ignore-type */ $id, $fields);
Loading history...
450
    }
451
452
    /*-------------------------------------------------------------------------
453
        Publish:
454
    -------------------------------------------------------------------------*/
455
456
    public function displayPublishPanel(XMLElement &$wrapper, $data = null, $flagWithError = null, $fieldnamePrefix = null, $fieldnamePostfix = null, $entry_id = null)
0 ignored issues
show
Coding Style introduced by
Incorrect spacing between argument "$data" and equals sign; expected 0 but found 1
Loading history...
Coding Style introduced by
Incorrect spacing between default value and equals sign for argument "$data"; expected 0 but found 1
Loading history...
Coding Style introduced by
Incorrect spacing between argument "$flagWithError" and equals sign; expected 0 but found 1
Loading history...
Coding Style introduced by
Incorrect spacing between default value and equals sign for argument "$flagWithError"; expected 0 but found 1
Loading history...
Coding Style introduced by
Incorrect spacing between argument "$fieldnamePrefix" and equals sign; expected 0 but found 1
Loading history...
Coding Style introduced by
Incorrect spacing between default value and equals sign for argument "$fieldnamePrefix"; expected 0 but found 1
Loading history...
Coding Style introduced by
Incorrect spacing between argument "$fieldnamePostfix" and equals sign; expected 0 but found 1
Loading history...
Coding Style introduced by
Incorrect spacing between default value and equals sign for argument "$fieldnamePostfix"; expected 0 but found 1
Loading history...
Coding Style introduced by
Incorrect spacing between argument "$entry_id" and equals sign; expected 0 but found 1
Loading history...
Coding Style introduced by
Incorrect spacing between default value and equals sign for argument "$entry_id"; expected 0 but found 1
Loading history...
457
    {
458
        $name = $this->get('element_name');
459
        $value = null;
460
461
        // New entry
462
        if (empty($data) && is_null($flagWithError) && !is_null($this->get('pre_populate'))) {
463
            $prepopulate = $this->get('pre_populate');
464
465
            $date = self::parseDate($prepopulate);
466
            $date = $date['start'];
467
            $value = $this->formatDate($date);
468
469
            // Error entry, display original data
470
        } elseif (!is_null($flagWithError)) {
471
            $value = $_POST['fields'][$name];
472
473
            // Empty entry
474
        } elseif (isset($data['value'])) {
475
            $value = $this->formatDate($data['value']);
476
        }
477
478
        $label = Widget::Label($this->get('label'));
0 ignored issues
show
Bug introduced by
It seems like $this->get('label') can also be of type array; however, parameter $name of Widget::Label() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

478
        $label = Widget::Label(/** @scrutinizer ignore-type */ $this->get('label'));
Loading history...
479
480
        if ($this->get('required') !== 'yes') {
481
            $label->appendChild(new XMLElement('i', __('Optional')));
482
        }
483
484
        // Input
485
        $label->appendChild(Widget::Input("fields{$fieldnamePrefix}[{$name}]", $value));
0 ignored issues
show
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $fieldnamePrefix instead of interpolation.

It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.

// Instead of
$x = "foo $bar $baz";

// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
Loading history...
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $name instead of interpolation.

It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.

// Instead of
$x = "foo $bar $baz";

// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
Loading history...
486
        $label->setAttribute('class', 'date');
487
488
        // Calendar
489
        if ($this->get('calendar') === 'yes') {
490
            $wrapper->setAttribute('data-interactive', 'data-interactive');
491
492
            $ul = new XMLElement('ul');
493
            $ul->setAttribute('class', 'suggestions');
494
            $ul->setAttribute('data-field-id', $this->get('id'));
0 ignored issues
show
Bug introduced by
It seems like $this->get('id') can also be of type array; however, parameter $value of XMLElement::setAttribute() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

494
            $ul->setAttribute('data-field-id', /** @scrutinizer ignore-type */ $this->get('id'));
Loading history...
495
            $ul->setAttribute('data-search-types', 'date');
496
497
            $calendar = new XMLElement('li');
498
            $calendar->appendChild(Widget::Calendar(($this->get('time') === 'yes')));
499
            $ul->appendChild($calendar);
500
501
            $label->appendChild($ul);
502
        }
503
504
        // Wrap label in error
505
        if (!is_null($flagWithError)) {
506
            $label = Widget::Error($label, $flagWithError);
507
        }
0 ignored issues
show
Coding Style introduced by
No blank line found after control structure
Loading history...
508
        $wrapper->appendChild($label);
509
    }
510
511
    public function checkPostFieldData($data, &$message, $entry_id = null)
0 ignored issues
show
Coding Style introduced by
Incorrect spacing between argument "$entry_id" and equals sign; expected 0 but found 1
Loading history...
Coding Style introduced by
Incorrect spacing between default value and equals sign for argument "$entry_id"; expected 0 but found 1
Loading history...
512
    {
513
        $message = null;
514
515
        // If this field is required
516
        if ($this->get('required') === 'yes' && strlen(trim($data)) == 0) {
517
            $message = __('‘%s’ is a required field.', array($this->get('label')));
518
            return self::__MISSING_FIELDS__;
519
        } elseif (empty($data)) {
520
            return self::__OK__;
521
        }
522
523
        // Handle invalid dates
524
        if (!DateTimeObj::validate($data)) {
525
            $message = __('The date specified in ‘%s’ is invalid.', array($this->get('label')));
526
            return self::__INVALID_FIELDS__;
527
        }
528
529
        return self::__OK__;
530
    }
531
532
    public function processRawFieldData($data, &$status, &$message = null, $simulate = false, $entry_id = null)
0 ignored issues
show
Coding Style introduced by
Incorrect spacing between argument "$message" and equals sign; expected 0 but found 1
Loading history...
Coding Style introduced by
Incorrect spacing between default value and equals sign for argument "$message"; expected 0 but found 1
Loading history...
Coding Style introduced by
Incorrect spacing between argument "$simulate" and equals sign; expected 0 but found 1
Loading history...
Coding Style introduced by
Incorrect spacing between default value and equals sign for argument "$simulate"; expected 0 but found 1
Loading history...
Coding Style introduced by
Incorrect spacing between argument "$entry_id" and equals sign; expected 0 but found 1
Loading history...
Coding Style introduced by
Incorrect spacing between default value and equals sign for argument "$entry_id"; expected 0 but found 1
Loading history...
533
    {
534
        $status = self::__OK__;
535
        $timestamp = null;
536
537
        // Prepopulate date
538
        if (is_null($data) || $data == '') {
539
            if ($this->get('pre_populate') !='') {
540
                $date = self::parseDate($this->get('pre_populate'));
541
                $date = $date['start'];
542
                $timestamp = $this->formatDate($date);
543
            }
544
545
            // Convert given date to timestamp
546
        } elseif ($status == self::__OK__ && DateTimeObj::validate($data)) {
547
            $timestamp = DateTimeObj::get('U', $data);
548
        }
549
550
        // Valid date
551
        if (!is_null($timestamp)) {
552
            return array(
553
                'value' => DateTimeObj::get('c', $timestamp),
0 ignored issues
show
Bug introduced by
It seems like $timestamp can also be of type false; however, parameter $timestamp of DateTimeObj::get() does only seem to accept null|string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

553
                'value' => DateTimeObj::get('c', /** @scrutinizer ignore-type */ $timestamp),
Loading history...
554
                'date' => DateTimeObj::getGMT('Y-m-d H:i:s', $timestamp)
0 ignored issues
show
Bug introduced by
It seems like $timestamp can also be of type false; however, parameter $timestamp of DateTimeObj::getGMT() does only seem to accept null|string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

554
                'date' => DateTimeObj::getGMT('Y-m-d H:i:s', /** @scrutinizer ignore-type */ $timestamp)
Loading history...
555
            );
556
557
            // Invalid date
558
        } else {
559
            return array(
560
                'value' => null,
561
                'date' => null
562
            );
563
        }
564
    }
565
566
    /*-------------------------------------------------------------------------
567
        Output:
568
    -------------------------------------------------------------------------*/
569
570
    public function appendFormattedElement(XMLElement &$wrapper, $data, $encode = false, $mode = null, $entry_id = null)
0 ignored issues
show
Coding Style introduced by
Incorrect spacing between argument "$encode" and equals sign; expected 0 but found 1
Loading history...
Coding Style introduced by
Incorrect spacing between default value and equals sign for argument "$encode"; expected 0 but found 1
Loading history...
Coding Style introduced by
Incorrect spacing between argument "$mode" and equals sign; expected 0 but found 1
Loading history...
Coding Style introduced by
Incorrect spacing between default value and equals sign for argument "$mode"; expected 0 but found 1
Loading history...
Coding Style introduced by
Incorrect spacing between argument "$entry_id" and equals sign; expected 0 but found 1
Loading history...
Coding Style introduced by
Incorrect spacing between default value and equals sign for argument "$entry_id"; expected 0 but found 1
Loading history...
571
    {
572
        if (isset($data['value'])) {
0 ignored issues
show
Coding Style introduced by
Blank line found at start of control structure
Loading history...
573
574
            // Get date
575
            if (is_array($data['value'])) {
576
                $date = current($data['value']);
577
            } else {
578
                $date = $data['value'];
579
            }
580
581
            $wrapper->appendChild(General::createXMLDateObject($date, $this->get('element_name')));
0 ignored issues
show
Bug introduced by
It seems like $this->get('element_name') can also be of type array; however, parameter $element of General::createXMLDateObject() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

581
            $wrapper->appendChild(General::createXMLDateObject($date, /** @scrutinizer ignore-type */ $this->get('element_name')));
Loading history...
Bug introduced by
It seems like General::createXMLDateOb...s->get('element_name')) can also be of type false; however, parameter $child of XMLElement::appendChild() does only seem to accept XMLElement|string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

581
            $wrapper->appendChild(/** @scrutinizer ignore-type */ General::createXMLDateObject($date, $this->get('element_name')));
Loading history...
582
        }
583
    }
584
585
    public function prepareTextValue($data, $entry_id = null)
0 ignored issues
show
Coding Style introduced by
Incorrect spacing between argument "$entry_id" and equals sign; expected 0 but found 1
Loading history...
Coding Style introduced by
Incorrect spacing between default value and equals sign for argument "$entry_id"; expected 0 but found 1
Loading history...
586
    {
587
        $value = '';
588
589
        if (isset($data['value'])) {
590
            $value = $this->formatDate($data['value']);
591
        }
592
593
        return $value;
594
    }
595
596
    public function getParameterPoolValue(array $data, $entry_id = null)
0 ignored issues
show
Coding Style introduced by
Incorrect spacing between argument "$entry_id" and equals sign; expected 0 but found 1
Loading history...
Coding Style introduced by
Incorrect spacing between default value and equals sign for argument "$entry_id"; expected 0 but found 1
Loading history...
597
    {
598
        return DateTimeObj::get('Y-m-d H:i:s', $data['value']);
599
    }
600
601
    /*-------------------------------------------------------------------------
602
        Import:
603
    -------------------------------------------------------------------------*/
604
605
    public function getImportModes()
606
    {
607
        return array(
608
            'getValue' =>       ImportableField::STRING_VALUE,
609
            'getPostdata' =>    ImportableField::ARRAY_VALUE
610
        );
611
    }
612
613
    public function prepareImportValue($data, $mode, $entry_id = null)
0 ignored issues
show
Coding Style introduced by
Incorrect spacing between argument "$entry_id" and equals sign; expected 0 but found 1
Loading history...
Coding Style introduced by
Incorrect spacing between default value and equals sign for argument "$entry_id"; expected 0 but found 1
Loading history...
614
    {
615
        $value = $status = $message = null;
616
        $modes = (object)$this->getImportModes();
617
618
        // Prepopulate date:
619
        if ($data === null || $data === '') {
620
            if (!is_null($this->get('pre_populate'))) {
621
                $timestamp = self::parseDate($this->get('pre_populate'));
622
                $timestamp = $timestamp['start'];
623
            }
624
625
            // DateTime to timestamp:
626
        } elseif ($data instanceof DateTime) {
627
            $timestamp = $data->getTimestamp();
628
629
            // Convert given date to timestamp:
630
        } elseif (DateTimeObj::validate($data)) {
631
            $timestamp = DateTimeObj::get('U', $data);
632
        }
633
634
        // Valid date found:
635
        if (isset($timestamp)) {
636
            $value = DateTimeObj::get('c', $timestamp);
637
        }
638
639
        if ($mode === $modes->getValue) {
640
            return $value;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $value also could return the type false which is incompatible with the return type mandated by ImportableField::prepareImportValue() of array|string.
Loading history...
641
        } elseif ($mode === $modes->getPostdata) {
642
            return $this->processRawFieldData($data, $status, $message, true, $entry_id);
643
        }
644
645
        return null;
646
    }
647
648
    /*-------------------------------------------------------------------------
649
        Export:
650
    -------------------------------------------------------------------------*/
651
652
    /**
653
     * Return a list of supported export modes for use with `prepareExportValue`.
654
     *
655
     * @return array
656
     */
657
    public function getExportModes()
658
    {
659
        return array(
660
            'getValue'    => ExportableField::VALUE,
661
            'getObject'   => ExportableField::OBJECT,
662
            'getPostdata' => ExportableField::POSTDATA
663
        );
664
    }
665
666
    /**
667
     * Give the field some data and ask it to return a value using one of many
668
     * possible modes.
669
     *
670
     * @param mixed $data
671
     * @param integer $mode
672
     * @param integer $entry_id
673
     * @return DateTime|null
674
     */
675
    public function prepareExportValue($data, $mode, $entry_id = null)
0 ignored issues
show
Coding Style introduced by
Incorrect spacing between argument "$entry_id" and equals sign; expected 0 but found 1
Loading history...
Coding Style introduced by
Incorrect spacing between default value and equals sign for argument "$entry_id"; expected 0 but found 1
Loading history...
676
    {
677
        $modes = (object)$this->getExportModes();
678
679
        if ($mode === $modes->getValue) {
680
            return $this->formatDate(
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->formatDate... $data['value'] : null) returns the type string which is incompatible with the documented return type DateTime|null.
Loading history...
681
682
                isset($data['value']) ? $data['value'] : null
683
            );
684
        }
685
686
        if ($mode === $modes->getObject) {
687
            $timezone = Symphony::Configuration()->get('timezone', 'region');
688
689
            $date = new DateTime(
690
                isset($data['value']) ? $data['value'] : 'now'
691
            );
692
693
            $date->setTimezone(new DateTimeZone($timezone));
0 ignored issues
show
Bug introduced by
It seems like $timezone can also be of type array; however, parameter $timezone of DateTimeZone::__construct() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

693
            $date->setTimezone(new DateTimeZone(/** @scrutinizer ignore-type */ $timezone));
Loading history...
694
695
            return $date;
696
        } elseif ($mode === $modes->getPostdata) {
697
            return isset($data['value'])
698
                ? $data['value']
0 ignored issues
show
Coding Style introduced by
Inline shorthand IF statement must be declared on a single line
Loading history...
699
                : null;
700
        }
701
702
        return null;
703
    }
704
705
    /*-------------------------------------------------------------------------
706
        Filtering:
707
    -------------------------------------------------------------------------*/
708
709
    public function buildDSRetrievalSQL($data, &$joins, &$where, $andOperation = false)
0 ignored issues
show
Coding Style introduced by
Incorrect spacing between argument "$andOperation" and equals sign; expected 0 but found 1
Loading history...
Coding Style introduced by
Incorrect spacing between default value and equals sign for argument "$andOperation"; expected 0 but found 1
Loading history...
710
    {
711
        if (self::isFilterRegex($data[0])) {
712
            $this->buildRegexSQL($data[0], array('value'), $joins, $where);
713
        } elseif (self::isFilterSQL($data[0])) {
714
            $this->buildFilterSQL($data[0], array('value'), $joins, $where);
715
        } else {
716
            $parsed = array();
717
718
            // For the filter provided, loop over each piece
719
            foreach ($data as $string) {
720
                $type = self::parseFilter($string);
721
722
                if ($type == self::ERROR) {
723
                    return false;
724
                }
725
726
                if (!is_array($parsed[$type])) {
727
                    $parsed[$type] = array();
728
                }
729
730
                $parsed[$type][] = $string;
731
            }
732
733
            foreach ($parsed as $value) {
734
                $this->buildRangeFilterSQL($value, $joins, $where, $andOperation);
735
            }
736
        }
737
738
        return true;
739
    }
740
741
    /*-------------------------------------------------------------------------
742
        Sorting:
743
    -------------------------------------------------------------------------*/
744
745
    public function buildSortingSQL(&$joins, &$where, &$sort, $order = 'ASC')
0 ignored issues
show
Coding Style introduced by
Incorrect spacing between argument "$order" and equals sign; expected 0 but found 1
Loading history...
Coding Style introduced by
Incorrect spacing between default value and equals sign for argument "$order"; expected 0 but found 1
Loading history...
746
    {
747
        if ($this->isRandomOrder($order)) {
748
            $sort = 'ORDER BY RAND()';
749
        } else {
750
            $sort = sprintf(
751
                'ORDER BY (
752
                    SELECT %s
753
                    FROM tbl_entries_data_%d AS `ed`
754
                    WHERE entry_id = e.id
755
                ) %s, `e`.`id` %s',
756
                '`ed`.date',
757
                $this->get('id'),
0 ignored issues
show
Bug introduced by
It seems like $this->get('id') can also be of type array; however, parameter $args of sprintf() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

757
                /** @scrutinizer ignore-type */ $this->get('id'),
Loading history...
758
                $order,
759
                $order
760
            );
761
        }
762
    }
763
764
    public function buildSortingSelectSQL($sort, $order = 'ASC')
0 ignored issues
show
Coding Style introduced by
Incorrect spacing between argument "$order" and equals sign; expected 0 but found 1
Loading history...
Coding Style introduced by
Incorrect spacing between default value and equals sign for argument "$order"; expected 0 but found 1
Loading history...
765
    {
766
        return null;
767
    }
768
769
    /*-------------------------------------------------------------------------
770
        Grouping:
771
    -------------------------------------------------------------------------*/
772
773
    public function groupRecords($records)
774
    {
775
        if (!is_array($records) || empty($records)) {
776
            return;
777
        }
778
779
        $groups = array('year' => array());
780
781
        foreach ($records as $r) {
782
            $data = $r->getData($this->get('id'));
783
784
            $timestamp = DateTimeObj::get('U', $data['value']);
785
            $info = getdate($timestamp);
0 ignored issues
show
Bug introduced by
$timestamp of type false|string is incompatible with the type integer expected by parameter $timestamp of getdate(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

785
            $info = getdate(/** @scrutinizer ignore-type */ $timestamp);
Loading history...
786
787
            $year = $info['year'];
788
            $month = ($info['mon'] < 10 ? '0' . $info['mon'] : $info['mon']);
0 ignored issues
show
Coding Style introduced by
Inline shorthand IF statement requires brackets around comparison
Loading history...
789
790
            if (!isset($groups['year'][$year])) {
791
                $groups['year'][$year] = array(
792
                    'attr' => array('value' => $year),
793
                    'records' => array(),
794
                    'groups' => array()
795
                );
796
            }
797
798
            if (!isset($groups['year'][$year]['groups']['month'])) {
799
                $groups['year'][$year]['groups']['month'] = array();
800
            }
801
802
            if (!isset($groups['year'][$year]['groups']['month'][$month])) {
803
                $groups['year'][$year]['groups']['month'][$month] = array(
804
                    'attr' => array('value' => $month),
805
                    'records' => array(),
806
                    'groups' => array()
807
                );
808
            }
809
810
            $groups['year'][$year]['groups']['month'][$month]['records'][] = $r;
811
        }
812
813
        return $groups;
814
    }
815
}
816