Completed
Pull Request — master (#210)
by ignace nyamagana
02:41
created

Reader::fetchDelimitersOccurrence()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 21
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 21
ccs 8
cts 8
cp 1
rs 9.3142
c 0
b 0
f 0
cc 3
eloc 15
nc 2
nop 2
crap 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 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 159
     *
44
     * @var int|null
45 159
     */
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
    public function getHeaderOffset()
56 159
    {
57
        return $this->header_offset;
58 159
    }
59 75
60
    /**
61
     * Selects the record to be used as the CSV header
62 144
     *
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
    public function setHeaderOffset($offset): self
71
    {
72
        $this->header_offset = null;
73
        if (null !== $offset) {
74 63
            $this->header_offset = $this->filterInteger(
75
                $offset,
76 63
                0,
77
                'the header offset index must be a positive integer or 0'
78
            );
79
        }
80
81
        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 9
     *
90
     * @param string[] $delimiters the delimiters to consider
91 9
     * @param int      $nb_rows    Detection is made using $nb_rows of the CSV
92 9
     *
93 9
     * @return array
94 9
     */
95 6
    public function fetchDelimitersOccurrence(array $delimiters, int $nb_rows = 1): array
96 9
    {
97 9
        $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 9
        };
101 9
        $delimiters = array_unique(array_filter($delimiters, function ($value) {
102 6
            return 1 == strlen($value);
103
        }));
104 9
        $csv = $this->getDocument();
105
        $csv->setFlags(SplFileObject::READ_CSV);
106
        $res = [];
107
        foreach ($delimiters as $delim) {
108
            $csv->setCsvControl($delim, $this->enclosure, $this->escape);
109
            $iterator = new CallbackFilterIterator(new LimitIterator($csv, 0, $nb_rows), $filter_row);
110
            $res[$delim] = count(iterator_to_array($iterator, false), COUNT_RECURSIVE);
111
        }
112
        arsort($res, SORT_NUMERIC);
113
114
        return $res;
115
    }
116 12
117
    /**
118 12
     * Returns a collection of selected records
119 12
     *
120 12
     * @param Statement|null $stmt
121 12
     *
122
     * @return RecordSet
123 12
     */
124
    public function select(Statement $stmt = null): RecordSet
125
    {
126
        $stmt = $stmt ?: new Statement();
127
128
        return $stmt->process($this);
129
    }
130
131
    /**
132
     * @inheritdoc
133
     */
134
    public function count(): int
135
    {
136
        return count($this->select());
137
    }
138 21
139
    /**
140 21
     * @inheritdoc
141
     */
142
    public function getIterator(): Iterator
143 18
    {
144 18
        return $this->select()->getIterator();
145
    }
146
147 15
    /**
148 18
     * @inheritdoc
149
     */
150 18
    public function jsonSerialize()
151 18
    {
152 18
        return $this->select()->jsonSerialize();
153 18
    }
154
155 18
    /**
156
     * Returns a HTML table representation of the CSV Table
157
     *
158
     * @param string $class_attr optional classname
159
     *
160
     * @return string
161
     */
162
    public function toHTML(string $class_attr = 'table-csv-data'): string
163
    {
164
        return $this->select()->toHTML($class_attr);
165
    }
166
167
    /**
168
     * Transforms a CSV into a XML
169
     *
170
     * @param string $root_name XML root node name
171
     * @param string $row_name  XML row node name
172
     * @param string $cell_name XML cell node name
173
     *
174 27
     * @return DomDocument
175
     */
176 27
    public function toXML(string $root_name = 'csv', string $row_name = 'row', string $cell_name = 'cell'): DomDocument
177 27
    {
178
        return $this->select()->toXML($root_name, $row_name, $cell_name);
179 27
    }
180 27
181
    /**
182
     * Returns a sequential array of all CSV lines
183 24
     *
184 24
     * @return array
185 16
     */
186 27
    public function fetchAll(): array
187
    {
188 27
        return $this->select()->fetchAll();
189 27
    }
190 27
191 27
    /**
192
     * Returns a single row from the CSV
193 27
     *
194
     * By default if no offset is provided the first row of the CSV is selected
195
     *
196
     * @param int $offset the CSV row offset
197
     *
198
     * @return array
199
     */
200
    public function fetchOne(int $offset = 0): array
201
    {
202
        return $this->select()->fetchOne($offset);
203 27
    }
204
205 27
    /**
206 24
     * Returns the next value from a single CSV column
207 18
     *
208 27
     * By default if no column index is provided the first column of the CSV is selected
209
     *
210
     * @param string|int $column_index CSV column index
211
     *
212
     * @return Iterator
213
     */
214
    public function fetchColumn($column_index = 0): Iterator
215
    {
216
        return $this->select()->fetchColumn($column_index);
217
    }
218
219
    /**
220
     * Fetches the next key-value pairs from a result set (first
221
     * column is the key, second column is the value).
222
     *
223
     * By default if no column index is provided:
224
     * - the first CSV column is used to provide the keys
225 39
     * - the second CSV column is used to provide the value
226
     *
227 39
     * @param string|int $offset_index The column index to serve as offset
228 27
     * @param string|int $value_index  The column index to serve as value
229
     *
230 27
     * @return Generator
231 6
     */
232 4
    public function fetchPairs($offset_index = 0, $value_index = 1)
233
    {
234 27
        return $this->select()->fetchPairs($offset_index, $value_index);
235 27
    }
236
}
237