Completed
Pull Request — master (#178)
by ignace nyamagana
02:40
created

RecordSet::fetchPairs()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 16
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 16
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 10
nc 2
nop 2
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 8.1.1
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
namespace League\Csv;
14
15
use CallbackFilterIterator;
16
use Countable;
17
use DOMDocument;
18
use DOMElement;
19
use Generator;
20
use InvalidArgumentException;
21
use Iterator;
22
use IteratorAggregate;
23
use JsonSerializable;
24
use League\Csv\Config\Validator;
25
use LimitIterator;
26
use OutOfRangeException;
27
28
/**
29
 * A class to extract and convert data from a CSV
30
 *
31
 * @package League.csv
32
 * @since  3.0.0
33
 *
34
 */
35
class RecordSet implements Countable, IteratorAggregate, JsonSerializable
36
{
37
    use Validator;
38
39
    /**
40
     * @var array
41
     */
42
    protected $header;
43
44
    /**
45
     * @var array
46
     */
47
    protected $flip_header;
48
49
    /**
50
     * @var int
51
     */
52
    protected $header_column_count;
53
54
    /**
55
     * @var Iterator
56
     */
57
    protected $iterator;
58
59
    /**
60
     * New Instance
61
     *
62
     * @param Iterator $iterator
63
     * @param array    $header
64
     */
65
    public function __construct(Iterator $iterator, array $header)
66
    {
67
        $this->header = $header;
68
        $this->flip_header = array_flip($header);
69
        $this->header_column_count = count($header);
70
        $this->iterator = $this->formatIterator($iterator);
71
    }
72
73
    /**
74
     * Apply CSV header to the return iterator
75
     *
76
     * @param Iterator $iterator
77
     * @param array    $header
0 ignored issues
show
Bug introduced by
There is no parameter named $header. 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...
78
     *
79
     * @throws OutOfRangeException if the column is inconsistent
80
     *
81
     * @return Iterator
82
     */
83
    protected function formatIterator(Iterator $iterator)
84
    {
85
        if (0 === $this->header_column_count) {
86
            return $iterator;
87
        }
88
89
        $combine_array = function (array $row) {
90
            if ($this->header_column_count != count($row)) {
91
                throw new OutOfRangeException('The record column count differs from the header column count');
92
            }
93
94
            return array_combine($this->header, $row);
95
        };
96
97
        return new MapIterator($iterator, $combine_array);
98
    }
99
100
    /**
101
     * @inheritdoc
102
     */
103
    public function __destruct()
104
    {
105
        $this->iterator = null;
106
    }
107
108
    /**
109
     * Returns a HTML table representation of the CSV Table
110
     *
111
     * @param string $class_attr optional classname
112
     *
113
     * @return string
114
     */
115
    public function toHTML($class_attr = 'table-csv-data')
116
    {
117
        $doc = $this->toXML('table', 'tr', 'td');
118
        $doc->documentElement->setAttribute('class', $class_attr);
119
120
        return $doc->saveHTML($doc->documentElement);
121
    }
122
123
    /**
124
     * Transforms a CSV into a XML
125
     *
126
     * @param string $root_name XML root node name
127
     * @param string $row_name  XML row node name
128
     * @param string $cell_name XML cell node name
129
     *
130
     * @return DOMDocument
131
     */
132
    public function toXML($root_name = 'csv', $row_name = 'row', $cell_name = 'cell')
133
    {
134
        $doc = new DOMDocument('1.0', 'UTF-8');
135
        $root = $doc->createElement($root_name);
136
137
        if (0 < $this->header_column_count) {
138
            $root->appendChild($this->convertRowToXML($this->header, $doc, $row_name, $cell_name));
139
        }
140
141
        foreach ($this->iterator as $row) {
142
            $root->appendChild($this->convertRowToXML($row, $doc, $row_name, $cell_name));
143
        }
144
        $doc->appendChild($root);
145
146
        return $doc;
147
    }
148
149
    /**
150
     * Convert a row into a DOMElement
151
     *
152
     * @param array       $row       Csv record
153
     * @param DOMDocument $root
0 ignored issues
show
Bug introduced by
There is no parameter named $root. 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...
154
     * @param string      $row_name  XML row node name
155
     * @param string      $cell_name XML cell node name
156
     *
157
     * @return DOMElement
158
     */
159
    protected function convertRowToXML(array $row, DOMDocument $doc, $row_name, $cell_name)
160
    {
161
        $node = $doc->createElement($row_name);
162
        foreach ($row as $value) {
163
            $cell = $doc->createElement($cell_name);
164
            $cell->appendChild($doc->createTextNode($value));
165
            $node->appendChild($cell);
166
        }
167
168
        return $node;
169
    }
170
171
    /**
172
     * @inheritdoc
173
     */
174
    public function getIterator()
175
    {
176
        return $this->iterator;
177
    }
178
179
    /**
180
     * @inheritdoc
181
     */
182
    public function count()
183
    {
184
        return iterator_count($this);
185
    }
186
187
    /**
188
     * @inheritdoc
189
     */
190
    public function jsonSerialize()
191
    {
192
        return $this->fetchAll();
193
    }
194
195
    /**
196
     * Returns a sequential array of all founded RecordSet
197
     *
198
     * @return array
199
     */
200
    public function fetchAll()
201
    {
202
        return iterator_to_array($this, false);
203
    }
204
205
    /**
206
     * Returns a single record from the recordSet
207
     *
208
     * @param int $offset the record offset relative to the RecordSet
209
     *
210
     * @return array
211
     */
212
    public function fetchOne($offset = 0)
213
    {
214
        $offset = $this->validateInteger($offset, 0, 'the offset valid is invalid');
215
        $it = new LimitIterator($this->iterator, $offset, 1);
216
        $it->rewind();
217
218
        return (array) $it->current();
219
    }
220
221
    /**
222
     * Returns the next value from a specific record column
223
     *
224
     * By default if no column index is provided the first column of the founded RecordSet is returned
225
     *
226
     * @param string|int $column_index CSV column index or header field name
227
     *
228
     * @return Iterator
229
     */
230
    public function fetchColumn($column_index = 0)
231
    {
232
        $column_index = $this->filterFieldName($column_index, 'the column index value is invalid');
233
        $filter = function ($row) use ($column_index) {
234
            return isset($row[$column_index]);
235
        };
236
        $select = function ($row) use ($column_index) {
237
            return $row[$column_index];
238
        };
239
240
        return new MapIterator(new CallbackFilterIterator($this->iterator, $filter), $select);
241
    }
242
243
    /**
244
     * Filter a field name against the CSV header if any
245
     *
246
     * @param string|int $field         the field name or the field index
247
     * @param string     $error_message the associated error message
248
     *
249
     * @throws InvalidArgumentException if the field is invalid
250
     *
251
     * @return string|int
252
     */
253
    protected function filterFieldName($field, $error_message)
254
    {
255
        if (false !== array_search($field, $this->header, true)) {
256
            return $field;
257
        }
258
259
        $index = $this->validateInteger($field, 0, $error_message);
260
        if (empty($this->header)) {
261
            return $index;
262
        }
263
264
        if (false !== ($index = array_search($index, $this->flip_header, true))) {
265
            return $index;
266
        }
267
268
        throw new InvalidArgumentException($error_message);
269
    }
270
271
    /**
272
     * Fetches the next key-value pairs from a result set (first
273
     * column is the key, second column is the value).
274
     *
275
     * By default if no column index is provided:
276
     * - the first CSV column is used to provide the keys
277
     * - the second CSV column is used to provide the value
278
     *
279
     * @param string|int $offset_index The field index or name to serve as offset
280
     * @param string|int $value_index  The field index or name to serve as value
281
     *
282
     * @return Generator
283
     */
284
    public function fetchPairs($offset_index = 0, $value_index = 1)
285
    {
286
        $offset_index = $this->filterFieldName($offset_index, 'the offset column index is invalid');
287
        $value_index = $this->filterFieldName($value_index, 'the value column index is invalid');
288
        $filter = function ($row) use ($offset_index) {
289
            return isset($row[$offset_index]);
290
        };
291
        $select = function ($row) use ($offset_index, $value_index) {
292
            return [$row[$offset_index], isset($row[$value_index]) ? $row[$value_index] : null];
293
        };
294
295
        $iterator = new MapIterator(new CallbackFilterIterator($this->iterator, $filter), $select);
296
        foreach ($iterator as $row) {
297
            yield $row[0] => $row[1];
298
        }
299
    }
300
}
301