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

RecordSet   A

Complexity

Total Complexity 18

Size/Duplication

Total Lines 213
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 18
c 1
b 0
f 0
lcom 1
cbo 2
dl 0
loc 213
rs 10

12 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A __destruct() 0 4 1
A toHTML() 0 7 1
A toXML() 0 18 2
A getIterator() 0 4 1
A count() 0 4 1
A jsonSerialize() 0 4 1
A fetchAll() 0 4 1
A fetchOne() 0 8 1
A fetchColumn() 0 12 1
A filterFieldName() 0 17 4
A fetchPairs() 0 16 3
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 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  3.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
     * Returns a HTML table representation of the CSV Table
75
     *
76
     * @param string $class_attr optional classname
77
     *
78
     * @return string
79
     */
80
    public function toHTML($class_attr = 'table-csv-data')
81
    {
82
        $doc = $this->toXML('table', 'tr', 'td');
83
        $doc->documentElement->setAttribute('class', $class_attr);
84
85
        return $doc->saveHTML($doc->documentElement);
86
    }
87
88
    /**
89
     * Transforms a CSV into a XML
90
     *
91
     * @param string $root_name XML root node name
92
     * @param string $row_name  XML row node name
93
     * @param string $cell_name XML cell node name
94
     *
95
     * @return DomDocument
96
     */
97
    public function toXML($root_name = 'csv', $row_name = 'row', $cell_name = 'cell')
98
    {
99
        $doc = new DomDocument('1.0', 'UTF-8');
100
        $root = $doc->createElement($root_name);
101
        foreach ($this->iterator as $row) {
102
            $row_element = $doc->createElement($row_name);
103
            array_walk($row, function ($value) use (&$row_element, $doc, $cell_name) {
104
                $content = $doc->createTextNode($value);
105
                $cell = $doc->createElement($cell_name);
106
                $cell->appendChild($content);
107
                $row_element->appendChild($cell);
108
            });
109
            $root->appendChild($row_element);
110
        }
111
        $doc->appendChild($root);
112
113
        return $doc;
114
    }
115
116
    /**
117
     * @inheritdoc
118
     */
119
    public function getIterator()
120
    {
121
        return $this->iterator;
122
    }
123
124
    /**
125
     * @inheritdoc
126
     */
127
    public function count()
128
    {
129
        return iterator_count($this);
130
    }
131
132
    /**
133
     * @inheritdoc
134
     */
135
    public function jsonSerialize()
136
    {
137
        return $this->fetchAll();
138
    }
139
140
    /**
141
     * Returns a sequential array of all founded RecordSet
142
     *
143
     * @return array
144
     */
145
    public function fetchAll()
146
    {
147
        return iterator_to_array($this, false);
148
    }
149
150
    /**
151
     * Returns a single record from the recordSet
152
     *
153
     * @param int $offset the record offset relative to the RecordSet
154
     *
155
     * @return array
156
     */
157
    public function fetchOne($offset = 0)
158
    {
159
        $offset = $this->validateInteger($offset, 0, 'the offset valid is invalid');
160
        $it = new LimitIterator($this->iterator, $offset, 1);
161
        $it->rewind();
162
163
        return (array) $it->current();
164
    }
165
166
    /**
167
     * Returns the next value from a specific record column
168
     *
169
     * By default if no column index is provided the first column of the founded RecordSet is returned
170
     *
171
     * @param string|int $column_index CSV column index or header field name
172
     *
173
     * @return Iterator
174
     */
175
    public function fetchColumn($column_index = 0)
176
    {
177
        $column_index = $this->filterFieldName($column_index, 'the column index value is invalid');
178
        $filter = function ($row) use ($column_index) {
179
            return isset($row[$column_index]);
180
        };
181
        $select = function ($row) use ($column_index) {
182
            return $row[$column_index];
183
        };
184
185
        return new MapIterator(new CallbackFilterIterator($this->iterator, $filter), $select);
186
    }
187
188
    /**
189
     * Filter a field name against the CSV header if any
190
     *
191
     * @param string|int $field         the field name or the field index
192
     * @param string     $error_message the associated error message
193
     *
194
     * @throws InvalidArgumentException if the field is invalid
195
     *
196
     * @return string|int
197
     */
198
    protected function filterFieldName($field, $error_message)
199
    {
200
        if (false !== array_search($field, $this->header, true)) {
201
            return $field;
202
        }
203
204
        $index = $this->validateInteger($field, 0, $error_message);
205
        if (empty($this->header)) {
206
            return $index;
207
        }
208
209
        if (false !== ($index = array_search($index, $this->flip_header, true))) {
210
            return $index;
211
        }
212
213
        throw new InvalidArgumentException($error_message);
214
    }
215
216
    /**
217
     * Fetches the next key-value pairs from a result set (first
218
     * column is the key, second column is the value).
219
     *
220
     * By default if no column index is provided:
221
     * - the first CSV column is used to provide the keys
222
     * - the second CSV column is used to provide the value
223
     *
224
     * @param string|int $offset_index The field index or name to serve as offset
225
     * @param string|int $value_index  The field index or name to serve as value
226
     *
227
     * @return Generator
228
     */
229
    public function fetchPairs($offset_index = 0, $value_index = 1)
230
    {
231
        $offset_index = $this->filterFieldName($offset_index, 'the offset column index is invalid');
232
        $value_index = $this->filterFieldName($value_index, 'the value column index is invalid');
233
        $filter = function ($row) use ($offset_index) {
234
            return isset($row[$offset_index]);
235
        };
236
        $select = function ($row) use ($offset_index, $value_index) {
237
            return [$row[$offset_index], isset($row[$value_index]) ? $row[$value_index] : null];
238
        };
239
240
        $iterator = new MapIterator(new CallbackFilterIterator($this->iterator, $filter), $select);
241
        foreach ($iterator as $row) {
242
            yield $row[0] => $row[1];
243
        }
244
    }
245
}
246