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; |
|
|
|
|
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
|
|
|
|
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.
The function can be called with either null or an array for the parameter
$needle
but will only accept an array as$haystack
.