SyncOrderedIterator::next()   C
last analyzed

Complexity

Conditions 12
Paths 23

Size

Total Lines 49
Code Lines 31

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 33
CRAP Score 12

Importance

Changes 0
Metric Value
dl 0
loc 49
ccs 33
cts 33
cp 1
rs 5.1474
c 0
b 0
f 0
cc 12
eloc 31
nc 23
nop 0
crap 12

How to fix   Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
/*
3
* The MIT License (MIT)
4
* Copyright © 2017 Marcos Lois Bermudez <[email protected]>
5
* *
6
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
7
* documentation files (the “Software”), to deal in the Software without restriction, including without limitation
8
* the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
9
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
10
* *
11
* The above copyright notice and this permission notice shall be included in all copies or substantial portions
12
* of the Software.
13
* *
14
* THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
15
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
16
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
17
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
18
* DEALINGS IN THE SOFTWARE.
19
*/
20
21
namespace TTIC\Commons\Iterator;
22
23
use Iterator;
24
25
class SyncOrderedIterator implements Iterator
26
{
27
    const LEFT_MISSING = 'left-missing';
28
    const RIGHT_MISSING = 'right-missing';
29
    const EQUAL = 'equal';
30
    const NOT_EQUAL = 'not-equal';
31
32
    /**
33
     * Left side iterator
34
     * @var Iterator
35
     */
36
    protected $left;
37
38
    /**
39
     * Right side iterator
40
     * @var Iterator
41
     */
42
    protected $right;
43
44
    /**
45
     * Current operation
46
     * @var mixed
47
     */
48
    protected $operation;
49
50
    /**
51
     * @var int
52
     */
53
    protected $key = 0;
54
55
    /**
56
     * @var callable
57
     */
58
    protected $keyCmpCallback;
59
    /**
60
     * @var callable
61
     */
62
    protected $valueEqualsCallback;
63
64
    /**
65
     * SyncOrderedIterator constructor.
66
     *
67
     * @param Iterator $left
68
     * @param Iterator $right
69
     */
70 9
    public function __construct(Iterator $left, Iterator $right,
71
                                callable $keyCmpCallback = null, callable $valueEqualsCallback = null)
72
    {
73 9
        $this->left = $left;
74 9
        $this->right = $right;
75 9
        $this->keyCmpCallback = $keyCmpCallback;
76 9
        $this->valueEqualsCallback = $valueEqualsCallback;
77 9
    }
78
79
    /**
80
     * Return the current element
81
     * @link http://php.net/manual/en/iterator.current.php
82
     * @return mixed Can return any type.
83
     * @since 5.0.0
84
     */
85 9
    public function current()
86
    {
87 9
        return $this->operation;
88
    }
89
90
    /**
91
     * Move forward to next element
92
     * @link http://php.net/manual/en/iterator.next.php
93
     * @return void Any returned value is ignored.
94
     * @since 5.0.0
95
     */
96 9
    public function next()
97
    {
98 9
        $left = $this->left;
99 9
        $right = $this->right;
100 9
        $this->operation = null;
101
102 9
        if (($left->valid() || $right->valid())) {
103 9
            if (!$left->valid()) {
104
                // If left is exausted
105 6
                $this->operation = $this->getOperation(self::LEFT_MISSING);
106 6
                $right->next();
107 6
                return;
108
            }
109 9
            if (!$right->valid()) {
110
                // If right is exausted
111 3
                $this->operation = $this->getOperation(self::RIGHT_MISSING);
112 3
                $left->next();
113 3
                return;
114
            }
115
116
117
            // Compare items
118 9
            if ($callback = $this->keyCmpCallback) {
119 6
                $cmp = $callback($left, $right);
120 4
            } else {
121 3
                $lItem = $left->current();
122 3
                $rItem = $right->current();
123 3
                $cmp = ($lItem === $rItem ? 0 : (($lItem < $rItem) ? -1 : 1));
124
            }
125
            // Create operations
126 9
            if ($cmp < 0) {
127
                // If left precedes right
128 9
                $this->operation = $this->getOperation(self::RIGHT_MISSING);
129 9
                $left->next();
130 9
                return;
131
            }
132 9
            if ($cmp > 0) {
133
                // right precedes left
134 9
                $this->operation = $this->getOperation(self::LEFT_MISSING);
135 9
                $right->next();
136 9
                return;
137
            }
138
            // Equal items
139 9
            $equals = ($callback = $this->valueEqualsCallback) ? $callback($left, $right) : true;
140 9
            $this->operation = $this->getOperation($equals ? self::EQUAL : self::NOT_EQUAL);
141 9
            $left->next();
142 9
            $right->next();
143 6
        }
144 9
    }
145
146
    /**
147
     * Return the key of the current element
148
     * @link http://php.net/manual/en/iterator.key.php
149
     * @return mixed scalar on success, or null on failure.
150
     * @since 5.0.0
151
     */
152 9
    public function key()
153
    {
154 9
        return $this->key;
155
    }
156
157
    /**
158
     * Checks if current position is valid
159
     * @link http://php.net/manual/en/iterator.valid.php
160
     * @return boolean The return value will be casted to boolean and then evaluated.
161
     * Returns true on success or false on failure.
162
     * @since 5.0.0
163
     */
164 9
    public function valid()
165
    {
166 9
        return (bool) $this->operation;
167
    }
168
169
    /**
170
     * Rewind the Iterator to the first element
171
     * @link http://php.net/manual/en/iterator.rewind.php
172
     * @return void Any returned value is ignored.
173
     * @since 5.0.0
174
     */
175 9
    public function rewind()
176
    {
177 9
        $this->left->rewind();
178 9
        $this->right->rewind();
179 9
        $this->key = -1;
180 9
        $this->next();
181 9
    }
182
183
    /**
184
     * Creates a operation for sync
185
     * @param $operation string
186
     * @return array|null
187
     */
188 9
    protected function getOperation($operation) {
189 9
        $op = [ 'type' => $operation ];
190
191
        switch ($operation) {
192 9
            case self::LEFT_MISSING:
193 9
                $op['item'] = [
194 9
                    'key' => $this->right->key(),
195 9
                    'value' => $this->right->current()
196 6
                ];
197 9
                break;
198 9
            case self::RIGHT_MISSING:
199 9
                $op['item'] = [
200 9
                    'key' => $this->left->key(),
201 9
                    'value' => $this->left->current()
202 6
                ];
203 9
                break;
204 9
            case self::EQUAL:
205 7
            case self::NOT_EQUAL:
206 9
                $op['left'] = [
207 9
                    'key' => $this->left->key(),
208 9
                    'value' => $this->left->current()
209 6
                ];
210 9
                $op['right'] = [
211 9
                    'key' => $this->right->key(),
212 9
                    'value' => $this->right->current()
213 6
                ];
214 9
                break;
215
        }
216
217 9
        $this->key++;
218 9
        return $op;
219
    }
220
}
221