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.
Test Failed
Pull Request — 3.0.x (#2836)
by Nicolas
04:14
created

SectionDatasource::setAssociatedEntryCounts()   C

Complexity

Conditions 8
Paths 5

Size

Total Lines 22
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 8
eloc 13
c 2
b 0
f 0
nc 5
nop 2
dl 0
loc 22
rs 6.6037
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 = (new FieldManager)
99
                    ->select()
100
                    ->fields(array_keys($data))
101
                    ->execute()
102
                    ->rowsIndexedByColumn('id');
103
                self::$_fieldPool += $pool;
104
            }
105
106
            foreach ($group['records'] as $entry) {
107
                $xEntry = $this->processEntry($entry);
108
109
                if ($xEntry instanceof XMLElement) {
110
                    $xGroup->appendChild($xEntry);
111
                }
112
            }
113
        }
114
115
        if (is_array($group['groups']) && !empty($group['groups'])) {
116
            foreach ($group['groups'] as $element => $group) {
0 ignored issues
show
introduced by
$element is overwriting one of the parameters of this function.
Loading history...
117
                foreach ($group as $g) {
118
                    $xGroup->appendChild(
119
                        $this->processRecordGroup($element, $g)
120
                    );
121
                }
122
            }
123
        }
124
125
        if (!$this->_param_output_only) {
126
            return $xGroup;
127
        }
128
    }
129
130
    /**
131
     * Given an Entry object, this function will generate an XML representation
132
     * of the Entry to be returned. It will also add any parameters selected
133
     * by this datasource to the parameter pool.
134
     *
135
     * @param Entry $entry
136
     * @throws Exception
137
     * @return XMLElement|boolean
138
     *  Returns boolean when only parameters are to be returned.
139
     */
140
    public function processEntry(Entry $entry)
141
    {
142
        $data = $entry->getData();
143
144
        $xEntry = new XMLElement('entry');
145
        $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

145
        $xEntry->setAttribute('id', /** @scrutinizer ignore-type */ $entry->get('id'));
Loading history...
146
147
        if (!empty($this->_associated_sections)) {
148
            $this->setAssociatedEntryCounts($xEntry, $entry);
149
        }
150
151
        if ($this->_can_process_system_parameters) {
152
            $this->processSystemParameters($entry);
153
        }
154
155
        foreach ($data as $field_id => $values) {
156
            if (!isset(self::$_fieldPool[$field_id]) || !is_object(self::$_fieldPool[$field_id])) {
157
                self::$_fieldPool[$field_id] = (new FieldManager)->select()->field($field_id)->execute()->next();
158
            }
159
160
            $this->processOutputParameters($entry, $field_id, $values);
161
162
            if (!$this->_param_output_only) {
163
                foreach ($this->dsParamINCLUDEDELEMENTS as $handle) {
164
                    list($handle, $mode) = preg_split('/\s*:\s*/', $handle, 2);
165
166
                    if (self::$_fieldPool[$field_id]->get('element_name') == $handle) {
167
                        try {
168
                            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...
169
                        } catch (Exception $ex) {
170
                            if (Symphony::Log()) {
171
                                Symphony::Log()->pushExceptionToLog($ex, true);
172
                            }
173
                            $this->appendFormattedError($handle, $xEntry, $ex);
174
                        } catch (Throwable $ex) {
175
                            if (Symphony::Log()) {
176
                                Symphony::Log()->pushExceptionToLog($ex, true);
177
                            }
178
                            $this->appendFormattedError($handle, $xEntry, $ex);
179
                        }
180
                    }
181
                }
182
            }
183
        }
184
185
        if ($this->_param_output_only) {
186
            return true;
187
        }
188
189
        // This is deprecated and will be removed in Symphony 3.0.0
190
        if (in_array('system:date', $this->dsParamINCLUDEDELEMENTS)) {
191
            if (Symphony::Log()) {
192
                Symphony::Log()->pushDeprecateWarningToLog('system:date', 'system:creation-date` or `system:modification-date', array(
193
                    'message-format' => __('The `%s` data source field is deprecated.')
194
                ));
195
            }
196
            $xDate = new XMLElement('system-date');
197
            $xDate->appendChild(
198
                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 string|XMLElement, 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

198
                /** @scrutinizer ignore-type */ General::createXMLDateObject(
Loading history...
199
                    DateTimeObj::get('U', $entry->get('creation_date')),
0 ignored issues
show
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

199
                    DateTimeObj::get('U', /** @scrutinizer ignore-type */ $entry->get('creation_date')),
Loading history...
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

199
                    /** @scrutinizer ignore-type */ DateTimeObj::get('U', $entry->get('creation_date')),
Loading history...
200
                    'created'
201
                )
202
            );
203
            $xDate->appendChild(
204
                General::createXMLDateObject(
205
                    DateTimeObj::get('U', $entry->get('modification_date')),
206
                    'modified'
207
                )
208
            );
209
            $xEntry->appendChild($xDate);
210
        }
211
212
        return $xEntry;
213
    }
214
215
    /**
216
     * Given an handle, it will create a XMLElement from its value.
217
     * The Throwable's message will be put into an error node.
218
     * The newly created XMLElement will then be appended to the $xEntry XMLElement.
219
     *
220
     * @param string $handle
221
     *  The name of the new XMLElement
222
     * @param XMLElement $xEntry
223
     *  The XMLElement to append a child intro
224
     * @param Throwable $ex
225
     *  The Throwable's message to use
226
     * @return void
227
     */
228
    private function appendFormattedError($handle, XMLElement &$xEntry, $ex)
229
    {
230
        $xmlField = new XMLElement($handle);
231
        $xmlField->appendChild(new XMLElement('error', General::wrapInCDATA($ex->getMessage())));
232
        $xEntry->appendChild($xmlField);
233
    }
234
235
    /**
236
     * An entry may be associated to other entries from various fields through
237
     * the section associations. This function will set the number of related
238
     * entries as attributes to the main `<entry>` element grouped by the
239
     * related entry's section.
240
     *
241
     * @param XMLElement $xEntry
242
     *  The <entry> XMLElement that the associated section counts will
243
     *  be set on
244
     * @param Entry $entry
245
     *  The current entry object
246
     * @throws Exception
247
     */
248
    public function setAssociatedEntryCounts(XMLElement &$xEntry, Entry $entry)
249
    {
250
        $associated_entry_counts = $entry->fetchAllAssociatedEntryCounts($this->_associated_sections);
251
252
        if (!empty($associated_entry_counts)) {
253
            foreach ($associated_entry_counts as $section_id => $fields) {
254
                foreach ($this->_associated_sections as $section) {
255
                    if ($section['id'] != $section_id) {
256
                        continue;
257
                    }
258
259
                    // For each related field show the count (#2083)
260
                    foreach ($fields as $field_id => $count) {
261
                        $field_handle = FieldManager::fetchHandleFromID($field_id);
262
                        $section_handle = $section['handle'];
263
                        // Make sure attribute does not begin with a digit
264
                        // @deprecated This needs to be removed in Symphony 4.0.0
265
                        if (preg_match('/^[0-9]/', $section_handle)) {
266
                            $section_handle = 'x-' . $section_handle;
267
                        }
268
                        if ($field_handle) {
269
                            $xEntry->setAttribute($section_handle . '-' . $field_handle, (string)$count);
270
                        }
271
                    }
272
                }
273
            }
274
        }
275
    }
276
277
    /**
278
     * Given an Entry object, this function will iterate over the `dsParamPARAMOUTPUT`
279
     * setting to see any of the Symphony system parameters need to be set.
280
     * The current system parameters supported are `system:id`, `system:author`,
281
     * `system:creation-date` and `system:modification-date`.
282
     * If these parameters are found, the result is added
283
     * to the `$param_pool` array using the key, `ds-datasource-handle.parameter-name`
284
     * For the moment, this function also supports the pre Symphony 2.3 syntax,
285
     * `ds-datasource-handle` which did not support multiple parameters.
286
     *
287
     * @param Entry $entry
288
     *  The Entry object that contains the values that may need to be added
289
     *  into the parameter pool.
290
     */
291
    public function processSystemParameters(Entry $entry)
292
    {
293
        if (!isset($this->dsParamPARAMOUTPUT)) {
294
            return;
295
        }
296
297
        // Support the legacy parameter `ds-datasource-handle`
298
        $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...
299
300
        foreach ($this->dsParamPARAMOUTPUT as $param) {
301
            // The new style of paramater is `ds-datasource-handle.field-handle`
302
            $param_key = $key . '.' . str_replace(':', '-', $param);
303
304
            if ($param === 'system:id') {
305
                $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...
306
307
            } elseif ($param === 'system:author') {
308
                $this->_param_pool[$param_key][] = $entry->get('author_id');
309
310
            } elseif ($param === 'system:creation-date' || $param === 'system:date') {
311
                if ($param === 'system:date' && Symphony::Log()) {
312
                    Symphony::Log()->pushDeprecateWarningToLog('system:date', 'system:creation-date', array(
313
                        'message-format' => __('The `%s` data source output parameter is deprecated.')
314
                    ));
315
                }
316
                $this->_param_pool[$param_key][] = $entry->get('creation_date');
317
318
            } elseif ($param === 'system:modification-date') {
319
                $this->_param_pool[$param_key][] = $entry->get('modification_date');
320
321
            }
322
        }
323
    }
324
325
    /**
326
     * Given an Entry object, a `$field_id` and an array of `$data`, this
327
     * function iterates over the `dsParamPARAMOUTPUT` and will call the
328
     * field's (identified by `$field_id`) `getParameterPoolValue` function
329
     * to add parameters to the `$this->_param_pool`.
330
     *
331
     * @param Entry $entry
332
     * @param integer $field_id
333
     * @param array $data
334
     */
335
    public function processOutputParameters(Entry $entry, $field_id, array $data)
336
    {
337
        if (!isset($this->dsParamPARAMOUTPUT)) {
338
            return;
339
        }
340
341
        // Support the legacy parameter `ds-datasource-handle`
342
        $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...
343
344
        foreach ($this->dsParamPARAMOUTPUT as $param) {
345
            if (self::$_fieldPool[$field_id]->get('element_name') !== $param) {
346
                continue;
347
            }
348
349
            // The new style of parameter is `ds-datasource-handle.field-handle`
350
            $param_key = $key . '.' . str_replace(':', '-', $param);
351
352
            if (!isset($this->_param_pool[$param_key]) || !is_array($this->_param_pool[$param_key])) {
353
                $this->_param_pool[$param_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...
354
            }
355
356
            try {
357
                $param_pool_values = self::$_fieldPool[$field_id]->getParameterPoolValue($data, $entry->get('id'));
358
            } catch (Exception $ex) {
359
                if (Symphony::Log()) {
360
                    Symphony::Log()->pushExceptionToLog($ex, true);
361
                }
362
                $param_pool_values = ['error' => $ex->getMessage()];
363
            } catch (Throwable $ex) {
364
                if (Symphony::Log()) {
365
                    Symphony::Log()->pushExceptionToLog($ex, true);
366
                }
367
                $param_pool_values = ['error' => $ex->getMessage()];
368
            }
369
370
            if (is_array($param_pool_values)) {
371
                $this->_param_pool[$param_key] = array_merge($param_pool_values, $this->_param_pool[$param_key]);
372
373
            } elseif (!is_null($param_pool_values)) {
374
                $this->_param_pool[$param_key][] = $param_pool_values;
375
376
            }
377
        }
378
    }
379
380
    /**
381
     * This function iterates over `dsParamFILTERS` and appends the relevant
382
     * where and join operations.
383
     * This SQL is generated with the Field's query builder.
384
     *
385
     * @see Field::getEntryQueryFieldAdapter()
386
     * @param EntryQuery $entryQuery
387
     * @throws Exception
388
     */
389
    public function processFilters(&$entryQuery)
390
    {
391
        if (!is_array($this->dsParamFILTERS) || empty($this->dsParamFILTERS)) {
392
            return;
393
        }
394
395
        $pool = (new FieldManager)
396
            ->select()
397
            ->fields(array_filter(array_keys($this->dsParamFILTERS), 'is_numeric'))
398
            ->execute()
399
            ->rowsIndexedByColumn('id');
400
        self::$_fieldPool += $pool;
401
402
        foreach ($this->dsParamFILTERS as $field_id => $filter) {
403
            if ((is_array($filter) && empty($filter)) || trim($filter) == '') {
404
                continue;
405
            }
406
407
            if (!is_array($filter)) {
408
                $filter_type = Datasource::determineFilterType($filter);
409
                $value = Datasource::splitFilter($filter_type, $filter);
410
            } else {
411
                $filter_type = Datasource::FILTER_OR;
412
                $value = $filter;
413
            }
414
415
            if (!in_array($field_id, self::$_system_parameters) && $field_id != 'id' && !(self::$_fieldPool[$field_id] instanceof Field)) {
416
                throw new Exception(
417
                    __(
418
                        'Error creating field object with id %1$d, for filtering in data source %2$s. Check this field exists.',
419
                        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...
420
                    )
421
                );
422
            }
423
424
            // Support system:id as well as the old 'id'. #1691
425
            if ($field_id === 'system:id' || $field_id === 'id') {
426
                if ($field_id === 'id' && Symphony::Log()) {
427
                    Symphony::Log()->pushDeprecateWarningToLog('id', 'system:id', array(
428
                        'message-format' => __('The `%s` data source filter is deprecated.')
429
                    ));
430
                }
431
                $op = $filter_type === Datasource::FILTER_AND ? 'and' : 'or';
432
                $entryQuery->filter('system:id', $value, $op);
433
            // Dates
434
            } elseif ($field_id === 'system:creation-date' || $field_id === 'system:modification-date' || $field_id === 'system:date') {
435
                if ($field_id === 'system:date' && Symphony::Log()) {
436
                    Symphony::Log()->pushDeprecateWarningToLog('system:date', 'system:creation-date` or `system:modification-date', array(
437
                        'message-format' => __('The `%s` data source filter is deprecated.')
438
                    ));
439
                    $field_id = 'system:creation-date';
440
                }
441
                $op = $filter_type === Datasource::FILTER_AND ? 'and' : 'or';
442
                $entryQuery->filter($field_id, $value, $op);
443
            // Field with EQFA
444
            } elseif (self::$_fieldPool[$field_id]->getEntryQueryFieldAdapter()) {
445
                $op = $filter_type === Datasource::FILTER_AND ? 'and' : 'or';
446
                $entryQuery->filter(self::$_fieldPool[$field_id], $value, $op);
447
            // Compat layer with the old API
448
            } else {
449
                $where = '';
450
                $joins = '';
451
                if (!self::$_fieldPool[$field_id]->buildDSRetrievalSQL($value, $joins, $where, ($filter_type == Datasource::FILTER_AND ? true : false))) {
452
                    $this->_force_empty_result = true;
453
                    return;
454
                }
455
456
                if ($joins) {
457
                    $joins = $entryQuery->replaceTablePrefix($joins);
458
                    $entryQuery->unsafe()->unsafeAppendSQLPart('join', $joins);
459
                }
460
                if ($where) {
461
                    $where = $entryQuery->replaceTablePrefix($where);
462
                    $wherePrefix = $entryQuery->containsSQLParts('where') ? '' : 'WHERE 1 = 1';
463
                    $entryQuery->unsafe()->unsafeAppendSQLPart('where', "$wherePrefix $where");
464
                }
465
466
                if (self::$_fieldPool[$field_id]->requiresSQLGrouping()) {
467
                    $entryQuery->distinct();
468
                }
469
            }
470
        }
471
    }
472
473
    public function execute(array &$param_pool = null)
474
    {
475
        $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...
476
        $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...
477
        $requiresPagination = (!isset($this->dsParamPAGINATERESULTS) ||
478
            $this->dsParamPAGINATERESULTS === 'yes')
0 ignored issues
show
Bug Best Practice introduced by
The property dsParamPAGINATERESULTS does not exist on SectionDatasource. Did you maybe forget to declare it?
Loading history...
479
            && isset($this->dsParamLIMIT) && General::intval($this->dsParamLIMIT) >= 0;
480
481
        $section = (new SectionManager)
482
            ->select()
483
            ->section($this->getSource())
484
            ->execute()
485
            ->next();
486
487
        if (!$section) {
0 ignored issues
show
introduced by
$section is of type Section, thus it always evaluated to true.
Loading history...
488
            $about = $this->about();
489
            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);
490
        }
491
492
        $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

492
        $sectioninfo = new XMLElement('section', General::sanitize(/** @scrutinizer ignore-type */ $section->get('name')), array(
Loading history...
493
            'id' => $section->get('id'),
494
            'handle' => $section->get('handle')
495
        ));
496
497
        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...
498
            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...
499
                throw new FrontendPageNotFoundException;
500
            }
501
502
            $this->_force_empty_result = false; //this is so the section info element doesn't disappear.
503
            $error = new XMLElement('error', __("Data source not executed, required parameter is missing."), array(
504
                '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...
505
            ));
506
            $result->appendChild($error);
507
            $result->prependChild($sectioninfo);
508
509
            return $result;
510
        }
511
512
        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...
513
            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...
514
                throw new FrontendPageNotFoundException;
515
            }
516
517
            $this->_negate_result = false; //this is so the section info element doesn't disappear.
518
            $result = $this->negateXMLSet();
519
            $result->prependChild($sectioninfo);
520
521
            return $result;
522
        }
523
524
        if (is_array($this->dsParamINCLUDEDELEMENTS)) {
525
            $include_pagination_element = in_array('system:pagination', $this->dsParamINCLUDEDELEMENTS);
526
        } else {
527
            $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...
528
        }
529
530
        if (isset($this->dsParamPARAMOUTPUT) && !is_array($this->dsParamPARAMOUTPUT)) {
531
            $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...
532
        }
533
534
        $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...
535
536
        // combine `INCLUDEDELEMENTS`, `PARAMOUTPUT` and `GROUP` into an
537
        // array of field handles to optimise the `EntryManager` queries
538
        $datasource_schema = $this->dsParamINCLUDEDELEMENTS;
539
540
        if (is_array($this->dsParamPARAMOUTPUT)) {
541
            $datasource_schema = array_merge($datasource_schema, $this->dsParamPARAMOUTPUT);
542
        }
543
544
        if ($this->dsParamGROUP) {
0 ignored issues
show
Bug introduced by
The property dsParamGROUP does not exist on SectionDatasource. Did you mean dsParamSORT?
Loading history...
545
            $datasource_schema[] = FieldManager::fetchHandleFromID($this->dsParamGROUP);
546
        }
547
548
        // Create our query object
549
        $entriesQuery = (new EntryManager)
550
            ->select($datasource_schema)
551
            ->section($this->getSource());
552
553
        // Process Filters
554
        $this->processFilters($entriesQuery);
555
556
        // Process Sorting
557
        $entriesQuery->sort((string)$this->dsParamSORT, $this->dsParamORDER);
558
559
        // Configure pagination in the query
560
        if ($requiresPagination) {
561
            $entriesQuery->paginate($this->dsParamSTARTPAGE, $this->dsParamLIMIT);
562
        }
563
564
        // Execute
565
        $pagination = $entriesQuery->execute()->pagination();
566
        $entries = $pagination->rows();
567
568
        /**
569
         * Immediately after building entries allow modification of the Data Source entries array
570
         *
571
         * @delegate DataSourceEntriesBuilt
572
         * @param string $context
573
         * '/frontend/'
574
         * @param Datasource $datasource
575
         * @param array $entries
576
         * @param array $filters
577
         */
578
        Symphony::ExtensionManager()->notifyMembers('DataSourceEntriesBuilt', '/frontend/', array(
579
            'datasource' => &$this,
580
            'entries' => &$entries,
581
            'filters' => $this->dsParamFILTERS
582
        ));
583
584
        $entries_per_page = $requiresPagination
585
            ? $pagination->pageSize()
586
            : $pagination->totalEntries();
587
588
        if (empty($entries)) {
589
            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...
590
                throw new FrontendPageNotFoundException;
591
            }
592
593
            $this->_force_empty_result = false;
594
            $result = $this->emptyXMLSet();
595
            $result->prependChild($sectioninfo);
596
597
            if ($include_pagination_element) {
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...
598
                $pagination_element = General::buildPaginationElement(0, 0, $entries_per_page);
599
600
                if ($pagination_element instanceof XMLElement && $result instanceof XMLElement) {
0 ignored issues
show
introduced by
$result is always a sub-type of XMLElement.
Loading history...
601
                    $result->prependChild($pagination_element);
602
                }
603
            }
604
        } else {
605
            if (!$this->_param_output_only) {
606
                $result->appendChild($sectioninfo);
607
608
                if ($include_pagination_element) {
609
                    $pagination_element = General::buildPaginationElement(
610
                        $pagination->totalEntries(),
611
                        $pagination->totalPages(),
612
                        $entries_per_page,
613
                        $pagination->currentPage()
614
                    );
615
616
                    if ($pagination_element instanceof XMLElement && $result instanceof XMLElement) {
0 ignored issues
show
introduced by
$result is always a sub-type of XMLElement.
Loading history...
617
                        $result->prependChild($pagination_element);
618
                    }
619
                }
620
            }
621
622
            if (!isset($this->dsParamASSOCIATEDENTRYCOUNTS) || $this->dsParamASSOCIATEDENTRYCOUNTS === 'yes') {
0 ignored issues
show
Bug Best Practice introduced by
The property dsParamASSOCIATEDENTRYCOUNTS does not exist on SectionDatasource. Did you maybe forget to declare it?
Loading history...
623
                $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...
624
            }
625
626
            // If the datasource require's GROUPING
627
            if (isset($this->dsParamGROUP)) {
628
                if (!isset(self::$_fieldPool[$this->dsParamGROUP])) {
629
                    self::$_fieldPool[$this->dsParamGROUP] = (new FieldManager)
630
                        ->select()
631
                        ->field($this->dsParamGROUP)
632
                        ->execute()
633
                        ->next();
634
                }
635
                if (self::$_fieldPool[$this->dsParamGROUP] == null) {
636
                    throw new SymphonyErrorPage(vsprintf("The field used for grouping '%s' cannot be found.", $this->dsParamGROUP));
637
                }
638
639
                $groups = self::$_fieldPool[$this->dsParamGROUP]->groupRecords($entries);
640
641
                foreach ($groups as $element => $group) {
642
                    foreach ($group as $g) {
643
                        $result->appendChild(
644
                            $this->processRecordGroup($element, $g)
645
                        );
646
                    }
647
                }
648
            } else {
649
                if (isset($entries[0])) {
650
                    $data = $entries[0]->getData();
651
                    if (!empty($data)) {
652
                        $pool = (new FieldManager)
653
                            ->select()
654
                            ->fields(array_keys($data))
655
                            ->execute()
656
                            ->rowsIndexedByColumn('id');
657
                        self::$_fieldPool += $pool;
658
                    }
659
                }
660
661
                foreach ($entries as $entry) {
662
                    $xEntry = $this->processEntry($entry);
663
664
                    if ($xEntry instanceof XMLElement) {
665
                        $result->appendChild($xEntry);
666
                    }
667
                }
668
            }
669
        }
670
671
        $param_pool = $this->_param_pool;
672
673
        return $result;
674
    }
675
}
676