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

RecordSet::applyHeader()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 17
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

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