Completed
Pull Request — master (#1606)
by James
05:16 queued 03:28
created

IniParser::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 3
cts 3
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
crap 1
1
<?php
2
/**
3
 * This file is part of the browscap package.
4
 *
5
 * Copyright (c) 1998-2017, Browser Capabilities Project
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
declare(strict_types = 1);
12
namespace Browscap\Parser;
13
14
final class IniParser implements ParserInterface
15
{
16
    /**
17
     * @var string
18
     */
19
    private $filename;
20
21
    /**
22
     * @var bool
23
     */
24
    private $shouldSort = false;
25
26
    /**
27
     * @var array
28
     */
29
    private $data;
30
31
    /**
32
     * @var array
33
     */
34
    private $fileLines;
35
36 12
    public function __construct(string $filename)
37
    {
38 12
        $this->filename = $filename;
39 12
    }
40
41 4
    public function setShouldSort(bool $shouldSort) : void
42
    {
43 4
        $this->shouldSort = $shouldSort;
44 4
    }
45
46 3
    public function shouldSort() : bool
47
    {
48 3
        return $this->shouldSort;
49
    }
50
51
    /**
52
     * @return array
53
     */
54 1
    public function getParsed() : array
55
    {
56 1
        return $this->data;
57
    }
58
59
    /**
60
     * @return string
61
     */
62 1
    public function getFilename() : string
63
    {
64 1
        return $this->filename;
65
    }
66
67
    /**
68
     * @throws \InvalidArgumentException
69
     *
70
     * @return array
71
     */
72 3
    public function getLinesFromFile() : array
73
    {
74 3
        $filename = $this->filename;
75
76 3
        if (!file_exists($filename)) {
77 1
            throw new \InvalidArgumentException("File not found: {$filename}");
78
        }
79
80 2
        return file($filename, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
81
    }
82
83
    /**
84
     * @param string[] $fileLines
85
     */
86 4
    public function setFileLines(array $fileLines) : void
87
    {
88 4
        $this->fileLines = $fileLines;
89 4
    }
90
91
    /**
92
     * @return array
93
     */
94 5
    public function getFileLines() : array
95
    {
96 5
        if (!$this->fileLines) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->fileLines of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
97 1
            $fileLines = $this->getLinesFromFile();
98
        } else {
99 4
            $fileLines = $this->fileLines;
100
        }
101
102 5
        return $fileLines;
103
    }
104
105
    /**
106
     * @throws \RuntimeException
107
     *
108
     * @return array
109
     */
110 3
    public function parse() : array
111
    {
112 3
        $fileLines = $this->getFileLines();
113
114 3
        $data = [];
115
116 3
        $currentSection  = '';
117 3
        $currentDivision = '';
118
119 3
        for ($line = 0, $count = count($fileLines); $line < $count; ++$line) {
120 3
            $currentLine       = ($fileLines[$line]);
121 3
            $currentLineLength = mb_strlen($currentLine);
122
123 3
            if (0 === $currentLineLength) {
124 2
                continue;
125
            }
126
127 3
            if (';;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;' === mb_substr($currentLine, 0, 40)) {
128 2
                $currentDivision = trim(mb_substr($currentLine, 41));
129
130 2
                continue;
131
            }
132
133
            // We only skip comments that *start* with semicolon
134 3
            if (';' === $currentLine[0]) {
135 2
                continue;
136
            }
137
138 3
            if ('[' === $currentLine[0]) {
139 2
                $currentSection = mb_substr($currentLine, 1, ($currentLineLength - 2));
140
141 2
                continue;
142
            }
143
144 3
            $bits = explode('=', $currentLine);
145
146 3
            if (2 < count($bits)) {
147 1
                throw new \RuntimeException("Too many equals in line: {$currentLine}, in Division: {$currentDivision}");
148
            }
149
150 2
            if (2 > count($bits)) {
151 1
                $bits[1] = '';
152
            }
153
154 2
            $data[$currentSection][$bits[0]]   = $bits[1];
155 2
            $data[$currentSection]['Division'] = $currentDivision;
156
        }
157
158 2
        if ($this->shouldSort()) {
159 2
            $data = $this->sortArrayAndChildArrays($data);
160
        }
161
162 2
        $this->data = $data;
163
164 2
        return $data;
165
    }
166
167
    /**
168
     * @param array $array
169
     *
170
     * @return array
171
     */
172 4
    private function sortArrayAndChildArrays(array $array) : array
173
    {
174 4
        ksort($array);
175
176 4
        foreach (array_keys($array) as $key) {
177 4
            if (!is_array($array[$key]) || empty($array[$key])) {
178 4
                continue;
179
            }
180
181 3
            $array[$key] = $this->sortArrayAndChildArrays($array[$key]);
182
        }
183
184 4
        return $array;
185
    }
186
}
187