1: | <?php |
2: | |
3: | |
4: | |
5: | |
6: | |
7: | |
8: | namespace Aurora\System; |
9: | |
10: | |
11: | |
12: | |
13: | |
14: | |
15: | abstract class AbstractSettings |
16: | { |
17: | public const JSON_FILE_NAME = 'config.json'; |
18: | |
19: | |
20: | |
21: | |
22: | |
23: | protected $aContainer; |
24: | |
25: | |
26: | |
27: | |
28: | protected $sPath; |
29: | |
30: | |
31: | |
32: | |
33: | protected $bIsLoaded; |
34: | |
35: | |
36: | |
37: | |
38: | |
39: | |
40: | |
41: | public function __construct($sSettingsPath) |
42: | { |
43: | $this->aContainer = []; |
44: | $this->sPath = $sSettingsPath; |
45: | $this->bIsLoaded = false; |
46: | } |
47: | |
48: | |
49: | |
50: | |
51: | |
52: | public function __isset($sName) |
53: | { |
54: | if (!$this->bIsLoaded) { |
55: | $this->Load(); |
56: | } |
57: | |
58: | return isset($this->aContainer[$sName]); |
59: | } |
60: | |
61: | |
62: | |
63: | |
64: | |
65: | |
66: | public function __set($sName, $mValue) |
67: | { |
68: | $this->SetValue($sName, $mValue); |
69: | } |
70: | |
71: | |
72: | |
73: | |
74: | |
75: | public function __get($sName) |
76: | { |
77: | return $this->GetValue($sName); |
78: | } |
79: | |
80: | |
81: | |
82: | |
83: | public function GetValues() |
84: | { |
85: | return $this->aContainer; |
86: | } |
87: | |
88: | |
89: | |
90: | |
91: | |
92: | public function GetPath() |
93: | { |
94: | return $this->sPath; |
95: | } |
96: | |
97: | |
98: | |
99: | |
100: | public function SetValues($aValues) |
101: | { |
102: | $this->aContainer = $aValues; |
103: | } |
104: | |
105: | |
106: | |
107: | |
108: | |
109: | |
110: | public function GetValue($sKey, $mDefault = null) |
111: | { |
112: | if (!$this->bIsLoaded) { |
113: | $this->Load(); |
114: | } |
115: | |
116: | return (isset($this->aContainer[$sKey])) ? $this->aContainer[$sKey]->Value : $mDefault; |
117: | } |
118: | |
119: | |
120: | |
121: | |
122: | |
123: | |
124: | |
125: | |
126: | public function GetConf($sKey, $mDefault = null) |
127: | { |
128: | return $this->GetValue($sKey, $mDefault); |
129: | } |
130: | |
131: | |
132: | |
133: | |
134: | |
135: | |
136: | |
137: | public function SetValue($sKey, $mValue) |
138: | { |
139: | $bResult = false; |
140: | |
141: | $sType = (isset($this->aContainer[$sKey])) ? $this->aContainer[$sKey]->Type : \gettype($mValue); |
142: | if (!isset($this->aContainer[$sKey])) { |
143: | $this->aContainer[$sKey] = new SettingsProperty($sKey, $mValue, $sType); |
144: | } |
145: | |
146: | switch ($sType) { |
147: | case 'string': |
148: | $mValue = (string) $mValue; |
149: | break; |
150: | case 'int': |
151: | case 'integer': |
152: | $mValue = (int) $mValue; |
153: | break; |
154: | case 'bool': |
155: | case 'boolean': |
156: | $mValue = (bool) $mValue; |
157: | break; |
158: | case 'spec': |
159: | $mValue = $this->specValidate($mValue, $this->aContainer[$sKey]->SpecType); |
160: | break; |
161: | case 'array': |
162: | if (!Utils::IsAssocArray($mValue)) { |
163: | |
164: | $mValue = array_values($mValue); |
165: | } |
166: | break; |
167: | default: |
168: | $mValue = null; |
169: | break; |
170: | } |
171: | $this->aContainer[$sKey]->Value = $mValue; |
172: | $this->aContainer[$sKey]->Changed = true; |
173: | |
174: | return $bResult; |
175: | } |
176: | |
177: | |
178: | |
179: | |
180: | |
181: | |
182: | |
183: | |
184: | |
185: | public function SetConf($sKey, $mValue) |
186: | { |
187: | return $this->SetValue($sKey, $mValue); |
188: | } |
189: | |
190: | public function IsExists() |
191: | { |
192: | return \file_exists($this->sPath); |
193: | } |
194: | |
195: | public function BackupConfigFile() |
196: | { |
197: | $sJsonFile = $this->sPath; |
198: | if (\file_exists($sJsonFile)) { |
199: | \copy($sJsonFile, $sJsonFile.'.bak'); |
200: | } |
201: | } |
202: | |
203: | public function CheckConfigFile() |
204: | { |
205: | $bResult = true; |
206: | |
207: | |
208: | $sJsonFile = $this->sPath; |
209: | if (!\file_exists(\dirname($sJsonFile))) { |
210: | \set_error_handler(function () { |
211: | }); |
212: | \mkdir(\dirname($sJsonFile), 0777); |
213: | \restore_error_handler(); |
214: | $bResult = \file_exists(\dirname($sJsonFile)); |
215: | } |
216: | |
217: | return $bResult; |
218: | } |
219: | |
220: | public function SaveDataToConfigFile($aData) |
221: | { |
222: | $sJsonFile = $this->sPath; |
223: | return (bool) \file_put_contents( |
224: | $sJsonFile, |
225: | \json_encode( |
226: | $aData, |
227: | JSON_PRETTY_PRINT | JSON_OBJECT_AS_ARRAY |
228: | ) |
229: | ); |
230: | } |
231: | |
232: | public function ParseData($aData) |
233: | { |
234: | $aContainer = []; |
235: | |
236: | if (\is_array($aData)) { |
237: | foreach ($aData as $sKey => $mValue) { |
238: | $sSpecType = null; |
239: | if (\is_array($mValue)) { |
240: | $sType = isset($mValue[1]) ? $mValue[1] : (isset($mValue[0]) ? \gettype($mValue[0]) : "string"); |
241: | $sSpecType = isset($mValue[2]) ? $mValue[2] : null; |
242: | $mValue = isset($mValue[0]) ? $mValue[0] : ""; |
243: | } else { |
244: | $sType = \gettype($mValue); |
245: | } |
246: | |
247: | switch ($sType) { |
248: | case 'string': |
249: | $mValue =(string) $mValue; |
250: | break; |
251: | case 'int': |
252: | case 'integer': |
253: | $sType = 'int'; |
254: | $mValue = (int) $mValue; |
255: | break; |
256: | case 'bool': |
257: | case 'boolean': |
258: | $sType = 'bool'; |
259: | $mValue = (bool) $mValue; |
260: | break; |
261: | case 'spec': |
262: | $mValue = $this->specConver($mValue, $sSpecType); |
263: | break; |
264: | case 'array': |
265: | break; |
266: | default: |
267: | $mValue = null; |
268: | break; |
269: | } |
270: | if (null !== $mValue) { |
271: | $aContainer[$sKey] = new SettingsProperty($sKey, $mValue, $sType, $sSpecType); |
272: | } |
273: | } |
274: | } |
275: | |
276: | return $aContainer; |
277: | } |
278: | |
279: | |
280: | |
281: | |
282: | |
283: | |
284: | public function LoadDataFromFile($sJsonFile) |
285: | { |
286: | $mResult = false; |
287: | |
288: | if (\file_exists($sJsonFile)) { |
289: | $sJsonData = \file_get_contents($sJsonFile); |
290: | $mResult = \json_decode($sJsonData, true); |
291: | } |
292: | |
293: | return $mResult; |
294: | } |
295: | |
296: | |
297: | |
298: | |
299: | |
300: | |
301: | public function Load($bForceLoad = false) |
302: | { |
303: | $bResult = false; |
304: | if ($this->bIsLoaded && !$bForceLoad) { |
305: | $bResult = true; |
306: | } else { |
307: | $mData = $this->LoadDataFromFile($this->sPath); |
308: | |
309: | if (!$mData) { |
310: | $mData = $this->LoadDataFromFile($this->sPath.'.bak'); |
311: | if ($mData) { |
312: | \copy($this->sPath.'.bak', $this->sPath); |
313: | } |
314: | } |
315: | |
316: | if ($mData !== false) { |
317: | $this->aContainer = $this->ParseData($mData); |
318: | $this->bIsLoaded = true; |
319: | $bResult = true; |
320: | } |
321: | } |
322: | return $bResult; |
323: | } |
324: | |
325: | |
326: | |
327: | |
328: | public function GetData() |
329: | { |
330: | $aResult = []; |
331: | foreach ($this->aContainer as $sKey => $mValue) { |
332: | $aValue = []; |
333: | if ($mValue->Type === 'spec') { |
334: | $mValue->Value = $this->specBackConver($mValue->Value, $mValue->SpecType); |
335: | $aValue[] = $mValue->SpecType; |
336: | } |
337: | \array_unshift( |
338: | $aValue, |
339: | $mValue->Value, |
340: | $mValue->Type |
341: | ); |
342: | |
343: | $aResult[$sKey] = $aValue; |
344: | } |
345: | |
346: | return $aResult; |
347: | } |
348: | |
349: | |
350: | |
351: | |
352: | public function Save() |
353: | { |
354: | $bResult = false; |
355: | $aData = $this->GetData(); |
356: | if (count($aData) > 0) { |
357: | if ($this->CheckConfigFile()) { |
358: | $this->BackupConfigFile(); |
359: | if ($this->SaveDataToConfigFile($aData)) { |
360: | $bResult = true; |
361: | } else { |
362: | throw new \Aurora\System\Exceptions\SettingsException('Can\'t write settings to the configuration file'); |
363: | } |
364: | } |
365: | } |
366: | |
367: | return $bResult; |
368: | } |
369: | |
370: | |
371: | |
372: | |
373: | |
374: | |
375: | |
376: | protected function specBackConver($sValue, $sEnumName) |
377: | { |
378: | $mResult = $sValue; |
379: | if (null !== $sEnumName) { |
380: | $mResult = Enums\EnumConvert::ToXml($sValue, $sEnumName); |
381: | } |
382: | |
383: | return $mResult; |
384: | } |
385: | |
386: | |
387: | |
388: | |
389: | |
390: | |
391: | |
392: | protected function specValidate($sValue, $sEnumName) |
393: | { |
394: | $mResult = null; |
395: | if (null !== $sEnumName) { |
396: | $mResult = Enums\EnumConvert::validate($sValue, $sEnumName); |
397: | } |
398: | return $mResult; |
399: | } |
400: | |
401: | |
402: | |
403: | |
404: | |
405: | |
406: | |
407: | protected function specConver($sValue, $sEnumName) |
408: | { |
409: | if (null !== $sEnumName) { |
410: | $mResult = Enums\EnumConvert::FromXml($sValue, $sEnumName); |
411: | } |
412: | |
413: | return $this->specValidate($mResult, $sEnumName); |
414: | } |
415: | |
416: | |
417: | |
418: | |
419: | protected function init() |
420: | { |
421: | foreach ($this->aMap as $sKey => $aField) { |
422: | $this->aLowerMap[strtolower($sKey)] = $aField; |
423: | $this->SetValue($sKey, $aField[0]); |
424: | } |
425: | } |
426: | } |
427: | |