Completed
Push — master ( 147747...e61ddd )
by ignace nyamagana
23:03 queued 02:55
created

ResultSet::getColumnNames()   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\RuntimeException;
24
use LimitIterator;
25
26
/**
27
 * Represents the result set of a {@link Reader} processed by a {@link Statement}
28
 *
29
 * @package League.csv
30
 * @since   9.0.0
31
 * @author  Ignace Nyamagana Butera <[email protected]>
32
 *
33
 */
34
class ResultSet implements Countable, IteratorAggregate, JsonSerializable
35
{
36
    use ValidatorTrait;
37
38
    /**
39
     * The CSV records collection
40
     *
41
     * @var Iterator
42
     */
43
    protected $iterator;
44
45
    /**
46
     * The CSV records collection column names
47
     *
48
     * @var array
49
     */
50
    protected $column_names = [];
51
52
    /**
53
     * Tell whether the CSV records offset must be kept on output
54
     *
55
     * @var bool
56
     */
57
    protected $preserve_offset = false;
58
59
    /**
60
     * New instance
61
     *
62
     * @param Iterator $iterator     a CSV records collection iterator
63
     * @param array    $column_names the associated collection column names
64
     */
65 100
    public function __construct(Iterator $iterator, array $column_names)
66
    {
67 100
        $this->iterator = $iterator;
68 100
        $this->column_names = $column_names;
69 100
    }
70
71
    /**
72
     * @inheritdoc
73
     */
74 100
    public function __destruct()
75
    {
76 100
        $this->iterator = null;
77 100
    }
78
79
    /**
80
     * Returns the column names associated with the ResultSet
81
     *
82
     * @return string[]
83
     */
84 4
    public function getColumnNames(): array
85
    {
86 4
        return $this->column_names;
87
    }
88
89
    /**
90
     * Tell whether the CSV document record offset must be kept on output
91
     *
92
     * @return bool
93
     */
94 2
    public function isRecordOffsetPreserved(): bool
95
    {
96 2
        return $this->preserve_offset;
97
    }
98
99
    /**
100
     * @inheritdoc
101
     */
102 10
    public function getIterator(): Generator
103
    {
104 10
        return $this->iteratorToGenerator($this->iterator);
105
    }
106
107
    /**
108
     * Return the generator depending on the preserveRecordOffset setting
109
     *
110
     * @param Iterator $iterator
111
     *
112
     * @return Generator
113
     */
114 18
    protected function iteratorToGenerator(Iterator $iterator): Generator
115
    {
116 18
        if ($this->preserve_offset) {
117 2
            foreach ($iterator as $offset => $value) {
118 2
                yield $offset => $value;
119
            }
120 2
            return;
121
        }
122
123 16
        foreach ($iterator as $value) {
124 14
            yield $value;
125
        }
126 12
    }
127
128
    /**
129
     * @inheritdoc
130
     */
131 2
    public function count(): int
132
    {
133 2
        return iterator_count($this->iterator);
134
    }
135
136
    /**
137
     * @inheritdoc
138
     */
139 2
    public function jsonSerialize(): array
140
    {
141 2
        return $this->fetchAll();
142
    }
143
144
    /**
145
     * Returns a sequential array of all CSV records found
146
     *
147
     * @return array
148
     */
149 58
    public function fetchAll(): array
150
    {
151 58
        return iterator_to_array($this->iterator, $this->preserve_offset);
152
    }
153
154
    /**
155
     * Returns a single record from the CSV
156
     *
157
     * By default if no offset is provided the first row of the CSV is selected
158
     *
159
     * @param int $offset the CSV record offset
160
     *
161
     * @return array
162
     */
163 6
    public function fetchOne(int $offset = 0): array
164
    {
165 6
        $offset = $this->filterMinRange($offset, 0, 'The submitted offset must be a positive integer or 0');
166 4
        $it = new LimitIterator($this->iterator, $offset, 1);
167 4
        $it->rewind();
168
169 4
        return (array) $it->current();
170
    }
171
172
    /**
173
     * Returns the next value from a single CSV record field
174
     *
175
     * By default if no column index is provided the first column of the CSV is selected
176
     *
177
     * @param string|int $index CSV column index
178
     *
179
     * @return Generator
180
     */
181 14
    public function fetchColumn($index = 0): Generator
182
    {
183 14
        $offset = $this->getColumnIndex($index, 'The column index `%s` value is invalid');
184
        $filter = function (array $record) use ($offset): bool {
185 8
            return isset($record[$offset]);
186 8
        };
187
188
        $select = function (array $record) use ($offset): string {
189 6
            return $record[$offset];
190 8
        };
191
192 8
        $iterator = new MapIterator(new CallbackFilterIterator($this->iterator, $filter), $select);
193
194 8
        return $this->iteratorToGenerator($iterator);
195
    }
196
197
    /**
198
     * Filter a column name against the CSV header if any
199
     *
200
     * @param string|int $field         the field name or the field index
201
     * @param string     $error_message the associated error message
202
     *
203
     * @throws RuntimeException if the field is invalid
204
     * @throws RuntimeException if the column is not found
205
     *
206
     * @return string|int
207
     */
208 22
    protected function getColumnIndex($field, string $error_message)
209
    {
210 22
        if (false !== array_search($field, $this->column_names, true)) {
211 2
            return $field;
212
        }
213
214 22
        if (is_string($field)) {
215 2
            throw new RuntimeException(sprintf($error_message, $field));
216
        }
217
218 20
        $index = $this->filterMinRange($field, 0, $error_message);
219 18
        if (empty($this->column_names)) {
220 14
            return $index;
221
        }
222
223 4
        $index = array_search($index, array_flip($this->column_names), true);
224 4
        if (false !== $index) {
225 2
            return $index;
226
        }
227
228 2
        throw new RuntimeException(sprintf($error_message, $field));
229
    }
230
231
    /**
232
     * Fetches the next key-value pairs from a result set (first
233
     * column is the key, second column is the value).
234
     *
235
     * By default if no column index is provided:
236
     * - the first CSV column is used to provide the keys
237
     * - the second CSV column is used to provide the value
238
     *
239
     * @param string|int $offset_index The column index to serve as offset
240
     * @param string|int $value_index  The column index to serve as value
241
     *
242
     * @return Generator
243
     */
244 8
    public function fetchPairs($offset_index = 0, $value_index = 1): Generator
245
    {
246 8
        $offset = $this->getColumnIndex($offset_index, 'The offset index value  `%s` is invalid');
247 8
        $value = $this->getColumnIndex($value_index, 'The value index value `%s` is invalid');
248
249
        $filter = function (array $record) use ($offset): bool {
250 8
            return isset($record[$offset]);
251 8
        };
252
253 8
        $select = function (array $record) use ($offset, $value): array {
254 6
            return [$record[$offset], $record[$value] ?? null];
255 8
        };
256
257 8
        $iterator = new MapIterator(new CallbackFilterIterator($this->iterator, $filter), $select);
258 8
        foreach ($iterator as $pair) {
259 6
            yield $pair[0] => $pair[1];
260
        }
261 8
    }
262
263
    /**
264
     * Whether we should preserve the CSV document record offset.
265
     *
266
     * If set to true CSV document record offset will be added to
267
     * method output where it makes sense.
268
     *
269
     * @param bool $status
270
     *
271
     * @return self
272
     */
273 4
    public function preserveRecordOffset(bool $status): self
274
    {
275 4
        $this->preserve_offset = $status;
276
277 4
        return $this;
278
    }
279
}
280