AbstractResultsIterator   A
last analyzed

Complexity

Total Complexity 39

Size/Duplication

Total Lines 261
Duplicated Lines 9.2 %

Coupling/Cohesion

Components 2
Dependencies 2

Importance

Changes 0
Metric Value
wmc 39
lcom 2
cbo 2
dl 24
loc 261
rs 9.28
c 0
b 0
f 0

22 Methods

Rating   Name   Duplication   Size   Complexity  
B __construct() 0 26 6
A __destruct() 0 7 2
A getRaw() 0 4 1
A getAggregations() 0 4 1
A getAggregation() 0 7 2
A count() 0 4 1
A current() 0 4 1
A next() 0 4 1
A key() 0 4 1
A valid() 0 15 3
A rewind() 0 4 1
A isScrollable() 0 4 1
A getConverter() 0 4 1
A getIndex() 0 4 1
A getDocument() 0 8 2
A documentExists() 0 4 1
A advanceKey() 0 10 3
A first() 0 6 1
A page() 0 19 3
A getDocumentScore() 12 12 3
A getDocumentSort() 12 12 3
convertDocument() 0 1 ?

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
3
/*
4
 * This file is part of the ONGR package.
5
 *
6
 * (c) NFQ Technologies UAB <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace ONGR\ElasticsearchBundle\Result;
13
14
use ONGR\ElasticsearchBundle\Mapping\Converter;
15
use ONGR\ElasticsearchBundle\Service\IndexService;
16
17
abstract class AbstractResultsIterator implements \Countable, \Iterator
18
{
19
    private $count = 0;
20
    private $raw;
21
    private $scrollId;
22
    private $scrollDuration;
23
24
    protected $documents = [];
25
    private $aggregations = [];
26
27
    private $converter;
28
    private $index;
29
30
    //Used to count scroll iteration.
31
    private $key = 0;
32
33
    public function __construct(
34
        array $rawData,
35
        IndexService $index,
36
        Converter $converter = null,
37
        array $scroll = []
38
    ) {
39
        $this->raw = $rawData;
40
        $this->converter = $converter;
41
        $this->index = $index;
42
43
        if (isset($scroll['_scroll_id']) && isset($scroll['duration'])) {
44
            $this->scrollId = $scroll['_scroll_id'];
45
            $this->scrollDuration = $scroll['duration'];
46
        }
47
48
        if (isset($rawData['aggregations'])) {
49
            $this->aggregations = &$rawData['aggregations'];
50
        }
51
52
        if (isset($rawData['hits']['hits'])) {
53
            $this->documents = $rawData['hits']['hits'];
54
        }
55
        if (isset($rawData['hits']['total']['value'])) {
56
            $this->count = $rawData['hits']['total']['value'];
57
        }
58
    }
59
60
    public function __destruct()
61
    {
62
        // Clear scroll if initialized
63
        if ($this->isScrollable()) {
64
            $this->index->clearScroll($this->scrollId);
65
        }
66
    }
67
68
    /**
69
     * @return array
70
     */
71
    public function getRaw()
72
    {
73
        return $this->raw;
74
    }
75
76
    /**
77
     * @return array
78
     */
79
    public function getAggregations()
80
    {
81
        return $this->aggregations;
82
    }
83
84
    /**
85
     * Returns specific aggregation by name.
86
     *
87
     * @param string $name
88
     *
89
     * @return array
90
     */
91
    public function getAggregation($name)
92
    {
93
        if (isset($this->aggregations[$name])) {
94
            return $this->aggregations[$name];
95
        }
96
        return null;
97
    }
98
99
    /**
100
     * Returns total count of documents.
101
     *
102
     * @return int
103
     */
104
    public function count()
105
    {
106
        return $this->count;
107
    }
108
109
    /**
110
     * Return the current element.
111
     */
112
    public function current()
113
    {
114
        return $this->getDocument($this->key());
115
    }
116
117
    /**
118
     * Move forward to the next element.
119
     */
120
    public function next(): self
121
    {
122
        return $this->advanceKey();
123
    }
124
125
    /**
126
     * Return the key of the current element.
127
     */
128
    public function key(): int
129
    {
130
        return $this->key;
131
    }
132
133
    /**
134
     * Checks if current position is valid.
135
     */
136
    public function valid(): bool
137
    {
138
        if (!isset($this->documents)) {
139
            return false;
140
        }
141
142
        $valid = $this->documentExists($this->key());
143
        if ($valid) {
144
            return true;
145
        }
146
147
        $this->page();
148
149
        return $this->documentExists($this->key());
150
    }
151
152
    /**
153
     * Rewind the Iterator to the first element.
154
     */
155
    public function rewind(): void
156
    {
157
        $this->key = 0;
158
    }
159
160
    public function isScrollable(): bool
161
    {
162
        return !empty($this->scrollId);
163
    }
164
165
    protected function getConverter(): Converter
166
    {
167
        return $this->converter;
168
    }
169
170
    public function getIndex(): IndexService
171
    {
172
        return $this->index;
173
    }
174
175
    /**
176
     * Gets document array from the container.
177
     */
178
    protected function getDocument(int $key)
179
    {
180
        if (!$this->documentExists($key)) {
181
            return null;
182
        }
183
184
        return $this->convertDocument($this->documents[$key]);
185
    }
186
187
    /**
188
     * Checks if a document exists in the local cache container.
189
     */
190
    protected function documentExists(int $key): bool
191
    {
192
        return array_key_exists($key, $this->documents);
193
    }
194
195
    /**
196
     * Advances key.
197
     *
198
     * @return $this
199
     */
200
    protected function advanceKey(): self
201
    {
202
        if ($this->isScrollable() && ($this->documents[$this->key()] == end($this->documents))) {
203
            $this->page();
204
        } else {
205
            $this->key++;
206
        }
207
208
        return $this;
209
    }
210
211
    /**
212
     * Rewind's the iteration and returns first result.
213
     */
214
    public function first()
215
    {
216
        $this->rewind();
217
218
        return $this->getDocument($this->key());
219
    }
220
221
    protected function page(): self
222
    {
223
        if ($this->key() == $this->count() || !$this->isScrollable()) {
224
            return $this;
225
        }
226
227
        $raw = $this->index->getClient()->scroll(
228
            [
229
                'scroll' => $this->scrollDuration,
230
                'scroll_id' => $this->scrollId,
231
            ]
232
        );
233
        $this->rewind();
234
235
        $this->scrollId = $raw['_scroll_id'];
236
        $this->documents = $raw['hits']['hits'];
237
238
        return $this;
239
    }
240
241
    /**
242
     * Returns score of current hit.
243
     */
244 View Code Duplication
    public function getDocumentScore(): int
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
245
    {
246
        if (!$this->valid()) {
247
            throw new \LogicException('Document score is available only while iterating over results.');
248
        }
249
250
        if (!isset($this->documents[$this->key]['_score'])) {
251
            return null;
252
        }
253
254
        return (int) $this->documents[$this->key]['_score'];
255
    }
256
257
    /**
258
    * Returns sort of current hit.
259
    */
260 View Code Duplication
    public function getDocumentSort()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
261
    {
262
        if (!$this->valid()) {
263
            throw new \LogicException('Document sort is available only while iterating over results.');
264
        }
265
266
        if (!isset($this->documents[$this->key]['sort'])) {
267
            return null;
268
        }
269
270
        return $this->documents[$this->key]['sort'][0];
271
    }
272
273
    /**
274
     * Convert`s raw array to a document object or a normalized array, depends on the iterator type.
275
     */
276
    abstract protected function convertDocument(array $raw);
277
}
278