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

RecordSet::toXML()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 18
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

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