Ini   A
last analyzed

Complexity

Total Complexity 18

Size/Duplication

Total Lines 154
Duplicated Lines 0 %

Test Coverage

Coverage 53.19%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 18
eloc 61
dl 0
loc 154
ccs 50
cts 94
cp 0.5319
rs 10
c 1
b 0
f 0

5 Methods

Rating   Name   Duplication   Size   Complexity  
A parseIniString() 0 16 2
A __construct() 0 24 5
B cast() 0 39 7
A checkIni() 0 17 2
A parseSections() 0 11 2
1
<?php
2
3
/**
4
 * This file is part of the Phalcon Framework.
5
 *
6
 * (c) Phalcon Team <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE.txt
9
 * file that was distributed with this source code.
10
 */
11
12
declare(strict_types=1);
13
14
namespace Phalcon\Config\Adapter;
15
16
use Phalcon\Config;
17
use Phalcon\Config\Exception;
18
19
use function array_key_exists;
20
use function basename;
21
use function call_user_func_array;
22
use function is_array;
23
use function is_numeric;
24
use function is_string;
25
use function parse_ini_file;
26
use function preg_match;
27
use function strpos;
28
use function strtolower;
29
use function substr;
30
31
use const INI_SCANNER_RAW;
32
33
class Ini extends Config
34
{
35
    /**
36
     * Ini constructor.
37
     *
38
     * @param string   $filePath
39
     * @param null|int $mode
40
     *
41
     * @throws Exception
42
     */
43 21
    public function __construct(string $filePath, int $mode = null)
44
    {
45 21
        if (null === $mode) {
46 14
            $mode = INI_SCANNER_RAW;
47
        }
48
49 21
        $config    = [];
50 21
        $iniConfig = $this->checkIni($filePath, $mode);
51 21
        foreach ($iniConfig as $section => $directives) {
52 21
            if (is_array($directives)) {
53 21
                $sections = $this->parseSections($directives);
54
55 21
                if (count($sections) > 0) {
56 21
                    $config[$section] = call_user_func_array(
57
                        "array_replace_recursive",
58 21
                        $sections
59
                    );
60
                }
61
            } else {
62 1
                $config[$section] = $this->cast($directives);
63
            }
64
        }
65
66 21
        parent::__construct($config);
67 21
    }
68
69
    /**
70
     * We have to cast values manually because parse_ini_file() has a poor
71
     * implementation.
72
     *
73
     * @param array|string $ini
74
     *
75
     * @return array|bool|float|int|null|string
76
     */
77 21
    protected function cast($ini)
78
    {
79 21
        if (is_array($ini)) {
80 1
            foreach ($ini as $key => $value) {
81 1
                $ini[$key] = $this->cast($value);
82
            }
83
84 1
            return $ini;
85
        }
86
87
        /**
88
         * Map of values
89
         */
90 21
        $ini      = (string) $ini;
91 21
        $lowerIni = strtolower($ini);
92
        $map      = [
93 21
            "true"  => true,
94
            "yes"   => true,
95
            "on"    => true,
96
            "false" => false,
97
            "no"    => false,
98
            "off"   => false,
99
            "null"  => null,
100
        ];
101
102 21
        if (array_key_exists($lowerIni, $map)) {
103 17
            return $map[$lowerIni];
104
        }
105
106
        // Decode float/int
107 21
        if (is_string($ini) && is_numeric($ini)) {
108 20
            if (preg_match("/[.]+/", $ini)) {
109 17
                return (double) $ini;
110
            } else {
111 20
                return (int) $ini;
112
            }
113
        }
114
115 21
        return $ini;
116
    }
117
118
    /**
119
     * Build multidimensional array from string
120
     *
121
     * @param string $path
122
     * @param mixed  $value
123
     *
124
     * @return array
125
     */
126 21
    protected function parseIniString(string $path, $value): array
127
    {
128 21
        $value    = $this->cast($value);
129 21
        $position = strpos($path, ".");
130
131 21
        if (false === $position) {
132
            return [
133 21
                $path => $value,
134
            ];
135
        }
136
137 21
        $key  = substr($path, 0, $position);
138 21
        $path = substr($path, $position + 1);
139
140
        return [
141 21
            $key => $this->parseIniString($path, $value),
142
        ];
143
    }
144
145
    /**
146
     * @param string $filePath
147
     * @param int    $mode
148
     *
149
     * @return array
150
     * @throws Exception
151
     */
152 21
    private function checkIni(string $filePath, int $mode): array
153
    {
154 21
        $iniConfig = parse_ini_file(
155 21
            $filePath,
156 21
            true,
157 21
            $mode
158
        );
159
160 21
        if (false === $iniConfig) {
161
            throw new Exception(
162
                "Configuration file " .
163
                basename($filePath) .
164
                " cannot be loaded"
165
            );
166
        }
167
168 21
        return $iniConfig;
169
    }
170
171
    /**
172
     * @param array $directives
173
     *
174
     * @return array
175
     */
176 21
    private function parseSections(array $directives): array
177
    {
178 21
        $sections = [];
179 21
        foreach ($directives as $path => $lastValue) {
180 21
            $sections[] = $this->parseIniString(
181 21
                (string) $path,
182
                $lastValue
183
            );
184
        }
185
186 21
        return $sections;
187
    }
188
}
189