Completed
Push — master ( b57571...eaf5ea )
by Michael
06:33
created

YamlConfigFile::getPathFile()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2.032

Importance

Changes 0
Metric Value
dl 0
loc 8
ccs 4
cts 5
cp 0.8
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 5
nc 2
nop 0
crap 2.032
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 5
    public function __construct(string $pathFile = null, array $settings = null)
57
    {
58 5
        $this->pathFile = $pathFile;
59 5
        $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 1
    public function getPathFile(): string
66
    {
67 1
        if (null === $this->pathFile) {
68 1
            $mess = 'Trying to access $pathFile before it was set';
69 1
            throw new \LogicException($mess);
70
        }
71
        return $this->pathFile;
72
    }
73
    /**
74
     * @return array
75
     * @throws \LogicException
76
     */
77 1
    public function getSettings(): array
78
    {
79 1
        if (null === $this->settings) {
80 1
            $mess = 'Trying to access $settings before it was set';
81 1
            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 1
    public function setPathFile(string $value): self
121
    {
122 1
        $this->pathFile = $value;
123 1
        return $this;
124
    }
125
    /**
126
     * @param array $value
127
     *
128
     * @return self
129
     */
130 1
    public function setSettings(array $value): self
131
    {
132 1
        $this->settings = $value;
133 1
        return $this;
134
    }
135
    /**
136
     * @param array      $array
137
     * @param string|int $key
138
     * @param mixed      $value
139
     *
140
     * @return array
141
     */
142
    private function arraySet(array &$array, $key, $value): array
143
    {
144
        if (null === $key) {
145
            $array = $value;
146
            return $array;
147
        }
148
        if (is_int($key)) {
149
            $key = (string)$key;
150
        }
151
        $keys = explode('.', $key);
152
        while (1 < count($keys)) {
153
            $key = array_shift($keys);
154
            // If the key doesn't exist at this depth, we will just create an empty array
155
            // to hold the next value, allowing us to create the arrays to hold final
156
            // values at the correct depth. Then we'll keep digging into the array.
157
            if (!array_key_exists($key, $array) || !is_array($array[$key])) {
158
                $array[$key] = [];
159
            }
160
            $array = &$array[$key];
161
        }
162
        $array[array_shift($keys)] = $value;
163
        return $array;
164
    }
165
    /**
166
     * @param array $yaml
167
     *
168
     * @return array
169
     */
170
    private function flattenYaml(array $yaml): array
171
    {
172
        /**
173
         * @var \RecursiveIteratorIterator|\Traversable $rItIt
174
         */
175
        $rItIt = new \RecursiveIteratorIterator(new \RecursiveArrayIterator($yaml));
176
        $settings = [];
177
        foreach ($rItIt as $leafValue) {
178
            $keys = [];
179
            foreach (range(0, $rItIt->getDepth()) as $depth) {
180
                $keys[] = $rItIt->getSubIterator($depth)
181
                    ->key();
182
            }
183
            $settings[implode('.', $keys)] = $leafValue;
184
        }
185
        return $settings;
186
    }
187
    /**
188
     * @param array $yaml
189
     *
190
     * @return array
191
     */
192
    private function unflattenYaml(array $yaml): array
193
    {
194
        $output = [];
195
        foreach ($yaml as $key => $value) {
196
            $this->arraySet($output, $key, $value);
197
            if (is_array($value) && false !== strpos($key, '.')) {
198
                $nested = $this->unflattenYaml($value);
199
                $output[$key] = $nested;
200
            }
201
        }
202
        return $output;
203
    }
204
    /**
205
     * @var string $pathFile
206
     */
207
    private $pathFile;
208
    /**
209
     * @var array $settings
210
     */
211
    private $settings;
212
}
213