Completed
Pull Request — master (#210)
by ignace nyamagana
04:08
created

Reader::getHeaderOffset()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
crap 1
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
declare(strict_types=1);
14
15
namespace League\Csv;
16
17
use CallbackFilterIterator;
18
use Countable;
19
use DomDocument;
20
use Generator;
21
use Iterator;
22
use IteratorAggregate;
23
use JsonSerializable;
24
use LimitIterator;
25
use SplFileObject;
26
27
/**
28
 *  A class to manage extracting and filtering a CSV
29
 *
30
 * @package League.csv
31
 * @since  3.0.0
32
 *
33
 */
34
class Reader extends AbstractCsv implements JsonSerializable, Countable, IteratorAggregate
35
{
36
    /**
37
     * @inheritdoc
38
     */
39
    protected $stream_filter_mode = STREAM_FILTER_READ;
40
41
    /**
42
     * CSV Document header offset
43
     *
44
     * @var int|null
45
     */
46
    protected $header_offset;
47
48
    /**
49
     * Returns the record offset used as header
50
     *
51
     * If no CSV record is used this method MUST return null
52
     *
53
     * @return int|null
54
     */
55 102
    public function getHeaderOffset()
56
    {
57 102
        return $this->header_offset;
58
    }
59
60
    /**
61
     * Selects the record to be used as the CSV header
62
     *
63
     * Because of the header is represented as an array, to be valid
64
     * a header MUST contain only unique string value.
65
     *
66
     * @param int|null $offset the header row offset
67
     *
68
     * @return $this
69
     */
70 22
    public function setHeaderOffset($offset): self
71
    {
72 22
        $this->header_offset = null;
73 22
        if (null !== $offset) {
74 18
            $this->header_offset = $this->filterInteger(
75
                $offset,
76 18
                0,
77 18
                'the header offset index must be a positive integer or 0'
78
            );
79
        }
80
81 20
        return $this;
82
    }
83
84
    /**
85
     * Detect Delimiters occurences in the CSV
86
     *
87
     * Returns a associative array where each key represents
88
     * a valid delimiter and each value the number of occurences
89
     *
90
     * @param string[] $delimiters the delimiters to consider
91
     * @param int      $nb_rows    Detection is made using $nb_rows of the CSV
92
     *
93
     * @return array
94
     */
95 8
    public function fetchDelimitersOccurrence(array $delimiters, int $nb_rows = 1): array
96
    {
97 8
        $nb_rows = $this->filterInteger($nb_rows, 1, 'The number of rows to consider must be a valid positive integer');
98
        $filter_row = function ($row) {
99 6
            return is_array($row) && count($row) > 1;
100 6
        };
101 6
        $delimiters = array_unique(array_filter($delimiters, function ($value) {
102 6
            return 1 == strlen($value);
103 6
        }));
104 6
        $this->document->setFlags(SplFileObject::READ_CSV);
105 6
        $res = [];
106 6
        foreach ($delimiters as $delim) {
107 6
            $this->document->setCsvControl($delim, $this->enclosure, $this->escape);
108 6
            $iterator = new CallbackFilterIterator(new LimitIterator($this->document, 0, $nb_rows), $filter_row);
109 6
            $res[$delim] = count(iterator_to_array($iterator, false), COUNT_RECURSIVE);
110
        }
111 6
        arsort($res, SORT_NUMERIC);
112
113 6
        return $res;
114
    }
115
116
    /**
117
     * Returns a collection of selected records
118
     *
119
     * @param Statement|null $stmt
120
     *
121
     * @return RecordSet
122
     */
123 86
    public function select(Statement $stmt = null): RecordSet
124
    {
125 86
        $stmt = $stmt ?: new Statement();
126
127 86
        return $stmt->process($this);
128
    }
129
130
    /**
131
     * @inheritdoc
132
     */
133 2
    public function count(): int
134
    {
135 2
        return iterator_count($this->getIterator());
136
    }
137
138
    /**
139
     * @inheritdoc
140
     */
141 122
    public function getIterator(): Iterator
142
    {
143 122
        $this->document->setFlags(SplFileObject::READ_CSV | SplFileObject::READ_AHEAD | SplFileObject::SKIP_EMPTY);
144 122
        $this->document->setCsvControl($this->delimiter, $this->enclosure, $this->escape);
145
146 122
        return $this->document;
147
    }
148
149
    /**
150
     * @inheritdoc
151
     */
152 2
    public function jsonSerialize()
153
    {
154 2
        return $this->select()->jsonSerialize();
155
    }
156
157
    /**
158
     * Returns the column header associate with the RecordSet
159
     *
160
     * @return string[]
161
     */
162 2
    public function getHeader()
163
    {
164 2
        return $this->select()->getHeader();
165
    }
166
167
    /**
168
     * Returns a HTML table representation of the CSV Table
169
     *
170
     * @param string $class_attr optional classname
171
     *
172
     * @return string
173
     */
174 2
    public function toHTML(string $class_attr = 'table-csv-data'): string
175
    {
176 2
        return $this->select()->toHTML($class_attr);
177
    }
178
179
    /**
180
     * Transforms a CSV into a XML
181
     *
182
     * @param string $root_name XML root node name
183
     * @param string $row_name  XML row node name
184
     * @param string $cell_name XML cell node name
185
     *
186
     * @return DomDocument
187
     */
188 2
    public function toXML(string $root_name = 'csv', string $row_name = 'row', string $cell_name = 'cell'): DomDocument
189
    {
190 2
        return $this->select()->toXML($root_name, $row_name, $cell_name);
191
    }
192
193
    /**
194
     * Returns a sequential array of all CSV lines
195
     *
196
     * @return array
197
     */
198 42
    public function fetchAll(): array
199
    {
200 42
        return $this->select()->fetchAll();
201
    }
202
203
    /**
204
     * Returns a single row from the CSV
205
     *
206
     * By default if no offset is provided the first row of the CSV is selected
207
     *
208
     * @param int $offset the CSV row offset
209
     *
210
     * @return array
211
     */
212 6
    public function fetchOne(int $offset = 0): array
213
    {
214 6
        return $this->select()->fetchOne($offset);
215
    }
216
217
    /**
218
     * Returns the next value from a single CSV column
219
     *
220
     * By default if no column index is provided the first column of the CSV is selected
221
     *
222
     * @param string|int $column_index CSV column index
223
     *
224
     * @return Iterator
225
     */
226 10
    public function fetchColumn($column_index = 0): Iterator
227
    {
228 10
        return $this->select()->fetchColumn($column_index);
229
    }
230
231
    /**
232
     * Fetches the next key-value pairs from a result set (first
233
     * column is the key, second column is the value).
234
     *
235
     * By default if no column index is provided:
236
     * - the first CSV column is used to provide the keys
237
     * - the second CSV column is used to provide the value
238
     *
239
     * @param string|int $offset_index The column index to serve as offset
240
     * @param string|int $value_index  The column index to serve as value
241
     *
242
     * @return Generator
243
     */
244 8
    public function fetchPairs($offset_index = 0, $value_index = 1)
245
    {
246 8
        return $this->select()->fetchPairs($offset_index, $value_index);
247
    }
248
}
249