Scrutinizer GitHub App not installed

We could not synchronize checks via GitHub's checks API since Scrutinizer's GitHub App is not installed for this repository.

Install GitHub App

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.
Completed
Push — master ( 70fd28...767599 )
by Sebastian
23s queued 11s
created

DocumentList::removeRange()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 10
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 8
nc 2
nop 2
dl 0
loc 10
rs 10
c 0
b 0
f 0
1
<?php
2
namespace Kitodo\Dlf\Common;
3
4
/**
5
 * (c) Kitodo. Key to digital objects e.V. <[email protected]>
6
 *
7
 * This file is part of the Kitodo and TYPO3 projects.
8
 *
9
 * @license GNU General Public License version 3 or later.
10
 * For the full copyright and license information, please read the
11
 * LICENSE.txt file that was distributed with this source code.
12
 */
13
14
/**
15
 * List class for the 'dlf' extension
16
 *
17
 * @author Sebastian Meyer <[email protected]>
18
 * @author Frank Ulrich Weber <[email protected]>
19
 * @package TYPO3
20
 * @subpackage dlf
21
 * @access public
22
 */
23
class DocumentList implements \ArrayAccess, \Countable, \Iterator, \TYPO3\CMS\Core\SingletonInterface {
24
    /**
25
     * This holds the number of documents in the list
26
     * @see \Countable
27
     *
28
     * @var integer
29
     * @access protected
30
     */
31
    protected $count = 0;
32
33
    /**
34
     * This holds the list entries in sorted order
35
     * @see \ArrayAccess
36
     *
37
     * @var array
38
     * @access protected
39
     */
40
    protected $elements = [];
41
42
    /**
43
     * This holds the list's metadata
44
     *
45
     * @var array
46
     * @access protected
47
     */
48
    protected $metadata = [];
49
50
    /**
51
     * This holds the current list position
52
     * @see \Iterator
53
     *
54
     * @var integer
55
     * @access protected
56
     */
57
    protected $position = 0;
58
59
    /**
60
     * This holds the full records of already processed list elements
61
     *
62
     * @var array
63
     * @access protected
64
     */
65
    protected $records = [];
66
67
    /**
68
     * Instance of \Kitodo\Dlf\Common\Solr class
69
     *
70
     * @var \Kitodo\Dlf\Common\Solr
71
     * @access protected
72
     */
73
    protected $solr;
74
75
    /**
76
     * This holds the Solr metadata configuration
77
     *
78
     * @var array
79
     * @access protected
80
     */
81
    protected $solrConfig = [];
82
83
    /**
84
     * This adds an array of elements at the given position to the list
85
     *
86
     * @access public
87
     *
88
     * @param array $elements: Array of elements to add to list
89
     * @param integer $position: Numeric position for including
90
     *
91
     * @return void
92
     */
93
    public function add(array $elements, $position = -1) {
94
        $position = \TYPO3\CMS\Core\Utility\MathUtility::forceIntegerInRange($position, 0, $this->count, $this->count);
95
        if (!empty($elements)) {
96
            array_splice($this->elements, $position, 0, $elements);
97
            $this->count = count($this->elements);
98
        }
99
    }
100
101
    /**
102
     * This counts the elements
103
     * @see \Countable::count()
104
     *
105
     * @access public
106
     *
107
     * @return integer The number of elements in the list
108
     */
109
    public function count() {
110
        return $this->count;
111
    }
112
113
    /**
114
     * This returns the current element
115
     * @see \Iterator::current()
116
     *
117
     * @access public
118
     *
119
     * @return array The current element
120
     */
121
    public function current() {
122
        if ($this->valid()) {
123
            return $this->getRecord($this->elements[$this->position]);
124
        } else {
125
            Helper::devLog('Invalid position "'.$this->position.'" for list element', DEVLOG_SEVERITY_NOTICE);
126
            return;
127
        }
128
    }
129
130
    /**
131
     * This returns the full record of any list element
132
     *
133
     * @access protected
134
     *
135
     * @param mixed $element: The list element
136
     *
137
     * @return mixed The element's full record
138
     */
139
    protected function getRecord($element) {
140
        if (is_array($element)
141
            && array_keys($element) == ['u', 'h', 's', 'p']) {
142
            // Return already processed record if possible.
143
            if (!empty($this->records[$element['u']])) {
144
                return $this->records[$element['u']];
145
            }
146
            $record = [
147
                'uid' => $element['u'],
148
                'page' => 1,
149
                'preview' => '',
150
                'subparts' => $element['p']
151
            ];
152
            // Check if it's a list of database records or Solr documents.
153
            if (!empty($this->metadata['options']['source'])
154
                && $this->metadata['options']['source'] == 'collection') {
155
                // Get document's thumbnail and metadata from database.
156
                $result = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
157
                    'tx_dlf_documents.uid AS uid,tx_dlf_documents.thumbnail AS thumbnail,tx_dlf_documents.metadata AS metadata',
158
                    'tx_dlf_documents',
159
                    '(tx_dlf_documents.uid='.intval($record['uid']).' OR tx_dlf_documents.partof='.intval($record['uid']).')'
160
                        .Helper::whereClause('tx_dlf_documents'),
161
                    '',
162
                    '',
163
                    ''
164
                );
165
                // Process results.
166
                while ($resArray = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($result)) {
167
                    // Prepare document's metadata.
168
                    $metadata = unserialize($resArray['metadata']);
169
                    if (!empty($metadata['type'][0])
170
                        && \TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($metadata['type'][0])) {
171
                        $metadata['type'][0] = Helper::getIndexNameFromUid($metadata['type'][0], 'tx_dlf_structures', $this->metadata['options']['pid']);
172
                    }
173
                    if (!empty($metadata['owner'][0])
174
                        && \TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($metadata['owner'][0])) {
175
                        $metadata['owner'][0] = Helper::getIndexNameFromUid($metadata['owner'][0], 'tx_dlf_libraries', $this->metadata['options']['pid']);
176
                    }
177
                    if (!empty($metadata['collection'])
178
                        && is_array($metadata['collection'])) {
179
                        foreach ($metadata['collection'] as $i => $collection) {
180
                            if (\TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($collection)) {
181
                                $metadata['collection'][$i] = Helper::getIndexNameFromUid($metadata['collection'][$i], 'tx_dlf_collections', $this->metadata['options']['pid']);
182
                            }
183
                        }
184
                    }
185
                    // Add metadata to list element.
186
                    if ($resArray['uid'] == $record['uid']) {
187
                        $record['thumbnail'] = $resArray['thumbnail'];
188
                        $record['metadata'] = $metadata;
189
                    } elseif (($key = array_search(['u' => $resArray['uid']], $record['subparts'], TRUE)) !== FALSE) {
190
                        $record['subparts'][$key] = [
191
                            'uid' => $resArray['uid'],
192
                            'page' => 1,
193
                            'preview' => (!empty($record['subparts'][$key]['h']) ? $record['subparts'][$key]['h'] : ''),
194
                            'thumbnail' => $resArray['thumbnail'],
195
                            'metadata' => $metadata
196
                        ];
197
                    }
198
                }
199
            } elseif (!empty($this->metadata['options']['source'])
200
                && $this->metadata['options']['source'] == 'search') {
201
                if ($this->solrConnect()) {
202
                    $params = [];
203
                    // Restrict the fields to the required ones
204
                    $params['fields'] = 'uid,id,toplevel,thumbnail,page';
205
                    foreach ($this->solrConfig as $solr_name) {
206
                        $params['fields'] .= ','.$solr_name;
207
                    }
208
                    // If it is a fulltext search, enable highlighting.
209
                    if ($this->metadata['fulltextSearch']) {
210
                        $params['component'] = [
211
                            'highlighting' => [
212
                                'query' => Solr::escapeQuery($this->metadata['searchString']),
213
                                'field' => 'fulltext',
214
                                'usefastvectorhighlighter' => TRUE
215
                            ]
216
                        ];
217
                    }
218
                    // Set additional query parameters.
219
                    $params['start'] = 0;
220
                    // Set reasonable limit for safety reasons.
221
                    // We don't expect to get more than 10.000 hits per UID.
222
                    $params['rows'] = 10000;
223
                    // Take over existing filter queries.
224
                    $params['filterquery'] = isset($this->metadata['options']['params']['filterquery']) ? $this->metadata['options']['params']['filterquery'] : [];
225
                    // Extend filter query to get all documents with the same UID.
226
                    foreach ($params['filterquery'] as $key => $value) {
227
                        if (isset($value['query'])) {
228
                            $params['filterquery'][$key]['query'] = $value['query'].' OR toplevel:true';
229
                        }
230
                    }
231
                    // Add filter query to get all documents with the required uid.
232
                    $params['filterquery'][] = ['query' => 'uid:'.Solr::escapeQuery($record['uid'])];
233
                    // Add sorting.
234
                    $params['sort'] = $this->metadata['options']['params']['sort'];
235
                    // Set query.
236
                    $params['query'] = $this->metadata['options']['select'].' OR toplevel:true';
237
                    // Perform search for all documents with the same uid that either fit to the search or marked as toplevel.
238
                    $selectQuery = $this->solr->service->createSelect($params);
0 ignored issues
show
Bug Best Practice introduced by
The property $service is declared protected in Kitodo\Dlf\Common\Solr. Since you implement __get, consider adding a @property or @property-read.
Loading history...
239
                    $result = $this->solr->service->select($selectQuery);
240
                    // If it is a fulltext search, fetch the highlighting results.
241
                    if ($this->metadata['fulltextSearch']) {
242
                        $highlighting = $result->getHighlighting();
243
                    }
244
                    // Process results.
245
                    foreach ($result as $resArray) {
246
                        // Prepare document's metadata.
247
                        $metadata = [];
248
                        foreach ($this->solrConfig as $index_name => $solr_name) {
249
                            if (!empty($resArray->$solr_name)) {
250
                                $metadata[$index_name] = (is_array($resArray->$solr_name) ? $resArray->$solr_name : [$resArray->$solr_name]);
251
                            }
252
                        }
253
                        // Add metadata to list elements.
254
                        if ($resArray->toplevel) {
255
                            $record['thumbnail'] = $resArray->thumbnail;
256
                            $record['metadata'] = $metadata;
257
                        } else {
258
                            $highlightedDoc = !empty($highlighting) ? $highlighting->getResult($resArray->id) : NULL;
259
                            $highlight = !empty($highlightedDoc) ? $highlightedDoc->getField('fulltext')[0] : '';
260
                            $record['subparts'][$resArray->id] = [
261
                                'uid' => $resArray->uid,
262
                                'page' => $resArray->page,
263
                                'preview' => $highlight,
264
                                'thumbnail' => $resArray->thumbnail,
265
                                'metadata' => $metadata
266
                            ];
267
                        }
268
                    }
269
                }
270
            }
271
            // Save record for later usage.
272
            $this->records[$element['u']] = $record;
273
        } else {
274
            Helper::devLog('No UID of list element to fetch full record', DEVLOG_SEVERITY_NOTICE);
275
            $record = $element;
276
        }
277
        return $record;
278
    }
279
280
    /**
281
     * This returns the current position
282
     * @see \Iterator::key()
283
     *
284
     * @access public
285
     *
286
     * @return integer The current position
287
     */
288
    public function key() {
289
        return $this->position;
290
    }
291
292
    /**
293
     * This moves the element at the given position up or down
294
     *
295
     * @access public
296
     *
297
     * @param integer $position: Numeric position for moving
298
     * @param integer $steps: Amount of steps to move up or down
299
     *
300
     * @return void
301
     */
302
    public function move($position, $steps) {
303
        $position = intval($position);
304
        // Check if list position is valid.
305
        if ($position < 0
306
            || $position >= $this->count) {
307
            Helper::devLog('Invalid position "'.$position.'" for element moving', DEVLOG_SEVERITY_WARNING);
308
            return;
309
        }
310
        $steps = intval($steps);
311
        // Check if moving given amount of steps is possible.
312
        if (($position + $steps) < 0
313
            || ($position + $steps) >= $this->count) {
314
            Helper::devLog('Invalid steps "'.$steps.'" for moving element at position "'.$position.'"', DEVLOG_SEVERITY_WARNING);
315
            return;
316
        }
317
        $element = $this->remove($position);
318
        $this->add([$element], $position + $steps);
319
    }
320
321
    /**
322
     * This moves the element at the given position up
323
     *
324
     * @access public
325
     *
326
     * @param integer $position: Numeric position for moving
327
     *
328
     * @return void
329
     */
330
    public function moveUp($position) {
331
        $this->move($position, -1);
332
    }
333
334
    /**
335
     * This moves the element at the given position down
336
     *
337
     * @access public
338
     *
339
     * @param integer $position: Numeric position for moving
340
     *
341
     * @return void
342
     */
343
    public function moveDown($position) {
344
        $this->move($position, 1);
345
    }
346
347
    /**
348
     * This increments the current list position
349
     * @see \Iterator::next()
350
     *
351
     * @access public
352
     *
353
     * @return void
354
     */
355
    public function next() {
356
        $this->position++;
357
    }
358
359
    /**
360
     * This checks if an offset exists
361
     * @see \ArrayAccess::offsetExists()
362
     *
363
     * @access public
364
     *
365
     * @param mixed $offset: The offset to check
366
     *
367
     * @return boolean Does the given offset exist?
368
     */
369
    public function offsetExists($offset) {
370
        return isset($this->elements[$offset]);
371
    }
372
373
    /**
374
     * This returns the element at the given offset
375
     * @see \ArrayAccess::offsetGet()
376
     *
377
     * @access public
378
     *
379
     * @param mixed $offset: The offset to return
380
     *
381
     * @return array The element at the given offset
382
     */
383
    public function offsetGet($offset) {
384
        if ($this->offsetExists($offset)) {
385
            return $this->getRecord($this->elements[$offset]);
386
        } else {
387
            Helper::devLog('Invalid offset "'.$offset.'" for list element', DEVLOG_SEVERITY_NOTICE);
388
            return;
389
        }
390
    }
391
392
    /**
393
     * This sets the element at the given offset
394
     * @see \ArrayAccess::offsetSet()
395
     *
396
     * @access public
397
     *
398
     * @param mixed $offset: The offset to set (non-integer offsets will be appended)
399
     * @param mixed $value: The value to set
400
     *
401
     * @return void
402
     */
403
    public function offsetSet($offset, $value) {
404
        if (\TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($offset)) {
405
            $this->elements[$offset] = $value;
406
        } else {
407
            $this->elements[] = $value;
408
        }
409
        // Re-number the elements.
410
        $this->elements = array_values($this->elements);
411
        $this->count = count($this->elements);
412
    }
413
414
    /**
415
     * This removes the element at the given position from the list
416
     *
417
     * @access public
418
     *
419
     * @param integer $position: Numeric position for removing
420
     *
421
     * @return array The removed element
422
     */
423
    public function remove($position) {
424
        $position = intval($position);
425
        if ($position < 0
426
            || $position >= $this->count) {
427
            Helper::devLog('Invalid position "'.$position.'" for element removing', DEVLOG_SEVERITY_WARNING);
428
            return;
429
        }
430
        $removed = array_splice($this->elements, $position, 1);
431
        $this->count = count($this->elements);
432
        return $this->getRecord($removed[0]);
433
    }
434
435
    /**
436
     * This removes elements at the given range from the list
437
     *
438
     * @access public
439
     *
440
     * @param integer $position: Numeric position for start of range
441
     * @param integer $length: Numeric position for length of range
442
     *
443
     * @return array The indizes of the removed elements
444
     */
445
    public function removeRange($position, $length) {
446
        $position = intval($position);
447
        if ($position < 0
448
            || $position >= $this->count) {
449
            Helper::devLog('Invalid position "'.$position.'" for element removing', DEVLOG_SEVERITY_WARNING);
450
            return;
451
        }
452
        $removed = array_splice($this->elements, $position, $length);
453
        $this->count = count($this->elements);
454
        return $removed;
455
    }
456
457
    /**
458
     * This clears the current list
459
     *
460
     * @access public
461
     *
462
     * @return void
463
     */
464
    public function reset() {
465
        $this->elements = [];
466
        $this->records = [];
467
        $this->metadata = [];
468
        $this->count = 0;
469
        $this->position = 0;
470
    }
471
472
    /**
473
     * This resets the list position
474
     * @see \Iterator::rewind()
475
     *
476
     * @access public
477
     *
478
     * @return void
479
     */
480
    public function rewind() {
481
        $this->position = 0;
482
    }
483
484
    /**
485
     * This saves the current list
486
     *
487
     * @access public
488
     *
489
     * @param integer $pid: PID for saving in database
490
     *
491
     * @return void
492
     */
493
    public function save($pid = 0) {
494
        $pid = max(intval($pid), 0);
495
        // If no PID is given, save to the user's session instead
496
        if ($pid > 0) {
497
            // TODO: Liste in Datenbank speichern (inkl. Sichtbarkeit, Beschreibung, etc.)
498
        } else {
499
            Helper::saveToSession([$this->elements, $this->metadata], get_class($this));
500
        }
501
    }
502
503
    /**
504
     * Connects to Solr server.
505
     *
506
     * @access protected
507
     *
508
     * @return boolean TRUE on success or FALSE on failure
509
     */
510
    protected function solrConnect() {
511
        // Get Solr instance.
512
        if (!$this->solr) {
513
            // Connect to Solr server.
514
            if ($this->solr = Solr::getInstance($this->metadata['options']['core'])) {
515
                // Load index configuration.
516
                $result = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
517
                    'tx_dlf_metadata.index_name AS index_name,tx_dlf_metadata.index_tokenized AS index_tokenized,tx_dlf_metadata.index_indexed AS index_indexed',
518
                    'tx_dlf_metadata',
519
                    'tx_dlf_metadata.is_listed=1'
520
                        .' AND tx_dlf_metadata.pid='.intval($this->metadata['options']['pid'])
521
                        .Helper::whereClause('tx_dlf_metadata'),
522
                    '',
523
                    'tx_dlf_metadata.sorting ASC',
524
                    ''
525
                );
526
                while ($resArray = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($result)) {
527
                    $this->solrConfig[$resArray['index_name']] = $resArray['index_name'].'_'.($resArray['index_tokenized'] ? 't' : 'u').'s'.($resArray['index_indexed'] ? 'i' : 'u');
528
                }
529
                // Add static fields.
530
                $this->solrConfig['type'] = 'type';
531
            } else {
532
                return FALSE;
533
            }
534
        }
535
        return TRUE;
536
    }
537
538
    /**
539
     * This sorts the current list by the given field
540
     *
541
     * @access public
542
     *
543
     * @param string $by: Sort the list by this field
544
     * @param boolean $asc: Sort ascending?
545
     *
546
     * @return void
547
     */
548
    public function sort($by, $asc = TRUE) {
549
        $newOrder = [];
550
        $nonSortable = [];
551
        foreach ($this->elements as $num => $element) {
552
            // Is this element sortable?
553
            if (!empty($element['s'][$by])) {
554
                $newOrder[$element['s'][$by].str_pad($num, 6, '0', STR_PAD_LEFT)] = $element;
555
            } else {
556
                $nonSortable[] = $element;
557
            }
558
        }
559
        // Reorder elements.
560
        if ($asc) {
561
            ksort($newOrder, SORT_LOCALE_STRING);
562
        } else {
563
            krsort($newOrder, SORT_LOCALE_STRING);
564
        }
565
        // Add non sortable elements to the end of the list.
566
        $newOrder = array_merge(array_values($newOrder), $nonSortable);
567
        // Check if something is missing.
568
        if ($this->count == count($newOrder)) {
569
            $this->elements = $newOrder;
570
        } else {
571
            Helper::devLog('Sorted list elements do not match unsorted elements', DEVLOG_SEVERITY_ERROR);
572
        }
573
    }
574
575
    /**
576
     * This unsets the element at the given offset
577
     * @see \ArrayAccess::offsetUnset()
578
     *
579
     * @access public
580
     *
581
     * @param mixed $offset: The offset to unset
582
     *
583
     * @return void
584
     */
585
    public function offsetUnset($offset) {
586
        unset ($this->elements[$offset]);
587
        // Re-number the elements.
588
        $this->elements = array_values($this->elements);
589
        $this->count = count($this->elements);
590
    }
591
592
    /**
593
     * This checks if the current list position is valid
594
     * @see \Iterator::valid()
595
     *
596
     * @access public
597
     *
598
     * @return boolean Is the current list position valid?
599
     */
600
    public function valid() {
601
        return isset($this->elements[$this->position]);
602
    }
603
604
    /**
605
     * This returns $this->metadata via __get()
606
     *
607
     * @access protected
608
     *
609
     * @return array The list's metadata
610
     */
611
    protected function _getMetadata() {
612
        return $this->metadata;
613
    }
614
615
    /**
616
     * This sets $this->metadata via __set()
617
     *
618
     * @access protected
619
     *
620
     * @param array $metadata: Array of new metadata
621
     *
622
     * @return void
623
     */
624
    protected function _setMetadata(array $metadata = []) {
625
        $this->metadata = $metadata;
626
    }
627
628
    /**
629
     * This is the constructor
630
     *
631
     * @access public
632
     *
633
     * @param array $elements: Array of documents initially setting up the list
634
     * @param array $metadata: Array of initial metadata
635
     *
636
     * @return void
637
     */
638
    public function __construct(array $elements = [], array $metadata = []) {
639
        if (empty($elements)
640
            && empty($metadata)) {
641
            // Let's check the user's session.
642
            $sessionData = Helper::loadFromSession(get_class($this));
643
            // Restore list from session data.
644
            if (is_array($sessionData)) {
645
                if (is_array($sessionData[0])) {
646
                    $this->elements = $sessionData[0];
647
                }
648
                if (is_array($sessionData[1])) {
649
                    $this->metadata = $sessionData[1];
650
                }
651
            }
652
        } else {
653
            // Add metadata to the list.
654
            $this->metadata = $metadata;
655
            // Add initial set of elements to the list.
656
            $this->elements = $elements;
657
        }
658
        $this->count = count($this->elements);
659
    }
660
661
    /**
662
     * This magic method is invoked each time a clone is called on the object variable
663
     * (This method is defined as private/protected because singleton objects should not be cloned)
664
     *
665
     * @access protected
666
     *
667
     * @return void
668
     */
669
    protected function __clone() {}
670
671
    /**
672
     * This magic method is called each time an invisible property is referenced from the object
673
     *
674
     * @access public
675
     *
676
     * @param string $var: Name of variable to get
677
     *
678
     * @return mixed Value of $this->$var
679
     */
680
    public function __get($var) {
681
        $method = '_get'.ucfirst($var);
682
        if (!property_exists($this, $var)
683
            || !method_exists($this, $method)) {
684
            Helper::devLog('There is no getter function for property "'.$var.'"', DEVLOG_SEVERITY_WARNING);
685
            return;
686
        } else {
687
            return $this->$method();
688
        }
689
    }
690
691
    /**
692
     * This magic method is called each time an invisible property is referenced from the object
693
     *
694
     * @access public
695
     *
696
     * @param string $var: Name of variable to set
697
     * @param mixed $value: New value of variable
698
     *
699
     * @return void
700
     */
701
    public function __set($var, $value) {
702
        $method = '_set'.ucfirst($var);
703
        if (!property_exists($this, $var)
704
            || !method_exists($this, $method)) {
705
            Helper::devLog('There is no setter function for property "'.$var.'"', DEVLOG_SEVERITY_WARNING);
706
        } else {
707
            $this->$method($value);
708
        }
709
    }
710
711
    /**
712
     * This magic method is executed prior to any serialization of the object
713
     * @see __wakeup()
714
     *
715
     * @access public
716
     *
717
     * @return array Properties to be serialized
718
     */
719
    public function __sleep() {
720
        return ['elements', 'metadata'];
721
    }
722
723
    /**
724
     * This magic method is executed after the object is deserialized
725
     * @see __sleep()
726
     *
727
     * @access public
728
     *
729
     * @return void
730
     */
731
    public function __wakeup() {
732
        $this->count = count($this->elements);
733
    }
734
}
735