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.

SectionDatasource::processRecordGroup()   B
last analyzed

Complexity

Conditions 11
Paths 12

Size

Total Lines 32
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 11
eloc 17
c 0
b 0
f 0
nc 12
nop 2
dl 0
loc 32
rs 7.3166

How to fix   Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * @package data-sources
5
 */
6
/**
7
 * The `SectionDatasource` allows a user to retrieve entries from a given
8
 * section on the Frontend. This datasource type exposes the filtering provided
9
 * by the Fields in the given section to narrow the result set down. The resulting
10
 * entries can be grouped, sorted and allows pagination. Results can be chained
11
 * from other `SectionDatasource`'s using output parameters.
12
 *
13
 * @since Symphony 2.3
14
 * @link http://getsymphony.com/learn/concepts/view/data-sources/
15
 */
16
17
class SectionDatasource extends Datasource
18
{
19
    /**
20
     * An array of Field objects that this Datasource has created to display
21
     * the results.
22
     */
23
    private static $_fieldPool = array();
24
25
    /**
26
     * An array of the Symphony meta data parameters.
27
     */
28
    private static $_system_parameters = array(
29
        'system:id',
30
        'system:author',
31
        'system:creation-date',
32
        'system:modification-date',
33
        'system:date' // deprecated
34
    );
35
36
    /**
37
     * Set's the Section ID that this Datasource will use as it's source
38
     *
39
     * @param integer $source
40
     */
41
    public function setSource($source)
42
    {
43
        $this->_source = (int)$source;
0 ignored issues
show
Bug Best Practice introduced by
The property _source does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
44
    }
45
46
    /**
47
     * Return's the Section ID that this datasource is using as it's source
48
     *
49
     * @return integer
50
     */
51
    public function getSource()
52
    {
53
        return $this->_source;
54
    }
55
56
    /**
57
     * If this Datasource requires System Parameters to be output, this function
58
     * will return true, otherwise false.
59
     *
60
     * @return boolean
61
     */
62
    public function canProcessSystemParameters()
63
    {
64
        if (!is_array($this->dsParamPARAMOUTPUT)) {
65
            return false;
66
        }
67
68
        foreach (self::$_system_parameters as $system_parameter) {
69
            if (in_array($system_parameter, $this->dsParamPARAMOUTPUT) === true) {
70
                return true;
71
            }
72
        }
73
74
        return false;
75
    }
76
77
    /**
78
     * Given a name for the group, and an associative array that
79
     * contains three keys, `attr`, `records` and `groups`. Grouping
80
     * of Entries is done by the grouping Field at a PHP level, not
81
     * through the Database.
82
     *
83
     * @param string $element
84
     *  The name for the XML node for this group
85
     * @param array $group
86
     *  An associative array of the group data, includes `attr`, `records`
87
     *  and `groups` keys.
88
     * @throws Exception
89
     * @return XMLElement
90
     */
91
    public function processRecordGroup($element, array $group)
92
    {
93
        $xGroup = new XMLElement($element, null, $group['attr']);
94
95
        if (is_array($group['records']) && !empty($group['records'])) {
96
            if (isset($group['records'][0])) {
97
                $data = $group['records'][0]->getData();
98
                $pool = FieldManager::fetch(array_keys($data));
99
                self::$_fieldPool += $pool;
100
            }
101
102
            foreach ($group['records'] as $entry) {
103
                $xEntry = $this->processEntry($entry);
104
105
                if ($xEntry instanceof XMLElement) {
106
                    $xGroup->appendChild($xEntry);
107
                }
108
            }
109
        }
110
111
        if (is_array($group['groups']) && !empty($group['groups'])) {
112
            foreach ($group['groups'] as $element => $group) {
0 ignored issues
show
introduced by
$element is overwriting one of the parameters of this function.
Loading history...
113
                foreach ($group as $g) {
114
                    $xGroup->appendChild(
115
                        $this->processRecordGroup($element, $g)
116
                    );
117
                }
118
            }
119
        }
120
121
        if (!$this->_param_output_only) {
122
            return $xGroup;
123
        }
124
    }
125
126
    /**
127
     * Given an Entry object, this function will generate an XML representation
128
     * of the Entry to be returned. It will also add any parameters selected
129
     * by this datasource to the parameter pool.
130
     *
131
     * @param Entry $entry
132
     * @throws Exception
133
     * @return XMLElement|boolean
134
     *  Returns boolean when only parameters are to be returned.
135
     */
136
    public function processEntry(Entry $entry)
137
    {
138
        $data = $entry->getData();
139
140
        $xEntry = new XMLElement('entry');
141
        $xEntry->setAttribute('id', $entry->get('id'));
0 ignored issues
show
Bug introduced by
It seems like $entry->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

141
        $xEntry->setAttribute('id', /** @scrutinizer ignore-type */ $entry->get('id'));
Loading history...
142
143
        if (!empty($this->_associated_sections)) {
144
            $this->setAssociatedEntryCounts($xEntry, $entry);
145
        }
146
147
        if ($this->_can_process_system_parameters) {
148
            $this->processSystemParameters($entry);
149
        }
150
151
        foreach ($data as $field_id => $values) {
152
            if (!isset(self::$_fieldPool[$field_id]) || !is_object(self::$_fieldPool[$field_id])) {
153
                self::$_fieldPool[$field_id] = FieldManager::fetch($field_id);
154
            }
155
156
            $this->processOutputParameters($entry, $field_id, $values);
157
158
            if (!$this->_param_output_only) {
159
                foreach ($this->dsParamINCLUDEDELEMENTS as $handle) {
160
                    list($handle, $mode) = preg_split('/\s*:\s*/', $handle, 2);
161
162
                    if (self::$_fieldPool[$field_id]->get('element_name') == $handle) {
163
                        self::$_fieldPool[$field_id]->appendFormattedElement($xEntry, $values, ($this->dsParamHTMLENCODE === 'yes' ? true : false), $mode, $entry->get('id'));
0 ignored issues
show
Bug Best Practice introduced by
The property dsParamHTMLENCODE does not exist on SectionDatasource. Did you maybe forget to declare it?
Loading history...
Coding Style introduced by
Inline shorthand IF statement requires brackets around comparison
Loading history...
164
                    }
165
                }
166
            }
167
        }
168
169
        if ($this->_param_output_only) {
170
            return true;
171
        }
172
173
        // This is deprecated and will be removed in Symphony 3.0.0
174
        if (in_array('system:date', $this->dsParamINCLUDEDELEMENTS)) {
175
            if (Symphony::Log()) {
176
                Symphony::Log()->pushDeprecateWarningToLog('system:date', 'system:creation-date` or `system:modification-date', array(
177
                    'message-format' => __('The `%s` data source field is deprecated.')
178
                ));
179
            }
0 ignored issues
show
Coding Style introduced by
No blank line found after control structure
Loading history...
180
            $xDate = new XMLElement('system-date');
181
            $xDate->appendChild(
182
                General::createXMLDateObject(
0 ignored issues
show
Bug introduced by
It seems like General::createXMLDateOb...ion_date')), 'created') 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

182
                /** @scrutinizer ignore-type */ General::createXMLDateObject(
Loading history...
183
                    DateTimeObj::get('U', $entry->get('creation_date')),
0 ignored issues
show
Bug introduced by
DateTimeObj::get('U', $e...->get('creation_date')) of type false|string is incompatible with the type integer expected by parameter $timestamp of General::createXMLDateObject(). ( Ignorable by Annotation )

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

183
                    /** @scrutinizer ignore-type */ DateTimeObj::get('U', $entry->get('creation_date')),
Loading history...
Bug introduced by
It seems like $entry->get('creation_date') can also be of type array; 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

183
                    DateTimeObj::get('U', /** @scrutinizer ignore-type */ $entry->get('creation_date')),
Loading history...
184
                    'created'
185
                )
186
            );
187
            $xDate->appendChild(
188
                General::createXMLDateObject(
189
                    DateTimeObj::get('U', $entry->get('modification_date')),
190
                    'modified'
191
                )
192
            );
193
            $xEntry->appendChild($xDate);
194
        }
195
196
        return $xEntry;
197
    }
198
199
    /**
200
     * An entry may be associated to other entries from various fields through
201
     * the section associations. This function will set the number of related
202
     * entries as attributes to the main `<entry>` element grouped by the
203
     * related entry's section.
204
     *
205
     * @param XMLElement $xEntry
206
     *  The <entry> XMLElement that the associated section counts will
207
     *  be set on
208
     * @param Entry $entry
209
     *  The current entry object
210
     * @throws Exception
211
     */
212
    public function setAssociatedEntryCounts(XMLElement &$xEntry, Entry $entry)
213
    {
214
        $associated_entry_counts = $entry->fetchAllAssociatedEntryCounts($this->_associated_sections);
215
216
        if (!empty($associated_entry_counts)) {
217
            foreach ($associated_entry_counts as $section_id => $fields) {
218
                foreach ($this->_associated_sections as $section) {
219
                    if ($section['id'] != $section_id) {
220
                        continue;
221
                    }
222
223
                    // For each related field show the count (#2083)
224
                    foreach ($fields as $field_id => $count) {
225
                        $field_handle = FieldManager::fetchHandleFromID($field_id);
226
                        $section_handle = $section['handle'];
227
                        // Make sure attribute does not begin with a digit
228
                        if (preg_match('/^[0-9]/', $section_handle)) {
229
                            $section_handle = 'x-' . $section_handle;
230
                        }
0 ignored issues
show
Coding Style introduced by
No blank line found after control structure
Loading history...
231
                        if ($field_handle) {
232
                            $xEntry->setAttribute($section_handle . '-' . $field_handle, (string)$count);
233
                        }
234
235
                        // Backwards compatibility (without field handle)
236
                        $xEntry->setAttribute($section_handle, (string)$count);
237
                    }
238
                }
239
            }
240
        }
241
    }
242
243
    /**
244
     * Given an Entry object, this function will iterate over the `dsParamPARAMOUTPUT`
245
     * setting to see any of the Symphony system parameters need to be set.
246
     * The current system parameters supported are `system:id`, `system:author`,
247
     * `system:creation-date` and `system:modification-date`.
248
     * If these parameters are found, the result is added
249
     * to the `$param_pool` array using the key, `ds-datasource-handle.parameter-name`
250
     * For the moment, this function also supports the pre Symphony 2.3 syntax,
251
     * `ds-datasource-handle` which did not support multiple parameters.
252
     *
253
     * @param Entry $entry
254
     *  The Entry object that contains the values that may need to be added
255
     *  into the parameter pool.
256
     */
257
    public function processSystemParameters(Entry $entry)
258
    {
259
        if (!isset($this->dsParamPARAMOUTPUT)) {
260
            return;
261
        }
262
263
        // Support the legacy parameter `ds-datasource-handle`
264
        $key = 'ds-' . $this->dsParamROOTELEMENT;
0 ignored issues
show
Bug Best Practice introduced by
The property dsParamROOTELEMENT does not exist on SectionDatasource. Did you maybe forget to declare it?
Loading history...
265
        $singleParam = count($this->dsParamPARAMOUTPUT) == 1;
266
267
        foreach ($this->dsParamPARAMOUTPUT as $param) {
268
            // The new style of paramater is `ds-datasource-handle.field-handle`
269
            $param_key = $key . '.' . str_replace(':', '-', $param);
270
271
            if ($param === 'system:id') {
272
                $this->_param_pool[$param_key][] = $entry->get('id');
0 ignored issues
show
Bug Best Practice introduced by
The property _param_pool does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
273
274
                if ($singleParam) {
275
                    $this->_param_pool[$key][] = $entry->get('id');
276
                }
277
            } elseif ($param === 'system:author') {
278
                $this->_param_pool[$param_key][] = $entry->get('author_id');
279
280
                if ($singleParam) {
281
                    $this->_param_pool[$key][] = $entry->get('author_id');
282
                }
283
            } elseif ($param === 'system:creation-date' || $param === 'system:date') {
284
                if ($param === 'system:date' && Symphony::Log()) {
285
                    Symphony::Log()->pushDeprecateWarningToLog('system:date', 'system:creation-date', array(
286
                        'message-format' => __('The `%s` data source output parameter is deprecated.')
287
                    ));
288
                }
0 ignored issues
show
Coding Style introduced by
No blank line found after control structure
Loading history...
289
                $this->_param_pool[$param_key][] = $entry->get('creation_date');
290
291
                if ($singleParam) {
292
                    $this->_param_pool[$key][] = $entry->get('creation_date');
293
                }
294
            } elseif ($param === 'system:modification-date') {
295
                $this->_param_pool[$param_key][] = $entry->get('modification_date');
296
297
                if ($singleParam) {
298
                    $this->_param_pool[$key][] = $entry->get('modification_date');
299
                }
300
            }
301
        }
302
    }
303
304
    /**
305
     * Given an Entry object, a `$field_id` and an array of `$data`, this
306
     * function iterates over the `dsParamPARAMOUTPUT` and will call the
307
     * field's (identified by `$field_id`) `getParameterPoolValue` function
308
     * to add parameters to the `$this->_param_pool`.
309
     *
310
     * @param Entry $entry
311
     * @param integer $field_id
312
     * @param array $data
313
     */
314
    public function processOutputParameters(Entry $entry, $field_id, array $data)
315
    {
316
        if (!isset($this->dsParamPARAMOUTPUT)) {
317
            return;
318
        }
319
320
        // Support the legacy parameter `ds-datasource-handle`
321
        $key = 'ds-' . $this->dsParamROOTELEMENT;
0 ignored issues
show
Bug Best Practice introduced by
The property dsParamROOTELEMENT does not exist on SectionDatasource. Did you maybe forget to declare it?
Loading history...
322
        $singleParam = count($this->dsParamPARAMOUTPUT) == 1;
323
324
        if ($singleParam && (!isset($this->_param_pool[$key]) || !is_array($this->_param_pool[$key]))) {
325
            $this->_param_pool[$key] = array();
0 ignored issues
show
Bug Best Practice introduced by
The property _param_pool does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
326
        }
327
328
        foreach ($this->dsParamPARAMOUTPUT as $param) {
329
            if (self::$_fieldPool[$field_id]->get('element_name') !== $param) {
330
                continue;
331
            }
332
333
            // The new style of paramater is `ds-datasource-handle.field-handle`
334
            $param_key = $key . '.' . str_replace(':', '-', $param);
335
336
            if (!isset($this->_param_pool[$param_key]) || !is_array($this->_param_pool[$param_key])) {
337
                $this->_param_pool[$param_key] = array();
338
            }
339
340
            $param_pool_values = self::$_fieldPool[$field_id]->getParameterPoolValue($data, $entry->get('id'));
341
342
            if (is_array($param_pool_values)) {
343
                $this->_param_pool[$param_key] = array_merge($param_pool_values, $this->_param_pool[$param_key]);
344
345
                if ($singleParam) {
346
                    $this->_param_pool[$key] = array_merge($param_pool_values, $this->_param_pool[$key]);
347
                }
348
            } elseif (!is_null($param_pool_values)) {
349
                $this->_param_pool[$param_key][] = $param_pool_values;
350
351
                if ($singleParam) {
352
                    $this->_param_pool[$key][] = $param_pool_values;
353
                }
354
            }
355
        }
356
    }
357
358
    /**
359
     * This function iterates over `dsParamFILTERS` and builds the relevant
360
     * `$where` and `$joins` parameters with SQL. This SQL is generated from
361
     * `Field->buildDSRetrievalSQL`. A third parameter, `$group` is populated
362
     * with boolean from `Field->requiresSQLGrouping()`
363
     *
364
     * @param string $where
365
     * @param string $joins
366
     * @param boolean $group
367
     * @throws Exception
368
     */
369
    public function processFilters(&$where, &$joins, &$group)
370
    {
371
        if (!is_array($this->dsParamFILTERS) || empty($this->dsParamFILTERS)) {
372
            return;
373
        }
374
375
        $pool = FieldManager::fetch(array_filter(array_keys($this->dsParamFILTERS), 'is_int'));
376
        self::$_fieldPool += $pool;
377
378
        if (!is_string($where)) {
0 ignored issues
show
introduced by
The condition is_string($where) is always true.
Loading history...
379
            $where = '';
380
        }
381
382
        foreach ($this->dsParamFILTERS as $field_id => $filter) {
383
            if ((is_array($filter) && empty($filter)) || trim($filter) == '') {
384
                continue;
385
            }
386
387
            if (!is_array($filter)) {
388
                $filter_type = Datasource::determineFilterType($filter);
389
                $value = Datasource::splitFilter($filter_type, $filter);
390
            } else {
391
                $filter_type = Datasource::FILTER_OR;
392
                $value = $filter;
393
            }
394
395
            if (!in_array($field_id, self::$_system_parameters) && $field_id != 'id' && !(self::$_fieldPool[$field_id] instanceof Field)) {
396
                throw new Exception(
397
                    __(
398
                        'Error creating field object with id %1$d, for filtering in data source %2$s. Check this field exists.',
399
                        array($field_id, '<code>' . $this->dsParamROOTELEMENT . '</code>')
0 ignored issues
show
Bug Best Practice introduced by
The property dsParamROOTELEMENT does not exist on SectionDatasource. Did you maybe forget to declare it?
Loading history...
400
                    )
401
                );
402
            }
403
404
            // Support system:id as well as the old 'id'. #1691
405
            if ($field_id === 'system:id' || $field_id === 'id') {
406
                if ($filter_type == Datasource::FILTER_AND) {
407
                    $value = array_map(function ($val) {
408
                        return explode(',', $val);
409
                    }, $value);
410
                } else {
411
                    $value = array($value);
412
                }
413
414
                foreach ($value as $v) {
415
                    $c = 'IN';
416
                    if (stripos($v[0], 'not:') === 0) {
417
                        $v[0] = preg_replace('/^not:\s*/', null, $v[0]);
418
                        $c = 'NOT IN';
419
                    }
420
421
                    // Cast all ID's to integers. (RE: #2191)
422
                    $v = array_map(function ($val) {
423
                        $val = General::intval($val);
424
425
                        // General::intval can return -1, so reset that to 0
426
                        // so there are no side effects for the following
427
                        // array_sum and array_filter calls. RE: #2475
428
                        if ($val === -1) {
429
                            $val = 0;
430
                        }
431
432
                        return $val;
433
                    }, $v);
434
                    $count = array_sum($v);
435
                    $v = array_filter($v);
436
437
                    // If the ID was cast to 0, then we need to filter on 'id' = 0,
438
                    // which will of course return no results, but without it the
439
                    // Datasource will return ALL results, which is not the
440
                    // desired behaviour. RE: #1619
441
                    if ($count === 0) {
442
                        $v[] = 0;
443
                    }
444
445
                    // If there are no ID's, no need to filter. RE: #1567
446
                    if (!empty($v)) {
447
                        $where .= " AND `e`.id " . $c . " (".implode(", ", $v).") ";
0 ignored issues
show
Coding Style Comprehensibility introduced by
The string literal AND `e`.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...
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...
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...
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...
448
                    }
449
                }
450
            } elseif ($field_id === 'system:creation-date' || $field_id === 'system:modification-date' || $field_id === 'system:date') {
451
                if ($field_id === 'system:date' && Symphony::Log()) {
452
                    Symphony::Log()->pushDeprecateWarningToLog('system:date', 'system:creation-date` or `system:modification-date', array(
453
                        'message-format' => __('The `%s` data source filter is deprecated.')
454
                    ));
455
                }
0 ignored issues
show
Coding Style introduced by
No blank line found after control structure
Loading history...
456
                $date_joins = '';
457
                $date_where = '';
458
                $date = new FieldDate();
459
                $date->buildDSRetrievalSQL($value, $date_joins, $date_where, ($filter_type == Datasource::FILTER_AND ? true : false));
0 ignored issues
show
Coding Style introduced by
Inline shorthand IF statement requires brackets around comparison
Loading history...
460
461
                // Replace the date field where with the `creation_date` or `modification_date`.
462
                $date_where = preg_replace('/`t\d+`.date/', ($field_id !== 'system:modification-date') ? '`e`.creation_date_gmt' : '`e`.modification_date_gmt', $date_where);
463
                $where .= $date_where;
464
            } else {
465
                if (!self::$_fieldPool[$field_id]->buildDSRetrievalSQL($value, $joins, $where, ($filter_type == Datasource::FILTER_AND ? true : false))) {
0 ignored issues
show
Coding Style introduced by
Inline shorthand IF statement requires brackets around comparison
Loading history...
466
                    $this->_force_empty_result = true;
467
                    return;
468
                }
469
470
                if (!$group) {
471
                    $group = self::$_fieldPool[$field_id]->requiresSQLGrouping();
472
                }
473
            }
474
        }
475
    }
476
477
    public function execute(array &$param_pool = null)
0 ignored issues
show
Coding Style introduced by
Incorrect spacing between argument "$param_pool" and equals sign; expected 0 but found 1
Loading history...
Coding Style introduced by
Incorrect spacing between default value and equals sign for argument "$param_pool"; expected 0 but found 1
Loading history...
478
    {
479
        $result = new XMLElement($this->dsParamROOTELEMENT);
0 ignored issues
show
Bug Best Practice introduced by
The property dsParamROOTELEMENT does not exist on SectionDatasource. Did you maybe forget to declare it?
Loading history...
480
        $this->_param_pool = $param_pool;
0 ignored issues
show
Bug Best Practice introduced by
The property _param_pool does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
481
        $where = null;
482
        $joins = null;
483
        $group = false;
484
485
        if (!$section = SectionManager::fetch((int)$this->getSource())) {
486
            $about = $this->about();
487
            trigger_error(__('The Section, %s, associated with the Data source, %s, could not be found.', array($this->getSource(), '<code>' . $about['name'] . '</code>')), E_USER_ERROR);
488
        }
489
490
        $sectioninfo = new XMLElement('section', General::sanitize($section->get('name')), array(
0 ignored issues
show
Bug introduced by
It seems like $section->get('name') can also be of type array; however, parameter $source of General::sanitize() 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

490
        $sectioninfo = new XMLElement('section', General::sanitize(/** @scrutinizer ignore-type */ $section->get('name')), array(
Loading history...
491
            'id' => $section->get('id'),
492
            'handle' => $section->get('handle')
493
        ));
494
495
        if ($this->_force_empty_result == true) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
496
            if ($this->dsParamREDIRECTONREQUIRED === 'yes') {
0 ignored issues
show
Bug Best Practice introduced by
The property dsParamREDIRECTONREQUIRED does not exist on SectionDatasource. Did you maybe forget to declare it?
Loading history...
497
                throw new FrontendPageNotFoundException;
498
            }
499
500
            $this->_force_empty_result = false; //this is so the section info element doesn't disappear.
501
            $error = new XMLElement('error', __("Data source not executed, required parameter is missing."), array(
0 ignored issues
show
Coding Style Comprehensibility introduced by
The string literal Data source not executed...d parameter is missing. 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...
502
                'required-param' => $this->dsParamREQUIREDPARAM
0 ignored issues
show
Bug Best Practice introduced by
The property dsParamREQUIREDPARAM does not exist on SectionDatasource. Did you maybe forget to declare it?
Loading history...
503
            ));
504
            $result->appendChild($error);
505
            $result->prependChild($sectioninfo);
506
507
            return $result;
508
        }
509
510
        if ($this->_negate_result == true) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
511
            if ($this->dsParamREDIRECTONFORBIDDEN === 'yes') {
0 ignored issues
show
Bug Best Practice introduced by
The property dsParamREDIRECTONFORBIDDEN does not exist on SectionDatasource. Did you maybe forget to declare it?
Loading history...
512
                throw new FrontendPageNotFoundException;
513
            }
514
515
            $this->_negate_result = false; //this is so the section info element doesn't disappear.
516
            $result = $this->negateXMLSet();
517
            $result->prependChild($sectioninfo);
518
519
            return $result;
520
        }
521
522
        if (is_array($this->dsParamINCLUDEDELEMENTS)) {
523
            $include_pagination_element = in_array('system:pagination', $this->dsParamINCLUDEDELEMENTS);
524
        } else {
525
            $this->dsParamINCLUDEDELEMENTS = array();
0 ignored issues
show
Bug Best Practice introduced by
The property dsParamINCLUDEDELEMENTS does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
526
        }
527
528
        if (isset($this->dsParamPARAMOUTPUT) && !is_array($this->dsParamPARAMOUTPUT)) {
529
            $this->dsParamPARAMOUTPUT = array($this->dsParamPARAMOUTPUT);
0 ignored issues
show
Bug Best Practice introduced by
The property dsParamPARAMOUTPUT does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
530
        }
531
532
        $this->_can_process_system_parameters = $this->canProcessSystemParameters();
0 ignored issues
show
Bug Best Practice introduced by
The property _can_process_system_parameters does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
533
534
        if (!isset($this->dsParamPAGINATERESULTS)) {
535
            $this->dsParamPAGINATERESULTS = 'yes';
0 ignored issues
show
Bug Best Practice introduced by
The property dsParamPAGINATERESULTS does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
536
        }
537
538
        // Process Filters
539
        $this->processFilters($where, $joins, $group);
540
541
        // Process Sorting
542
        if ($this->dsParamSORT == 'system:id') {
543
            EntryManager::setFetchSorting('system:id', $this->dsParamORDER);
0 ignored issues
show
Bug introduced by
'system:id' of type string is incompatible with the type integer expected by parameter $field_id of EntryManager::setFetchSorting(). ( Ignorable by Annotation )

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

543
            EntryManager::setFetchSorting(/** @scrutinizer ignore-type */ 'system:id', $this->dsParamORDER);
Loading history...
544
        } elseif ($this->dsParamSORT == 'system:date' || $this->dsParamSORT == 'system:creation-date') {
545
            if ($this->dsParamSORT === 'system:date' && Symphony::Log()) {
546
                Symphony::Log()->pushDeprecateWarningToLog('system:date', 'system:creation-date', array(
547
                    'message-format' => __('The `%s` data source sort is deprecated.')
548
                ));
549
            }
0 ignored issues
show
Coding Style introduced by
No blank line found after control structure
Loading history...
550
            EntryManager::setFetchSorting('system:creation-date', $this->dsParamORDER);
551
        } elseif ($this->dsParamSORT == 'system:modification-date') {
552
            EntryManager::setFetchSorting('system:modification-date', $this->dsParamORDER);
553
        } else {
554
            EntryManager::setFetchSorting(
555
                FieldManager::fetchFieldIDFromElementName($this->dsParamSORT, $this->getSource()),
556
                $this->dsParamORDER
557
            );
558
        }
559
560
        // combine `INCLUDEDELEMENTS`, `PARAMOUTPUT` and `GROUP` into an
561
        // array of field handles to optimise the `EntryManager` queries
562
        $datasource_schema = $this->dsParamINCLUDEDELEMENTS;
563
564
        if (is_array($this->dsParamPARAMOUTPUT)) {
565
            $datasource_schema = array_merge($datasource_schema, $this->dsParamPARAMOUTPUT);
566
        }
567
568
        if ($this->dsParamGROUP) {
0 ignored issues
show
Bug introduced by
The property dsParamGROUP does not exist on SectionDatasource. Did you mean dsParamSORT?
Loading history...
569
            $datasource_schema[] = FieldManager::fetchHandleFromID($this->dsParamGROUP);
570
        }
571
572
        $entries = EntryManager::fetchByPage(
573
            ($this->dsParamPAGINATERESULTS === 'yes' && $this->dsParamSTARTPAGE > 0 ? $this->dsParamSTARTPAGE : 1),
0 ignored issues
show
Coding Style introduced by
Inline shorthand IF statement requires brackets around comparison
Loading history...
574
            $this->getSource(),
575
            ($this->dsParamPAGINATERESULTS === 'yes' && $this->dsParamLIMIT >= 0 ? $this->dsParamLIMIT : null),
0 ignored issues
show
Coding Style introduced by
Inline shorthand IF statement requires brackets around comparison
Loading history...
576
            $where,
577
            $joins,
578
            $group,
579
            (!$include_pagination_element ? true : false),
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $include_pagination_element does not seem to be defined for all execution paths leading up to this point.
Loading history...
Coding Style introduced by
Inline shorthand IF statement requires brackets around comparison
Loading history...
580
            true,
581
            array_unique($datasource_schema)
582
        );
583
584
        /**
585
         * Immediately after building entries allow modification of the Data Source entries array
586
         *
587
         * @delegate DataSourceEntriesBuilt
588
         * @param string $context
589
         * '/frontend/'
590
         * @param Datasource $datasource
591
         * @param array $entries
592
         * @param array $filters
593
         */
594
        Symphony::ExtensionManager()->notifyMembers('DataSourceEntriesBuilt', '/frontend/', array(
595
            'datasource' => &$this,
596
            'entries' => &$entries,
597
            'filters' => $this->dsParamFILTERS
598
        ));
599
600
        $entries_per_page = ($this->dsParamPAGINATERESULTS === 'yes' && isset($this->dsParamLIMIT) && $this->dsParamLIMIT >= 0 ? $this->dsParamLIMIT : $entries['total-entries']);
0 ignored issues
show
Coding Style introduced by
Inline shorthand IF statement requires brackets around comparison
Loading history...
601
602
        if (($entries['total-entries'] <= 0 || $include_pagination_element === true) && (!is_array($entries['records']) || empty($entries['records'])) || $this->dsParamSTARTPAGE == '0') {
0 ignored issues
show
introduced by
Consider adding parentheses for clarity. Current Interpretation: ($entries['total-entries...dsParamSTARTPAGE == '0', Probably Intended Meaning: $entries['total-entries'...sParamSTARTPAGE == '0')
Loading history...
603
            if ($this->dsParamREDIRECTONEMPTY === 'yes') {
0 ignored issues
show
Bug Best Practice introduced by
The property dsParamREDIRECTONEMPTY does not exist on SectionDatasource. Did you maybe forget to declare it?
Loading history...
604
                throw new FrontendPageNotFoundException;
605
            }
606
607
            $this->_force_empty_result = false;
608
            $result = $this->emptyXMLSet();
609
            $result->prependChild($sectioninfo);
610
611
            if ($include_pagination_element) {
612
                $pagination_element = General::buildPaginationElement(0, 0, $entries_per_page);
613
614
                if ($pagination_element instanceof XMLElement && $result instanceof XMLElement) {
0 ignored issues
show
introduced by
$result is always a sub-type of XMLElement.
Loading history...
615
                    $result->prependChild($pagination_element);
616
                }
617
            }
618
        } else {
619
            if (!$this->_param_output_only) {
620
                $result->appendChild($sectioninfo);
621
622
                if ($include_pagination_element) {
623
                    $pagination_element = General::buildPaginationElement(
624
                        $entries['total-entries'],
625
                        $entries['total-pages'],
626
                        $entries_per_page,
627
                        ($this->dsParamPAGINATERESULTS === 'yes' && $this->dsParamSTARTPAGE > 0 ? $this->dsParamSTARTPAGE : 1)
0 ignored issues
show
Coding Style introduced by
Inline shorthand IF statement requires brackets around comparison
Loading history...
628
                    );
629
630
                    if ($pagination_element instanceof XMLElement && $result instanceof XMLElement) {
0 ignored issues
show
introduced by
$result is always a sub-type of XMLElement.
Loading history...
631
                        $result->prependChild($pagination_element);
632
                    }
633
                }
634
            }
635
636
            // If this datasource has a Limit greater than 0 or the Limit is not set
637
            if (!isset($this->dsParamLIMIT) || $this->dsParamLIMIT > 0) {
638
                if (!isset($this->dsParamASSOCIATEDENTRYCOUNTS) || $this->dsParamASSOCIATEDENTRYCOUNTS === 'yes') {
639
                    $this->_associated_sections = $section->fetchChildAssociations();
0 ignored issues
show
Bug Best Practice introduced by
The property _associated_sections does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
640
                }
641
642
                // If the datasource require's GROUPING
643
                if (isset($this->dsParamGROUP)) {
644
                    self::$_fieldPool[$this->dsParamGROUP] = FieldManager::fetch($this->dsParamGROUP);
645
646
                    if (self::$_fieldPool[$this->dsParamGROUP] == null) {
647
                        throw new SymphonyErrorPage(vsprintf("The field used for grouping '%s' cannot be found.", $this->dsParamGROUP));
648
                    }
649
650
                    $groups = self::$_fieldPool[$this->dsParamGROUP]->groupRecords($entries['records']);
651
652
                    foreach ($groups as $element => $group) {
653
                        foreach ($group as $g) {
654
                            $result->appendChild(
655
                                $this->processRecordGroup($element, $g)
656
                            );
657
                        }
658
                    }
659
                } else {
660
                    if (isset($entries['records'][0])) {
661
                        $data = $entries['records'][0]->getData();
662
                        $pool = FieldManager::fetch(array_keys($data));
663
                        self::$_fieldPool += $pool;
664
                    }
665
666
                    foreach ($entries['records'] as $entry) {
667
                        $xEntry = $this->processEntry($entry);
668
669
                        if ($xEntry instanceof XMLElement) {
670
                            $result->appendChild($xEntry);
671
                        }
672
                    }
673
                }
674
            }
675
        }
676
677
        $param_pool = $this->_param_pool;
678
679
        return $result;
680
    }
681
}
682