Completed
Push — master ( 7fd45d...bcd868 )
by ignace nyamagana
05:19 queued 03:54
created

ResultSet::getHeader()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 4
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
* This file is part of the League.csv library
4
*
5
* @license http://opensource.org/licenses/MIT
6
* @link https://github.com/thephpleague/csv/
7
* @version 9.0.0
8
* @package League.csv
9
*
10
* For the full copyright and license information, please view the LICENSE
11
* file that was distributed with this source code.
12
*/
13
declare(strict_types=1);
14
15
namespace League\Csv;
16
17
use CallbackFilterIterator;
18
use Countable;
19
use Generator;
20
use Iterator;
21
use IteratorAggregate;
22
use JsonSerializable;
23
use League\Csv\Exception\OutOfRangeException;
24
use League\Csv\Exception\RuntimeException;
25
use LimitIterator;
26
27
/**
28
 * Represents the result set of a {@link Reader} processed by a {@link Statement}
29
 *
30
 * @package League.csv
31
 * @since   9.0.0
32
 * @author  Ignace Nyamagana Butera <[email protected]>
33
 *
34
 */
35
class ResultSet implements Countable, IteratorAggregate, JsonSerializable
36
{
37
    /**
38
     * The CSV records collection
39
     *
40
     * @var Iterator
41
     */
42
    protected $records;
43
44
    /**
45
     * The CSV records collection column names
46
     *
47
     * @var array
48
     */
49
    protected $header = [];
50
51
    /**
52
     * Tell whether the CSV records offset must be kept on output
53
     *
54
     * @var bool
55
     */
56
    protected $preserve_offset = false;
57
58
    /**
59
     * New instance
60
     *
61
     * @param Iterator $iterator a CSV records collection iterator
0 ignored issues
show
Bug introduced by
There is no parameter named $iterator. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
62
     * @param array    $header   the associated collection column names
63
     * @param Iterator $records
64
     */
65 8
    public function __construct(Iterator $records, array $header)
66
    {
67 8
        $this->records = $records;
68 8
        $this->header = $header;
69 8
    }
70
71
    /**
72
     * @inheritdoc
73
     */
74 10
    public function __destruct()
75
    {
76 10
        $this->records = null;
77 10
    }
78
79
    /**
80
     * Returns the column names associated with the ResultSet
81
     *
82
     * @return string[]
83
     */
84 2
    public function getHeader(): array
85
    {
86 2
        return $this->header;
87
    }
88
89
    /**
90
     * @inheritdoc
91
     */
92 2
    public function getRecords(): Generator
93
    {
94 2
        return $this->iteratorToGenerator($this->records);
95
    }
96
97
    /**
98
     * Return the generator depending on the preserveRecordOffset setting
99
     *
100
     * @param Iterator $iterator
101
     *
102
     * @return Generator
103
     */
104 6
    protected function iteratorToGenerator(Iterator $iterator): Generator
105
    {
106 6
        if ($this->preserve_offset) {
107 4
            foreach ($iterator as $offset => $value) {
108 4
                yield $offset => $value;
109
            }
110 4
            return;
111
        }
112
113 2
        foreach ($iterator as $value) {
114 2
            yield $value;
115
        }
116 2
    }
117
118
    /**
119
     * Tell whether the CSV document record offset must be kept on output
120
     *
121
     * @return bool
122
     */
123 2
    public function isRecordOffsetPreserved(): bool
124
    {
125 2
        return $this->preserve_offset;
126
    }
127
128
    /**
129
     * @inheritdoc
130
     */
131 4
    public function getIterator(): Generator
132
    {
133 4
        return $this->getRecords();
134
    }
135
136
    /**
137
     * @inheritdoc
138
     */
139 2
    public function count(): int
140
    {
141 2
        return iterator_count($this->records);
142
    }
143
144
    /**
145
     * Returns a sequential array of all CSV records found
146
     *
147
     * @return array
148
     */
149 8
    public function fetchAll(): array
150
    {
151 8
        return iterator_to_array($this->records, $this->preserve_offset);
152
    }
153
154
    /**
155
     * @inheritdoc
156
     */
157 2
    public function jsonSerialize(): array
158
    {
159 2
        return $this->fetchAll();
160
    }
161
162
    /**
163
     * Returns a the nth record from the resultset
164
     *
165
     * By default if no index is provided the first record of the resultet is returned
166
     *
167
     * @param int $nth_record the CSV record offset
168
     *
169
     * @throws OutOfRangeException if argument is lesser than 0
170
     *
171
     * @return array
172
     */
173 4
    public function fetchOne(int $nth_record = 0): array
174
    {
175 4
        if ($nth_record < 0) {
176 2
            throw new OutOfRangeException(sprintf('%s() expects the submitted offset to be a positive integer or 0, %s given', __METHOD__, $nth_record));
177
        }
178
179 2
        $iterator = new LimitIterator($this->records, $nth_record, 1);
180 2
        $iterator->rewind();
181
182 2
        return (array) $iterator->current();
183
    }
184
185
    /**
186
     * Returns the next value from a single CSV record field
187
     *
188
     * By default if no column index is provided the first column of the CSV is selected
189
     *
190
     * @param string|int $index CSV column index
191
     *
192
     * @return Generator
193
     */
194 14
    public function fetchColumn($index = 0): Generator
195
    {
196 14
        $offset = $this->getColumnIndex($index, __METHOD__.'() expects the column index to be a valid string or integer, `%s` given');
197
        $filter = function (array $record) use ($offset): bool {
198 8
            return isset($record[$offset]);
199 8
        };
200
201
        $select = function (array $record) use ($offset): string {
202 6
            return $record[$offset];
203 8
        };
204
205 8
        $iterator = new MapIterator(new CallbackFilterIterator($this->records, $filter), $select);
206
207 8
        return $this->iteratorToGenerator($iterator);
208
    }
209
210
    /**
211
     * Filter a column name against the CSV header if any
212
     *
213
     * @param string|int $field         the field name or the field index
214
     * @param string     $error_message the associated error message
215
     *
216
     * @return string|int
217
     */
218 20
    protected function getColumnIndex($field, string $error_message)
219
    {
220 20
        $method = 'getColumnIndexByKey';
221 20
        if (is_string($field)) {
222 4
            $method = 'getColumnIndexByValue';
223
        }
224
225 20
        return $this->$method($field, $error_message);
226
    }
227
228
    /**
229
     * Returns the selected column name
230
     *
231
     * @param string $value
232
     * @param string $error_message
233
     *
234
     * @throws RuntimeException if the column is not found
235
     *
236
     * @return string
237
     */
238 4
    protected function getColumnIndexByValue(string $value, string $error_message): string
239
    {
240 4
        if (false !== array_search($value, $this->header, true)) {
241 2
            return $value;
242
        }
243
244 2
        throw new RuntimeException(sprintf($error_message, $value));
245
    }
246
247
    /**
248
     * Returns the selected column name according to its offset
249
     *
250
     * @param int    $index
251
     * @param string $error_message
252
     *
253
     * @throws OutOfRangeException if the field index is invalid
254
     * @throws RuntimeException    if the field is invalid or not found
255
     *
256
     * @return int|string
257
     */
258 12
    protected function getColumnIndexByKey(int $index, string $error_message)
259
    {
260 12
        if ($index < 0) {
261 2
            throw new OutOfRangeException($error_message);
262
        }
263
264 10
        if (empty($this->header)) {
265 6
            return $index;
266
        }
267
268 4
        $value = array_search($index, array_flip($this->header), true);
269 4
        if (false !== $value) {
270 2
            return $value;
271
        }
272
273 2
        throw new RuntimeException(sprintf($error_message, $index));
274
    }
275
276
    /**
277
     * Fetches the next key-value pairs from a result set (first
278
     * column is the key, second column is the value).
279
     *
280
     * By default if no column index is provided:
281
     * - the first CSV column is used to provide the keys
282
     * - the second CSV column is used to provide the value
283
     *
284
     * @param string|int $offset_index The column index to serve as offset
285
     * @param string|int $value_index  The column index to serve as value
286
     *
287
     * @return Generator
288
     */
289 8
    public function fetchPairs($offset_index = 0, $value_index = 1): Generator
290
    {
291 8
        $offset = $this->getColumnIndex($offset_index, __METHOD__.'() expects the offset index value to be a valid string or integer, `%s` given');
292 8
        $value = $this->getColumnIndex($value_index, __METHOD__.'() expects the value index value to be a valid string or integer, `%s` given');
293
294
        $filter = function (array $record) use ($offset): bool {
295 8
            return isset($record[$offset]);
296 8
        };
297
298 8
        $select = function (array $record) use ($offset, $value): array {
299 6
            return [$record[$offset], $record[$value] ?? null];
300 8
        };
301
302 8
        $iterator = new MapIterator(new CallbackFilterIterator($this->records, $filter), $select);
303 8
        foreach ($iterator as $pair) {
304 6
            yield $pair[0] => $pair[1];
305
        }
306 8
    }
307
308
    /**
309
     * Whether we should preserve the CSV document record offset.
310
     *
311
     * If set to true CSV document record offset will be added to
312
     * method output where it makes sense.
313
     *
314
     * @param bool $status
315
     *
316
     * @return self
317
     */
318 2
    public function preserveRecordOffset(bool $status): self
319
    {
320 2
        $this->preserve_offset = $status;
321
322 2
        return $this;
323
    }
324
}
325