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.
Passed
Push — master ( 2240c6...8ae5ca )
by Nicolas
04:17
created

EntryManager::fetchByPage()   C

Complexity

Conditions 7
Paths 6

Size

Total Lines 41
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 28
c 0
b 0
f 0
nc 6
nop 9
dl 0
loc 41
rs 6.7272

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
/**
4
 * @package toolkit
5
 */
6
/**
7
 * The `EntryManager` is responsible for all `Entry` objects in Symphony.
8
 * Entries are stored in the database in a cluster of tables. There is a
9
 * parent entry row stored in `tbl_entries` and then each field's data is
10
 * stored in a separate table, `tbl_entries_data_{field_id}`. Where Field ID
11
 * is generated when the Section is saved. This Manager provides basic
12
 * add, edit, delete and fetching methods for Entries.
13
 */
14
15
class EntryManager
16
{
17
    /**
18
     * The Field ID that will be used to sort when fetching Entries, defaults
19
     * to null, which implies the Entry ID (id column in `tbl_entries`).
20
     * To order by core fields, use one of
21
     * 'system:creation-date', 'system:modification-date', 'system:id'.
22
     * @var integer|string
23
     */
24
    protected static $_fetchSortField = null;
25
26
    /**
27
     * The direction that entries should be sorted in, available options are
28
     * RAND, ASC or DESC. Defaults to null, which implies ASC
29
     * @var string
30
     */
31
    protected static $_fetchSortDirection = null;
32
33
    /**
34
     * Setter function for the default sorting direction of the Fetch
35
     * function. Available options are RAND, ASC or DESC.
36
     *
37
     * @param string $direction
38
     *  The direction that entries should be sorted in, available options
39
     *  are RAND, ASC or DESC.
40
     */
41
    public static function setFetchSortingDirection($direction)
42
    {
43
        $direction = strtoupper($direction);
44
45
        if ($direction == 'RANDOM') {
46
            $direction = 'RAND';
47
        }
48
49
        self::$_fetchSortDirection = (in_array($direction, array('RAND', 'ASC', 'DESC')) ? $direction : null);
50
    }
51
52
    /**
53
     * Sets the field to applying the sorting direction on when fetching
54
     * entries
55
     *
56
     * @param integer $field_id
57
     *  The ID of the Field that should be sorted on
58
     */
59
    public static function setFetchSortingField($field_id)
60
    {
61
        self::$_fetchSortField = $field_id;
62
    }
63
64
    /**
65
     * Convenience function that will set sorting field and direction
66
     * by calling `setFetchSortingField()` & `setFetchSortingDirection()`
67
     *
68
     * @see toolkit.EntryManager#setFetchSortingField()
69
     * @see toolkit.EntryManager#setFetchSortingDirection()
70
     * @param integer $field_id
71
     *  The ID of the Field that should be sorted on
72
     * @param string $direction
73
     *  The direction that entries should be sorted in, available options
74
     *  are RAND, ASC or DESC. Defaults to ASC
75
     */
76
    public static function setFetchSorting($field_id, $direction = 'ASC')
77
    {
78
        self::setFetchSortingField($field_id);
79
        self::setFetchSortingDirection($direction);
80
    }
81
82
    /**
83
     * Returns an object representation of the sorting for the
84
     * EntryManager, with the field and direction provided
85
     *
86
     * @return StdClass
87
     */
88
    public static function getFetchSorting()
89
    {
90
        return (object)array(
91
            'field' => self::$_fetchSortField,
92
            'direction' => self::$_fetchSortDirection
93
        );
94
    }
95
96
    /**
97
     * Executes the SQL queries need to save a field's data for the specified
98
     * entry id.
99
     *
100
     * It first locks the table for writes, it then deletes existing data and then
101
     * it inserts a new row for the data. Errors are discarded and the lock is
102
     * released, if it was acquired.
103
     *
104
     * @param int $entry_id
105
     *  The entry id to save the data for
106
     * @param int $field_id
107
     *  The field id to save the data for
108
     * @param array $field
109
     *  The field data to save
110
     */
111
    protected static function saveFieldData($entry_id, $field_id, $field)
112
    {
113
        // Check that we have a field id
114
        if (empty($field_id)) {
115
            return;
116
        }
117
118
        // Ignore parameter when not an array
119
        if (!is_array($field)) {
0 ignored issues
show
introduced by
The condition is_array($field) is always true.
Loading history...
120
            $field = array();
121
        }
122
123
        $did_lock = false;
124
        $exception = null;
125
        try {
126
127
            // Check if table exists
128
            $table_name = 'tbl_entries_data_' . General::intval($field_id);
129
            if (!Symphony::Database()->tableExists($table_name)) {
130
                return;
131
            }
132
133
            // Lock the table for write
134
            $did_lock = Symphony::Database()->query("LOCK TABLES `$table_name` WRITE");
135
136
            // Delete old data
137
            Symphony::Database()->delete($table_name, sprintf("
138
                `entry_id` = %d", $entry_id
139
            ));
140
141
            // Insert new data
142
            $data = array(
143
                'entry_id' => $entry_id
144
            );
145
146
            $fields = array();
147
148
            foreach ($field as $key => $value) {
149
                if (is_array($value)) {
150
                    foreach ($value as $ii => $v) {
151
                        $fields[$ii][$key] = $v;
152
                    }
153
                } else {
154
                    $fields[max(0, count($fields) - 1)][$key] = $value;
155
                }
156
            }
157
158
            foreach ($fields as $index => $field_data) {
159
                $fields[$index] = array_merge($data, $field_data);
160
            }
161
162
            // Insert only if we have field data
163
            if (!empty($fields)) {
164
                Symphony::Database()->insert($fields, $table_name);
165
            }
166
        } catch (Exception $ex) {
167
            $exception = $ex;
168
            Symphony::Log()->pushExceptionToLog($ex, true);
169
        }
170
171
        if ($did_lock) {
172
            Symphony::Database()->query('UNLOCK TABLES');
173
        }
174
175
        if ($exception) {
176
            throw $exception;
177
        }
178
    }
179
180
    /**
181
     * Given an Entry object, iterate over all of the fields in that object
182
     * an insert them into their relevant entry tables.
183
     *
184
     * @see EntryManager::saveFieldData()
185
     * @param Entry $entry
186
     *  An Entry object to insert into the database
187
     * @throws DatabaseException
188
     * @return boolean
189
     */
190
    public static function add(Entry $entry)
191
    {
192
        $fields = $entry->get();
193
        Symphony::Database()->insert($fields, 'tbl_entries');
194
195
        if (!$entry_id = Symphony::Database()->getInsertID()) {
196
            return false;
197
        }
198
199
        // Iterate over all data for this entry
200
        foreach ($entry->getData() as $field_id => $field) {
201
            // Write data
202
            static::saveFieldData($entry_id, $field_id, $field);
203
        }
204
205
        $entry->set('id', $entry_id);
206
207
        return true;
208
    }
209
210
    /**
211
     * Update an existing Entry object given an Entry object
212
     *
213
     * @see EntryManager::saveFieldData()
214
     * @param Entry $entry
215
     *  An Entry object
216
     * @throws DatabaseException
217
     * @return boolean
218
     */
219
    public static function edit(Entry $entry)
220
    {
221
        // Update modification date and modification author.
222
        Symphony::Database()->update(
223
            array(
224
                'modification_author_id' => $entry->get('modification_author_id'),
225
                'modification_date' => $entry->get('modification_date'),
226
                'modification_date_gmt' => $entry->get('modification_date_gmt')
227
            ),
228
            'tbl_entries',
229
            sprintf(' `id` = %d', (int)$entry->get('id'))
230
        );
231
232
        // Iterate over all data for this entry
233
        foreach ($entry->getData() as $field_id => $field) {
234
            // Write data
235
            static::saveFieldData($entry->get('id'), $field_id, $field);
0 ignored issues
show
Bug introduced by
It seems like $entry->get('id') can also be of type array; however, parameter $entry_id of EntryManager::saveFieldData() 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

235
            static::saveFieldData(/** @scrutinizer ignore-type */ $entry->get('id'), $field_id, $field);
Loading history...
236
        }
237
238
        return true;
239
    }
240
241
    /**
242
     * Given an Entry ID, or an array of Entry ID's, delete all
243
     * data associated with this Entry using a Field's `entryDataCleanup()`
244
     * function, and then remove this Entry from `tbl_entries`. If the `$entries`
245
     * all belong to the same section, passing `$section_id` will improve
246
     * performance
247
     *
248
     * @param array|integer $entries
249
     *  An entry_id, or an array of entry id's to delete
250
     * @param integer $section_id (optional)
251
     *  If possible, the `$section_id` of the the `$entries`. This parameter
252
     *  should be left as null if the `$entries` array contains entry_id's for
253
     *  multiple sections.
254
     * @throws DatabaseException
255
     * @throws Exception
256
     * @return boolean
257
     */
258
    public static function delete($entries, $section_id = null)
259
    {
260
        $needs_data = true;
261
262
        if (!is_array($entries)) {
263
            $entries = array($entries);
264
        }
265
266
        // Get the section's schema
267
        if (!is_null($section_id)) {
268
            $section = SectionManager::fetch($section_id);
269
270
            if ($section instanceof Section) {
271
                $fields = $section->fetchFields();
272
                $data = array();
273
274
                foreach ($fields as $field) {
275
                    $reflection = new ReflectionClass($field);
276
                    // This field overrides the default implementation, so pass it data.
277
                    $data[$field->get('element_name')] = $reflection->getMethod('entryDataCleanup')->class == 'Field' ? false : true;
278
                }
279
280
                $data = array_filter($data);
281
282
                if (empty($data)) {
283
                    $needs_data = false;
284
                }
285
            }
286
        }
287
288
        // We'll split $entries into blocks of 2500 (random number)
289
        // and process the deletion in chunks.
290
        $chunks = array_chunk($entries, 2500);
291
292
        foreach ($chunks as $chunk) {
293
            $entry_list = implode("', '", $chunk);
294
295
            // If we weren't given a `section_id` we'll have to process individually
296
            // If we don't need data for any field, we can process the whole chunk
297
            // without building Entry objects, otherwise we'll need to build
298
            // Entry objects with data
299
            if (is_null($section_id) || !$needs_data) {
300
                $entries = $chunk;
301
            } elseif ($needs_data) {
302
                $entries = self::fetch($chunk, $section_id);
303
            }
304
305
            if ($needs_data) {
306
                foreach ($entries as $id) {
307
                    // Handles the case where `section_id` was not provided
308
                    if (is_null($section_id)) {
309
                        $e = self::fetch($id);
310
311
                        if (!is_array($e)) {
312
                            continue;
313
                        }
314
315
                        $e = current($e);
316
317
                        if (!$e instanceof Entry) {
318
                            continue;
319
                        }
320
321
                        // If we needed data, whole Entry objects will exist
322
                    } elseif ($needs_data) {
323
                        $e = $id;
324
                        $id = $e->get('id');
325
                    }
326
327
                    // Time to loop over it and send it to the fields.
328
                    // Note we can't rely on the `$fields` array as we may
329
                    // also be dealing with the case where `section_id` hasn't
330
                    // been provided
331
                    $entry_data = $e->getData();
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $e does not seem to be defined for all execution paths leading up to this point.
Loading history...
332
333
                    foreach ($entry_data as $field_id => $data) {
334
                        $field = FieldManager::fetch($field_id);
335
                        $field->entryDataCleanup($id, $data);
336
                    }
337
                }
338
            } else {
339
                foreach ($fields as $field) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $fields does not seem to be defined for all execution paths leading up to this point.
Loading history...
340
                    $field->entryDataCleanup($chunk);
341
                }
342
            }
343
344
            Symphony::Database()->delete('tbl_entries', " `id` IN ('$entry_list') ");
345
        }
346
347
        return true;
348
    }
349
350
    /**
351
     * This function will return an array of Entry objects given an ID or an array of ID's.
352
     * Do not provide `$entry_id` as an array if not specifying the `$section_id`. This function
353
     * is commonly passed custom SQL statements through the `$where` and `$join` parameters
354
     * that is generated by the fields of this section.
355
     *
356
     * @since Symphony 2.7.0 it will also call a new method on fields,
357
     * `buildSortingSelectSQL()`, to make sure fields can add ordering columns in
358
     * the SELECT clause. This is required on MySQL 5.7+ strict mode.
359
     *
360
     * @param integer|array $entry_id
361
     *  An array of Entry ID's or an Entry ID to return
362
     * @param integer $section_id
363
     *  The ID of the Section that these entries are contained in
364
     * @param integer $limit
365
     *  The limit of entries to return
366
     * @param integer $start
367
     *  The starting offset of the entries to return
368
     * @param string $where
369
     *  Any custom WHERE clauses. The tbl_entries alias is `e`
370
     * @param string $joins
371
     *  Any custom JOIN's
372
     * @param boolean $group
373
     *  Whether the entries need to be grouped by Entry ID or not
374
     * @param boolean $buildentries
375
     *  Whether to return an array of entry ID's or Entry objects. Defaults to
376
     *  true, which will return Entry objects
377
     * @param array $element_names
378
     *  Choose whether to get data from a subset of fields or all fields in a section,
379
     *  by providing an array of field names. Defaults to null, which will load data
380
     *  from all fields in a section.
381
     * @param boolean $enable_sort
382
     *  Defaults to true, if false this function will not apply any sorting
383
     * @throws Exception
384
     * @return array
385
     *  If `$buildentries` is true, this function will return an array of Entry objects,
386
     *  otherwise it will return an associative array of Entry data from `tbl_entries`
387
     */
388
    public static function fetch($entry_id = null, $section_id = null, $limit = null, $start = null, $where = null, $joins = null, $group = false, $buildentries = true, $element_names = null, $enable_sort = true)
389
    {
390
        $sort = null;
391
        $sortSelectClause = null;
392
393
        if (!$entry_id && !$section_id) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $section_id of type null|integer is loosely compared to false; this is ambiguous if the integer can be 0. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
394
            return array();
395
        }
396
397
        if (!$section_id) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $section_id of type null|integer is loosely compared to false; this is ambiguous if the integer can be 0. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
398
            $section_id = self::fetchEntrySectionID($entry_id);
0 ignored issues
show
Bug introduced by
It seems like $entry_id can also be of type array; however, parameter $entry_id of EntryManager::fetchEntrySectionID() 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

398
            $section_id = self::fetchEntrySectionID(/** @scrutinizer ignore-type */ $entry_id);
Loading history...
399
        }
400
401
        $section = SectionManager::fetch($section_id);
402
        if (!is_object($section)) {
403
            return array();
404
        }
405
406
        // SORTING
407
        // A single $entry_id doesn't need to be sorted on, or if it's explicitly disabled
408
        if ((!is_array($entry_id) && General::intval($entry_id) > 0) || !$enable_sort) {
409
            $sort = null;
410
411
        // Check for RAND first, since this works independently of any specific field
412
        } elseif (self::$_fetchSortDirection == 'RAND') {
413
            $sort = 'ORDER BY RAND() ';
414
415
        // Handle Creation Date or the old Date sorting
416
        } elseif (self::$_fetchSortField === 'system:creation-date' || self::$_fetchSortField === 'date') {
417
            $sort = sprintf('ORDER BY `e`.`creation_date_gmt` %s', self::$_fetchSortDirection);
418
419
        // Handle Modification Date sorting
420
        } elseif (self::$_fetchSortField === 'system:modification-date') {
421
            $sort = sprintf('ORDER BY `e`.`modification_date_gmt` %s', self::$_fetchSortDirection);
422
423
        // Handle sorting for System ID
424
        } elseif (self::$_fetchSortField == 'system:id' || self::$_fetchSortField == 'id') {
425
            $sort = sprintf('ORDER BY `e`.`id` %s', self::$_fetchSortDirection);
426
427
        // Handle when the sort field is an actual Field
428
        } elseif (self::$_fetchSortField && $field = FieldManager::fetch(self::$_fetchSortField)) {
0 ignored issues
show
Bug introduced by
It seems like self::_fetchSortField can also be of type string; however, parameter $id of FieldManager::fetch() does only seem to accept integer|array, 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

428
        } elseif (self::$_fetchSortField && $field = FieldManager::fetch(/** @scrutinizer ignore-type */ self::$_fetchSortField)) {
Loading history...
429
            if ($field->isSortable()) {
430
                $field->buildSortingSQL($joins, $where, $sort, self::$_fetchSortDirection);
431
                $sortSelectClause = $field->buildSortingSelectSQL($sort, self::$_fetchSortDirection);
432
            }
433
434
        // Handle if the section has a default sorting field
435
        } elseif ($section->getSortingField() && $field = FieldManager::fetch($section->getSortingField())) {
436
            if ($field->isSortable()) {
437
                $field->buildSortingSQL($joins, $where, $sort, $section->getSortingOrder());
438
                $sortSelectClause = $field->buildSortingSelectSQL($sort, $section->getSortingOrder());
439
            }
440
441
        // No sort specified, so just sort on system id
442
        } else {
443
            $sort = sprintf('ORDER BY `e`.`id` %s', self::$_fetchSortDirection);
444
        }
445
446
        if ($field && !$group) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $field does not seem to be defined for all execution paths leading up to this point.
Loading history...
447
            $group = $field->requiresSQLGrouping();
448
        }
449
450
        if ($entry_id && !is_array($entry_id)) {
451
            $entry_id = array($entry_id);
452
        }
453
454
        $sql = sprintf("
455
            SELECT %s`e`.`id`, `e`.section_id,
456
                `e`.`author_id`, `e`.`modification_author_id`,
457
                `e`.`creation_date` AS `creation_date`,
458
                `e`.`modification_date` AS `modification_date`
459
                %s
460
            FROM `tbl_entries` AS `e`
461
            %s
462
            WHERE 1
463
            %s
464
            %s
465
            %s
466
            %s
467
            %s
468
            ",
469
            $group ? 'DISTINCT ' : '',
470
            $sortSelectClause ? ', ' . $sortSelectClause : '',
471
            $joins,
472
            $entry_id ? "AND `e`.`id` IN ('".implode("', '", $entry_id)."') " : '',
0 ignored issues
show
Bug introduced by
It seems like $entry_id can also be of type integer; however, parameter $pieces of implode() does only seem to accept array, 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

472
            $entry_id ? "AND `e`.`id` IN ('".implode("', '", /** @scrutinizer ignore-type */ $entry_id)."') " : '',
Loading history...
473
            $section_id ? sprintf("AND `e`.`section_id` = %d", $section_id) : '',
474
            $where,
475
            $sort,
476
            $limit ? sprintf('LIMIT %d, %d', $start, $limit) : ''
477
        );
478
479
        $rows = Symphony::Database()->fetch($sql);
480
481
        // Create UNIX timestamps, as it has always been (Re: #2501)
482
        foreach ($rows as &$entry) {
483
            $entry['creation_date'] = DateTimeObj::get('U', $entry['creation_date']);
484
            $entry['modification_date'] = DateTimeObj::get('U', $entry['modification_date']);
485
        }
486
        unset($entry);
487
488
        return ($buildentries && (is_array($rows) && !empty($rows)) ? self::__buildEntries($rows, $section_id, $element_names) : $rows);
489
    }
490
491
    /**
492
     * Given an array of Entry data from `tbl_entries` and a section ID, return an
493
     * array of Entry objects. For performance reasons, it's possible to pass an array
494
     * of field handles via `$element_names`, so that only a subset of the section schema
495
     * will be queried. This function currently only supports Entry from one section at a
496
     * time.
497
     *
498
     * @param array $rows
499
     *  An array of Entry data from `tbl_entries` including the Entry ID, Entry section,
500
     *  the ID of the Author who created the Entry, and a Unix timestamp of creation
501
     * @param integer $section_id
502
     *  The section ID of the entries in the `$rows`
503
     * @param array $element_names
504
     *  Choose whether to get data from a subset of fields or all fields in a section,
505
     *  by providing an array of field names. Defaults to null, which will load data
506
     *  from all fields in a section.
507
     * @throws DatabaseException
508
     * @return array
509
     *  An array of Entry objects
510
     */
511
    public static function __buildEntries(array $rows, $section_id, $element_names = null)
512
    {
513
        $entries = array();
514
515
        if (empty($rows)) {
516
            return $entries;
517
        }
518
519
        $schema = FieldManager::fetchFieldIDFromElementName($element_names, $section_id);
520
521
        if (is_int($schema)) {
522
            $schema = array($schema);
523
        }
524
525
        $raw = array();
526
        $rows_string = '';
527
528
        // Append meta data:
529
        foreach ($rows as $entry) {
530
            $raw[$entry['id']]['meta'] = $entry;
531
            $rows_string .= $entry['id'] . ',';
532
        }
533
534
        $rows_string = trim($rows_string, ',');
535
536
        // Append field data:
537
        if (is_array($schema)) {
538
            foreach ($schema as $field_id) {
539
                try {
540
                    $row = Symphony::Database()->fetch("SELECT * FROM `tbl_entries_data_{$field_id}` WHERE `entry_id` IN ($rows_string) ORDER BY `id` ASC");
541
                } catch (Exception $e) {
542
                    // No data due to error
543
                    continue;
544
                }
545
546
                if (!is_array($row) || empty($row)) {
547
                    continue;
548
                }
549
550
                foreach ($row as $r) {
551
                    $entry_id = $r['entry_id'];
552
553
                    unset($r['id']);
554
                    unset($r['entry_id']);
555
556
                    if (!isset($raw[$entry_id]['fields'][$field_id])) {
557
                        $raw[$entry_id]['fields'][$field_id] = $r;
558
                    } else {
559
                        foreach (array_keys($r) as $key) {
560
                            // If this field already has been set, we need to take the existing
561
                            // value and make it array, adding the current value to it as well
562
                            // There is a special check incase the the field's value has been
563
                            // purposely set to null in the database.
564
                            if (
565
                                (
566
                                    isset($raw[$entry_id]['fields'][$field_id][$key])
567
                                    || is_null($raw[$entry_id]['fields'][$field_id][$key])
568
                                )
569
                                && !is_array($raw[$entry_id]['fields'][$field_id][$key])
570
                            ) {
571
                                $raw[$entry_id]['fields'][$field_id][$key] = array(
572
                                    $raw[$entry_id]['fields'][$field_id][$key],
573
                                    $r[$key]
574
                                );
575
576
                                // This key/value hasn't been set previously, so set it
577
                            } elseif (!isset($raw[$entry_id]['fields'][$field_id][$key])) {
578
                                $raw[$entry_id]['fields'][$field_id] = array($r[$key]);
579
580
                                // This key has been set and it's an array, so just append
581
                                // this value onto the array
582
                            } else {
583
                                $raw[$entry_id]['fields'][$field_id][$key][] = $r[$key];
584
                            }
585
                        }
586
                    }
587
                }
588
            }
589
        }
590
591
        // Loop over the array of entry data and convert it to an array of Entry objects
592
        foreach ($raw as $entry) {
593
            $obj = self::create();
594
595
            $obj->set('id', $entry['meta']['id']);
596
            $obj->set('author_id', $entry['meta']['author_id']);
597
            $obj->set('modification_author_id', $entry['meta']['modification_author_id']);
598
            $obj->set('section_id', $entry['meta']['section_id']);
599
            $obj->set('creation_date', DateTimeObj::get('c', $entry['meta']['creation_date']));
600
601
            if (isset($entry['meta']['modification_date'])) {
602
                $obj->set('modification_date', DateTimeObj::get('c', $entry['meta']['modification_date']));
603
            } else {
604
                $obj->set('modification_date', $obj->get('creation_date'));
605
            }
606
607
            $obj->creationDate = $obj->get('creation_date');
0 ignored issues
show
Documentation Bug introduced by
It seems like $obj->get('creation_date') can also be of type array. However, the property $creationDate is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
Deprecated Code introduced by
The property Entry::$creationDate has been deprecated: Since Symphony 2.3.1, use $entry->get('creation_date') instead. This variable will be removed in Symphony 3.0 ( Ignorable by Annotation )

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

607
            /** @scrutinizer ignore-deprecated */ $obj->creationDate = $obj->get('creation_date');

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
608
609
            if (isset($entry['fields']) && is_array($entry['fields'])) {
610
                foreach ($entry['fields'] as $field_id => $data) {
611
                    $obj->setData($field_id, $data);
612
                }
613
            }
614
615
            $entries[] = $obj;
616
        }
617
618
        return $entries;
619
    }
620
621
622
    /**
623
     * Given an Entry ID, return the Section ID that it belongs to
624
     *
625
     * @param integer $entry_id
626
     *  The ID of the Entry to return it's section
627
     * @return integer
628
     *  The Section ID for this Entry's section
629
     */
630
    public static function fetchEntrySectionID($entry_id)
631
    {
632
        return Symphony::Database()->fetchVar('section_id', 0, sprintf("
0 ignored issues
show
Bug Best Practice introduced by
The expression return Symphony::Databas...d LIMIT 1', $entry_id)) also could return the type string which is incompatible with the documented return type integer.
Loading history...
633
            SELECT `section_id` FROM `tbl_entries` WHERE `id` = %d LIMIT 1",
634
            $entry_id
635
        ));
636
    }
637
638
    /**
639
     * Return the count of the number of entries in a particular section.
640
     *
641
     * @param integer $section_id
642
     *  The ID of the Section where the Entries are to be counted
643
     * @param string $where
644
     *  Any custom WHERE clauses
645
     * @param string $joins
646
     *  Any custom JOIN's
647
     * @param boolean $group
648
     *  Whether the entries need to be grouped by Entry ID or not
649
     * @return integer
650
     */
651
    public static function fetchCount($section_id = null, $where = null, $joins = null, $group = false)
652
    {
653
        if (is_null($section_id)) {
654
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type integer.
Loading history...
655
        }
656
657
        $section = SectionManager::fetch($section_id);
658
659
        if (!is_object($section)) {
660
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type integer.
Loading history...
661
        }
662
663
        return Symphony::Database()->fetchVar('count', 0, sprintf("
0 ignored issues
show
Bug Best Practice introduced by
The expression return Symphony::Databas..., $section_id, $where)) also could return the type string which is incompatible with the documented return type integer.
Loading history...
664
                SELECT COUNT(%s`e`.id) as `count`
665
                FROM `tbl_entries` AS `e`
666
                %s
667
                WHERE `e`.`section_id` = %d
668
                %s
669
            ",
670
            $group ? 'DISTINCT ' : '',
671
            $joins,
672
            $section_id,
673
            $where
674
        ));
675
    }
676
677
    /**
678
     * Returns an array of Entry objects, with some basic pagination given
679
     * the number of Entry's to return and the current starting offset. This
680
     * function in turn calls the fetch function that does alot of the heavy
681
     * lifting. For instance, if there are 60 entries in a section and the pagination
682
     * dictates that per page, 15 entries are to be returned, by passing 2 to
683
     * the $page parameter you could return entries 15-30
684
     *
685
     * @param integer $page
686
     *  The page to return, defaults to 1
687
     * @param integer $section_id
688
     *  The ID of the Section that these entries are contained in
689
     * @param integer $entriesPerPage
690
     *  The number of entries to return per page.
691
     * @param string $where
692
     *  Any custom WHERE clauses
693
     * @param string $joins
694
     *  Any custom JOIN's
695
     * @param boolean $group
696
     *  Whether the entries need to be grouped by Entry ID or not
697
     * @param boolean $records_only
698
     *  If this is set to true, an array of Entry objects will be returned
699
     *  without any basic pagination information. Defaults to false
700
     * @param boolean $buildentries
701
     *  Whether to return an array of entry ID's or Entry objects. Defaults to
702
     *  true, which will return Entry objects
703
     * @param array $element_names
704
     *  Choose whether to get data from a subset of fields or all fields in a section,
705
     *  by providing an array of field names. Defaults to null, which will load data
706
     *  from all fields in a section.
707
     * @throws Exception
708
     * @return array
709
     *  Either an array of Entry objects, or an associative array containing
710
     *  the total entries, the start position, the entries per page and the
711
     *  Entry objects
712
     */
713
    public static function fetchByPage($page = 1, $section_id, $entriesPerPage, $where = null, $joins = null, $group = false, $records_only = false, $buildentries = true, array $element_names = null)
714
    {
715
        if ($entriesPerPage != null && !is_string($entriesPerPage) && !is_numeric($entriesPerPage)) {
0 ignored issues
show
introduced by
The condition is_numeric($entriesPerPage) is always true.
Loading history...
716
            throw new Exception(__('Entry limit specified was not a valid type. String or Integer expected.'));
717
        } elseif ($entriesPerPage == null) {
718
            $records = self::fetch(null, $section_id, null, null, $where, $joins, $group, $buildentries, $element_names);
719
720
            $count = self::fetchCount($section_id, $where, $joins, $group);
721
722
            $entries = array(
723
                'total-entries' => $count,
724
                'total-pages' => 1,
725
                'remaining-pages' => 0,
726
                'remaining-entries' => 0,
727
                'start' => 1,
728
                'limit' => $count,
729
                'records' => $records
730
            );
731
732
            return $entries;
733
        } else {
734
            $start = (max(1, $page) - 1) * $entriesPerPage;
735
736
            $records = ($entriesPerPage == '0' ? null : self::fetch(null, $section_id, $entriesPerPage, $start, $where, $joins, $group, $buildentries, $element_names));
737
738
            if ($records_only) {
739
                return array('records' => $records);
740
            }
741
742
            $entries = array(
743
                'total-entries' => self::fetchCount($section_id, $where, $joins, $group),
744
                'records' => $records,
745
                'start' => max(1, $start),
746
                'limit' => $entriesPerPage
747
            );
748
749
            $entries['remaining-entries'] = max(0, $entries['total-entries'] - ($start + $entriesPerPage));
750
            $entries['total-pages'] = max(1, ceil($entries['total-entries'] * (1 / $entriesPerPage)));
751
            $entries['remaining-pages'] = max(0, $entries['total-pages'] - $page);
752
753
            return $entries;
754
        }
755
    }
756
757
    /**
758
     * Creates a new Entry object using this class as the parent.
759
     *
760
     * @return Entry
761
     */
762
    public static function create()
763
    {
764
        return new Entry;
765
    }
766
}
767