Completed
Pull Request — master (#178)
by ignace nyamagana
02:30
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 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
namespace League\Csv;
14
15
use CallbackFilterIterator;
16
use Countable;
17
use DOMDocument;
18
use Generator;
19
use InvalidArgumentException;
20
use Iterator;
21
use IteratorAggregate;
22
use JsonSerializable;
23
use League\Csv\Config\Validator;
24
use LimitIterator;
25
26
/**
27
 * A class to extract and convert data from a CSV
28
 *
29
 * @package League.csv
30
 * @since  9.0.0
31
 *
32
 */
33
class RecordSet implements Countable, IteratorAggregate, JsonSerializable
34
{
35
    use Validator;
36
37
    /**
38
     * @var array
39
     */
40
    protected $header;
41
42
    /**
43
     * @var array
44
     */
45
    protected $flip_header;
46
47
    /**
48
     * @var Iterator
49
     */
50
    protected $iterator;
51
52
    /**
53
     * New Instance
54
     *
55
     * @param Iterator $iterator
56
     * @param array    $header
57
     */
58
    public function __construct(Iterator $iterator, array $header)
59
    {
60
        $this->iterator = $iterator;
61
        $this->header = $header;
62
        $this->flip_header = array_flip($header);
63
    }
64
65
    /**
66
     * @inheritdoc
67
     */
68
    public function __destruct()
69
    {
70
        $this->iterator = null;
71
    }
72
73
    /**
74
     * @inheritdoc
75
     */
76
    public function getIterator()
77
    {
78
        return $this->iterator;
79
    }
80
81
    /**
82
     * Returns the object header
83
     *
84
     * @return string[]
85
     */
86
    public function getHeader()
87
    {
88
        return $this->header;
89
    }
90
91
    /**
92
     * Returns a HTML table representation of the CSV Table
93
     *
94
     * @param string $class_attr optional classname
95
     *
96
     * @return string
97
     */
98
    public function toHTML($class_attr = 'table-csv-data')
99
    {
100
        $doc = $this->toXML('table', 'tr', 'td');
101
        $doc->documentElement->setAttribute('class', $class_attr);
102
103
        return $doc->saveHTML($doc->documentElement);
104
    }
105
106
    /**
107
     * Transforms a CSV into a XML
108
     *
109
     * @param string $root_name XML root node name
110
     * @param string $row_name  XML row node name
111
     * @param string $cell_name XML cell node name
112
     *
113
     * @return DOMDocument
114
     */
115
    public function toXML($root_name = 'csv', $row_name = 'row', $cell_name = 'cell')
116
    {
117
        $this->row_name = $this->validateString($row_name);
118
        $this->cell_name = $this->validateString($cell_name);
119
        $doc = new DOMDocument('1.0', 'UTF-8');
120
        $root = $doc->createElement($this->validateString($root_name));
121
        if (!empty($this->header)) {
122
            $root->appendChild($this->convertRecordToDOMNode($this->header, $doc));
123
        }
124
125
        foreach ($this->iterator as $row) {
126
            $root->appendChild($this->convertRecordToDOMNode($row, $doc));
127
        }
128
        $doc->appendChild($root);
129
130
        return $doc;
131
    }
132
133
    /**
134
     * @inheritdoc
135
     */
136
    public function count()
137
    {
138
        return iterator_count($this);
139
    }
140
141
    /**
142
     * @inheritdoc
143
     */
144
    public function jsonSerialize()
145
    {
146
        return $this->fetchAll();
147
    }
148
149
    /**
150
     * Returns a sequential array of all founded RecordSet
151
     *
152
     * @return array
153
     */
154
    public function fetchAll()
155
    {
156
        return iterator_to_array($this, false);
157
    }
158
159
    /**
160
     * Returns a single record from the recordSet
161
     *
162
     * @param int $offset the record offset relative to the RecordSet
163
     *
164
     * @return array
165
     */
166
    public function fetchOne($offset = 0)
167
    {
168
        $offset = $this->validateInteger($offset, 0, 'the submitted offset is invalid');
169
        $it = new LimitIterator($this->iterator, $offset, 1);
170
        $it->rewind();
171
172
        return (array) $it->current();
173
    }
174
175
    /**
176
     * Returns the next value from a specific record column
177
     *
178
     * By default if no column index is provided the first column of the founded RecordSet is returned
179
     *
180
     * @param string|int $column_index CSV column index or header field name
181
     *
182
     * @return Iterator
183
     */
184
    public function fetchColumn($column_index = 0)
185
    {
186
        $column_index = $this->filterFieldName($column_index, 'the column index value is invalid');
187
        $filter = function ($row) use ($column_index) {
188
            return isset($row[$column_index]);
189
        };
190
        $select = function ($row) use ($column_index) {
191
            return $row[$column_index];
192
        };
193
194
        return new MapIterator(new CallbackFilterIterator($this->iterator, $filter), $select);
195
    }
196
197
    /**
198
     * Filter a field 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 InvalidArgumentException if the field is invalid
204
     *
205
     * @return string|int
206
     */
207
    protected function filterFieldName($field, $error_message)
208
    {
209
        if (false !== array_search($field, $this->header, true)) {
210
            return $field;
211
        }
212
213
        $index = $this->validateInteger($field, 0, $error_message);
214
        if (empty($this->header)) {
215
            return $index;
216
        }
217
218
        if (false !== ($index = array_search($index, $this->flip_header, true))) {
219
            return $index;
220
        }
221
222
        throw new InvalidArgumentException($error_message);
223
    }
224
225
    /**
226
     * Fetches the next key-value pairs from a result set (first
227
     * column is the key, second column is the value).
228
     *
229
     * By default if no column index is provided:
230
     * - the first CSV column is used to provide the keys
231
     * - the second CSV column is used to provide the value
232
     *
233
     * @param string|int $offset_index The field index or name to serve as offset
234
     * @param string|int $value_index  The field index or name to serve as value
235
     *
236
     * @return Generator
237
     */
238
    public function fetchPairs($offset_index = 0, $value_index = 1)
239
    {
240
        $offset_index = $this->filterFieldName($offset_index, 'the offset column index is invalid');
241
        $value_index = $this->filterFieldName($value_index, 'the value column index is invalid');
242
        $filter = function ($row) use ($offset_index) {
243
            return isset($row[$offset_index]);
244
        };
245
        $select = function ($row) use ($offset_index, $value_index) {
246
            return [$row[$offset_index], isset($row[$value_index]) ? $row[$value_index] : null];
247
        };
248
249
        $iterator = new MapIterator(new CallbackFilterIterator($this->iterator, $filter), $select);
250
        foreach ($iterator as $row) {
251
            yield $row[0] => $row[1];
252
        }
253
    }
254
}
255