Completed
Push — master ( f97949...b57571 )
by Michael
02:55
created

YamlConfigFile::arraySet()   B

Complexity

Conditions 6
Paths 7

Size

Total Lines 23
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 42

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 23
ccs 0
cts 20
cp 0
rs 8.5906
cc 6
eloc 14
nc 7
nop 3
crap 42
1
<?php
2
declare(strict_types = 1);
3
/**
4
 * Contains class YamlConfigFile.
5
 *
6
 * PHP version 7.0+
7
 *
8
 * LICENSE:
9
 * This file is part of Yet Another Php Eve Api Library also know as Yapeal
10
 * which can be used to access the Eve Online API data and place it into a
11
 * database.
12
 * Copyright (C) 2016 Michael Cummings
13
 *
14
 * This program is free software: you can redistribute it and/or modify it
15
 * under the terms of the GNU Lesser General Public License as published by the
16
 * Free Software Foundation, either version 3 of the License, or (at your
17
 * option) any later version.
18
 *
19
 * This program is distributed in the hope that it will be useful, but WITHOUT
20
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
22
 * for more details.
23
 *
24
 * You should have received a copy of the GNU Lesser General Public License
25
 * along with this program. If not, see
26
 * <http://spdx.org/licenses/LGPL-3.0.html>.
27
 *
28
 * You should be able to find a copy of this license in the COPYING-LESSER.md
29
 * file. A copy of the GNU GPL should also be available in the COPYING.md file.
30
 *
31
 * @author    Michael Cummings <[email protected]>
32
 * @copyright 2016 Michael Cummings
33
 * @license   LGPL-3.0+
34
 */
35
namespace Yapeal\Cli\Yapeal;
36
37
use Symfony\Component\Yaml\Dumper;
38
use Symfony\Component\Yaml\Exception\ParseException;
39
use Symfony\Component\Yaml\Parser;
40
use Yapeal\FileSystem\SafeFileHandlingTrait;
41
42
/**
43
 * Class YamlConfigFile.
44
 */
45
class YamlConfigFile
46
{
47
    use SafeFileHandlingTrait;
48
    /**
49
     * YamlConfigFile constructor.
50
     *
51
     * @param string|null $pathFile
52
     * @param array|null  $settings
53
     *
54
     * @internal param string $fileName
55
     */
56
    public function __construct(string $pathFile = null, array $settings = null)
57
    {
58
        $this->pathFile = $pathFile;
59
        $this->settings = $settings;
0 ignored issues
show
Documentation Bug introduced by
It seems like $settings can be null. However, the property $settings is declared as array. Maybe change the type of the property to array|null or add a type check?

Our type inference engine has found an assignment of a scalar value (like a string, an integer or null) to a property which is an array.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property.

To type hint that a parameter can be either an array or null, you can set a type hint of array and a default value of null. The PHP interpreter will then accept both an array or null for that parameter.

function aContainsB(array $needle = null, array  $haystack) {
    if (!$needle) {
        return false;
    }

    return array_intersect($haystack, $needle) == $haystack;
}

The function can be called with either null or an array for the parameter $needle but will only accept an array as $haystack.

Loading history...
60
    }
61
    /**
62
     * @return string
63
     * @throws \LogicException
64
     */
65
    public function getPathFile(): string
66
    {
67
        if (null === $this->pathFile) {
68
            $mess = 'Trying to access $pathFile before it was set';
69
            throw new \LogicException($mess);
70
        }
71
        return $this->pathFile;
72
    }
73
    /**
74
     * @return array
75
     * @throws \LogicException
76
     */
77
    public function getSettings(): array
78
    {
79
        if (null === $this->settings) {
80
            $mess = 'Trying to access $settings before it was set';
81
            throw new \LogicException($mess);
82
        }
83
        return $this->settings;
84
    }
85
    /**
86
     * @return self
87
     * @throws \LogicException
88
     */
89
    public function read(): self
90
    {
91
        $data = $this->safeFileRead($this->getPathFile());
92
        if (false === $data) {
93
            $this->setSettings([]);
94
            return $this;
95
        }
96
        try {
97
            $data = (new Parser())->parse($data, true, false);
98
        } catch (ParseException $exc) {
99
            $this->setSettings([]);
100
            return $this;
101
        }
102
        $data = $this->flattenYaml($data);
103
        $this->setSettings($data);
104
        return $this;
105
    }
106
    /**
107
     * @throws \LogicException
108
     */
109
    public function save()
110
    {
111
        $data = $this->unflattenYaml($this->getSettings());
112
        $data = (new Dumper())->dump($data);
113
        $this->safeDataWrite($this->getPathFile(), $data);
114
    }
115
    /**
116
     * @param string $value
117
     *
118
     * @return self
119
     */
120
    public function setPathFile(string $value): self
121
    {
122
        $this->pathFile = $value;
123
        return $this;
124
    }
125
    /**
126
     * @param array $value
127
     */
128
    public function setSettings(array $value)
129
    {
130
        $this->settings = $value;
131
    }
132
    /**
133
     * @param array      $array
134
     * @param string|int $key
135
     * @param mixed      $value
136
     *
137
     * @return array
138
     */
139
    private function arraySet(array &$array, $key, $value): array
140
    {
141
        if (null === $key) {
142
            $array = $value;
143
            return $array;
144
        }
145
        if (is_int($key)) {
146
            $key = (string)$key;
147
        }
148
        $keys = explode('.', $key);
149
        while (1 < count($keys)) {
150
            $key = array_shift($keys);
151
            // If the key doesn't exist at this depth, we will just create an empty array
152
            // to hold the next value, allowing us to create the arrays to hold final
153
            // values at the correct depth. Then we'll keep digging into the array.
154
            if (!array_key_exists($key, $array) || !is_array($array[$key])) {
155
                $array[$key] = [];
156
            }
157
            $array = &$array[$key];
158
        }
159
        $array[array_shift($keys)] = $value;
160
        return $array;
161
    }
162
    /**
163
     * @param array $yaml
164
     *
165
     * @return array
166
     */
167
    private function flattenYaml(array $yaml): array
168
    {
169
        /**
170
         * @var \RecursiveIteratorIterator|\Traversable $rItIt
171
         */
172
        $rItIt = new \RecursiveIteratorIterator(new \RecursiveArrayIterator($yaml));
173
        $settings = [];
174
        foreach ($rItIt as $leafValue) {
175
            $keys = [];
176
            foreach (range(0, $rItIt->getDepth()) as $depth) {
177
                $keys[] = $rItIt->getSubIterator($depth)
178
                    ->key();
179
            }
180
            $settings[implode('.', $keys)] = $leafValue;
181
        }
182
        return $settings;
183
    }
184
    /**
185
     * @param array $yaml
186
     *
187
     * @return array
188
     */
189
    private function unflattenYaml(array $yaml): array
190
    {
191
        $output = [];
192
        foreach ($yaml as $key => $value) {
193
            $this->arraySet($output, $key, $value);
194
            if (is_array($value) && false !== strpos($key, '.')) {
195
                $nested = $this->unflattenYaml($value);
196
                $output[$key] = $nested;
197
            }
198
        }
199
        return $output;
200
    }
201
    /**
202
     * @var string $pathFile
203
     */
204
    private $pathFile;
205
    /**
206
     * @var array $settings
207
     */
208
    private $settings;
209
}
210