Completed
Pull Request — master (#210)
by ignace nyamagana
06:59
created

Reader::fetchDelimitersOccurrence()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 20
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 20
ccs 15
cts 15
cp 1
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 14
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 Iterator;
19
use IteratorAggregate;
20
use LimitIterator;
21
use SplFileObject;
22
23
/**
24
 *  A class to manage extracting and filtering a CSV
25
 *
26
 * @package League.csv
27
 * @since  3.0.0
28
 *
29
 */
30
class Reader extends AbstractCsv implements IteratorAggregate
31
{
32
    /**
33
     * @inheritdoc
34
     */
35
    protected $stream_filter_mode = STREAM_FILTER_READ;
36
37
    /**
38
     * CSV Document header offset
39
     *
40
     * @var int|null
41
     */
42
    protected $header_offset;
43
44
    /**
45
     * Returns the record offset used as header
46
     *
47
     * If no CSV record is used this method MUST return null
48
     *
49
     * @return int|null
50
     */
51 14
    public function getHeaderOffset()
52
    {
53 14
        return $this->header_offset;
54
    }
55
56
    /**
57
     * Selects the record to be used as the CSV header
58
     *
59
     * Because of the header is represented as an array, to be valid
60
     * a header MUST contain only unique string value.
61
     *
62
     * @param int|null $offset the header row offset
63
     *
64
     * @return static
65
     */
66 26
    public function setHeaderOffset($offset): self
67
    {
68 26
        $this->header_offset = null;
69 26
        if (null !== $offset) {
70 22
            $this->header_offset = $this->filterInteger(
71
                $offset,
72 22
                0,
73 22
                'the header offset index must be a positive integer or 0'
74
            );
75
        }
76
77 24
        return $this;
78
    }
79
80
    /**
81
     * Detect Delimiters occurences in the CSV
82
     *
83
     * Returns a associative array where each key represents
84
     * a valid delimiter and each value the number of occurences
85
     *
86
     * @param string[] $delimiters the delimiters to consider
87
     * @param int      $nb_rows    Detection is made using $nb_rows of the CSV
88
     *
89
     * @return array
90
     */
91 8
    public function fetchDelimitersOccurrence(array $delimiters, int $nb_rows = 1): array
92
    {
93 8
        $nb_rows = $this->filterInteger($nb_rows, 1, 'The number of rows to consider must be a valid positive integer');
94
        $filter_row = function ($row) {
95 6
            return is_array($row) && count($row) > 1;
96 6
        };
97 6
        $delimiters = array_unique(array_filter($delimiters, function ($value) {
98 6
            return 1 == strlen($value);
99 6
        }));
100 6
        $this->document->setFlags(SplFileObject::READ_CSV);
101 6
        $res = [];
102 6
        foreach ($delimiters as $delim) {
103 6
            $this->document->setCsvControl($delim, $this->enclosure, $this->escape);
104 6
            $iterator = new CallbackFilterIterator(new LimitIterator($this->document, 0, $nb_rows), $filter_row);
105 6
            $res[$delim] = count(iterator_to_array($iterator, false), COUNT_RECURSIVE);
106
        }
107 6
        arsort($res, SORT_NUMERIC);
108
109 6
        return $res;
110
    }
111
112
    /**
113
     * Returns a collection of selected records
114
     *
115
     * @param Statement|null $stmt
116
     *
117
     * @return RecordSet
118
     */
119 78
    public function select(Statement $stmt = null): RecordSet
120
    {
121 78
        $stmt = $stmt ?: new Statement();
122
123 78
        return $stmt->process($this);
124
    }
125
126
    /**
127
     * @inheritdoc
128
     */
129 112
    public function getIterator(): Iterator
130
    {
131 112
        $this->document->setFlags(SplFileObject::READ_CSV | SplFileObject::READ_AHEAD | SplFileObject::SKIP_EMPTY);
132 112
        $this->document->setCsvControl($this->delimiter, $this->enclosure, $this->escape);
133
134 112
        return $this->document;
135
    }
136
137
    /**
138
     * Returns the column header associate with the RecordSet
139
     *
140
     * @throws Exception If no header is found
141
     *
142
     * @return string[]
143
     */
144 96
    public function getHeader(): array
145
    {
146 96
        if (null === $this->header_offset) {
147 78
            return [];
148
        }
149
150 18
        $csv = $this->getIterator();
151 18
        $csv->seek($this->header_offset);
152 18
        $header = $csv->current();
153 18
        if (empty($header)) {
154 2
            throw new Exception('The header record specified by `Reader::setHeaderOffset` does not exist or is empty');
155
        }
156
157 16
        if (0 !== $this->header_offset) {
158 4
            return $header;
159
        }
160
161 12
        return $this->removeBOM($header, mb_strlen($this->getInputBOM()), $this->enclosure);
162
    }
163
}
164