Passed
Push — 1.x ( b78ae7...e3653f )
by Ulises Jeremias
02:22
created

ConcatIterator::jsonSerialize()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 1
b 0
f 1
1
<?php namespace Mbh\Iterator;
2
3
/**
4
 * MBHFramework
5
 *
6
 * @link      https://github.com/MBHFramework/mbh-framework
7
 * @copyright Copyright (c) 2017 Ulises Jeremias Cornejo Fandos
8
 * @license   https://github.com/MBHFramework/mbh-framework/blob/master/LICENSE (MIT License)
9
 */
10
11
use ArrayAccess;
12
use AppendIterator;
13
use JsonSerializable;
14
use Countable;
15
use Iterator;
16
use RuntimeException;
17
use InvalidArgumentException;
18
19
/**
20
 * Iterator to allow multiple iterators to be concatenated
21
 */
22
23
class ConcatIterator extends AppendIterator implements ArrayAccess, Countable, JsonSerializable
24
{
25
    const INVALID_INDEX = 'Index invalid or out of range';
26
27
    /** @var int $count Fast-lookup count for full set of iterators */
28
    public $count = 0;
29
30
    /**
31
     * Build an iterator over multiple iterators
32
     * Unlike a LimitIterator, the $end defines the last index, not the count
33
     *
34
     * @param Iterator $iterator,... Concat iterators in order
35
     */
36
    public function __construct(...$args)
37
    {
38
        parent::__construct();
39
        foreach ($args as $i => $iterator) {
40
            if (
41
                $iterator instanceof ArrayAccess &&
42
                $iterator instanceof Countable
43
            ) {
44
                // Unroll other ConcatIterators, so we avoid deep iterator stacks
45
                if ($iterator instanceof self) {
46
                    foreach ($iterator->getArrayIterator() as $innerIt) {
0 ignored issues
show
Bug introduced by
The method getArrayIterator() does not exist on Countable. It seems like you code against a sub-type of Countable such as Mbh\Iterator\ConcatIterator. ( Ignorable by Annotation )

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

46
                    foreach ($iterator->/** @scrutinizer ignore-call */ getArrayIterator() as $innerIt) {
Loading history...
Bug introduced by
The method getArrayIterator() does not exist on ArrayAccess. It seems like you code against a sub-type of ArrayAccess such as Mbh\Iterator\ConcatIterator. ( Ignorable by Annotation )

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

46
                    foreach ($iterator->/** @scrutinizer ignore-call */ getArrayIterator() as $innerIt) {
Loading history...
47
                        $this->append($innerIt);
48
                    }
49
                } else {
50
                    $this->append($iterator);
0 ignored issues
show
Bug introduced by
$iterator of type ArrayAccess&Countable is incompatible with the type Iterator expected by parameter $iterator of AppendIterator::append(). ( Ignorable by Annotation )

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

50
                    $this->append(/** @scrutinizer ignore-type */ $iterator);
Loading history...
51
                }
52
53
                $this->count += count($iterator);
54
            } else {
55
                throw new InvalidArgumentException(
56
                    'Argument ' . $i .
57
                    ' passed to ' . __METHOD__ .
58
                    ' must be of type ArrayAccess, Countable, and Traversable. ' .
59
                    gettype($iterator) . ' given.'
60
                );
61
            }
62
        }
63
    }
64
65
    /**
66
     * Countable
67
     */
68
    public function count(): int
69
    {
70
        return $this->count;
71
    }
72
73
    /**
74
     * ArrayAccess
75
     */
76
    public function offsetExists($offset): boolean
0 ignored issues
show
Bug introduced by
The type Mbh\Iterator\boolean was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
77
    {
78
        return $offset >= 0 && $offset < $this->count;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $offset >= 0 && $offset < $this->count returns the type boolean which is incompatible with the type-hinted return Mbh\Iterator\boolean.
Loading history...
79
    }
80
81
    public function offsetGet($offset)
82
    {
83
        if ($this->offsetExists($offset)) {
84
            list($it, $idx) = $this->getIteratorByIndex($offset);
85
            return $it->offsetGet($idx);
86
        } else {
87
            throw new RuntimeException(self::INVALID_INDEX);
88
        }
89
    }
90
91
    public function offsetSet($offset, $value)
92
    {
93
        list($it, $idx) = $this->getIteratorByIndex($offset);
94
        $it->offsetSet($idx, $value);
95
    }
96
97
    public function offsetUnset($offset)
98
    {
99
        list($it, $idx) = $this->getIteratorByIndex($offset);
100
        $it->offsetUnset($idx);
101
    }
102
103
    /**
104
     * JsonSerializable
105
     */
106
    public function jsonSerialize(): array
107
    {
108
        return $this->toArray();
109
    }
110
111
    public function toArray(): array
112
    {
113
        return iterator_to_array($this, false);
114
    }
115
116
    /**
117
     * Find which of the inner iterators an index corresponds to
118
     *
119
     * @param int $index
120
     * @return [ArrayAccess, int] The iterator and interior index
121
     */
0 ignored issues
show
Documentation Bug introduced by
The doc comment [ArrayAccess, int] at position 0 could not be parsed: Unknown type name '[' at position 0 in [ArrayAccess, int].
Loading history...
122
    protected function getIteratorByIndex($index = 0)
123
    {
124
        $runningCount = 0;
125
        foreach ($this->getArrayIterator() as $innerIt) {
126
            $count = count($innerIt);
127
            if ($index < $runningCount + $count) {
128
                return [$innerIt, $index - $runningCount];
129
            }
130
            $runningCount += $count;
131
        }
132
133
        return null;
134
    }
135
}
136