1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* BEdita, API-first content management framework |
4
|
|
|
* Copyright 2016 ChannelWeb Srl, Chialab Srl |
5
|
|
|
* |
6
|
|
|
* This file is part of BEdita: you can redistribute it and/or modify |
7
|
|
|
* it under the terms of the GNU Lesser General Public License as published |
8
|
|
|
* by the Free Software Foundation, either version 3 of the License, or |
9
|
|
|
* (at your option) any later version. |
10
|
|
|
* |
11
|
|
|
* See LICENSE.LGPL or <http://gnu.org/licenses/lgpl-3.0.html> for more details. |
12
|
|
|
*/ |
13
|
|
|
namespace BEdita\Core\Configure\Engine; |
14
|
|
|
|
15
|
|
|
use Cake\Core\Configure\ConfigEngineInterface; |
16
|
|
|
use Cake\Database\Exception; |
17
|
|
|
use Cake\Datasource\ModelAwareTrait; |
18
|
|
|
|
19
|
|
|
/** |
20
|
|
|
* BEdita database configuration engine. |
21
|
|
|
* |
22
|
|
|
* Configuration parameters are stored in `config` table |
23
|
|
|
* |
24
|
|
|
* Each `config.name` in database should be a first level key in Configure (without dots) |
25
|
|
|
* Some keys like 'Datasources', 'Cache' and 'EmailTransport' are reserved and may not be stored in database |
26
|
|
|
* Instead each corresponding `config.content` field should be either a string or JSON |
27
|
|
|
* `config.context` represents a group of parameters loaded via Configure::load($key, 'database') |
28
|
|
|
* |
29
|
|
|
* DatabaseConfig also manipulates how 'null', 'true', 'false' are handled. |
30
|
|
|
* These values will be converted to their boolean equivalents or to null. |
31
|
|
|
* |
32
|
|
|
* @since 4.0.0 |
33
|
|
|
* @property \BEdita\Core\Model\Table\ConfigTable $Config |
34
|
|
|
*/ |
35
|
|
|
class DatabaseConfig implements ConfigEngineInterface |
36
|
|
|
{ |
37
|
|
|
use ModelAwareTrait; |
38
|
|
|
|
39
|
|
|
/** |
40
|
|
|
* Application id |
41
|
|
|
* |
42
|
|
|
* @var int |
43
|
|
|
*/ |
44
|
|
|
protected $applicationId = null; |
45
|
|
|
|
46
|
|
|
/** |
47
|
|
|
* Reserved keys not storable in database |
48
|
|
|
* |
49
|
|
|
* @var array |
50
|
|
|
*/ |
51
|
|
|
public const RESERVED_KEYS = ['Datasources', 'Cache', 'EmailTransport', 'Session', 'Error', 'App']; |
52
|
|
|
|
53
|
|
|
/** |
54
|
|
|
* Setup application `id` if provided. |
55
|
|
|
* |
56
|
|
|
* @param int $applicationId Application id |
57
|
|
|
*/ |
58
|
|
|
public function __construct($applicationId = null) |
59
|
|
|
{ |
60
|
|
|
$this->applicationId = $applicationId; |
61
|
|
|
$this->loadModel('Config'); |
62
|
|
|
} |
63
|
|
|
|
64
|
|
|
/** |
65
|
|
|
* Read configuration from database of `$key` parameters group |
66
|
|
|
* and return the results as an array. |
67
|
|
|
* Parameter group is mapped to database column `config.context`. |
68
|
|
|
* |
69
|
|
|
* @param string|null $key The group of parameters to read from database (see `config.context`). |
70
|
|
|
* @return array Parsed configuration values. |
71
|
|
|
*/ |
72
|
|
|
public function read($key): array |
73
|
|
|
{ |
74
|
|
|
return $this->Config->fetchConfig($this->applicationId, $key) |
75
|
|
|
->all() |
76
|
|
|
->filter(function (array $item): bool { |
77
|
|
|
return !in_array($item['name'], self::RESERVED_KEYS); |
78
|
|
|
}) |
79
|
|
|
->map(function (array $item): array { |
80
|
|
|
$content = json_decode($item['content'], true); |
81
|
|
|
if ($content === null && json_last_error() !== JSON_ERROR_NONE) { |
82
|
|
|
$content = static::valueFromString($item['content']); |
83
|
|
|
} |
84
|
|
|
$item['content'] = $content; |
85
|
|
|
|
86
|
|
|
return $item; |
87
|
|
|
}) |
88
|
|
|
->combine('name', 'content') |
89
|
|
|
->toArray(); |
90
|
|
|
} |
91
|
|
|
|
92
|
|
|
/** |
93
|
|
|
* Dumps Configure data array to Database. |
94
|
|
|
* |
95
|
|
|
* @param string $key The group parameter to write to. |
96
|
|
|
* @param array $data The data to write. |
97
|
|
|
* @return bool Success. |
98
|
|
|
*/ |
99
|
|
|
public function dump($key, array $data): bool |
100
|
|
|
{ |
101
|
|
|
$context = $key; |
102
|
|
|
$entities = []; |
103
|
|
|
foreach ($data as $name => $content) { |
104
|
|
|
if (in_array($name, self::RESERVED_KEYS)) { |
105
|
|
|
continue; |
106
|
|
|
} |
107
|
|
|
$content = is_array($content) ? json_encode($content) : static::valueToString($content); |
108
|
|
|
$entities[] = $this->Config->newEntity(compact('name', 'context', 'content')); |
109
|
|
|
} |
110
|
|
|
$this->Config->getConnection()->transactional(function () use ($entities) { |
111
|
|
|
foreach ($entities as $entity) { |
112
|
|
|
if (!$this->Config->save($entity, ['atomic' => false])) { |
113
|
|
|
throw new Exception(sprintf('Config save failed: %s', print_r($entity->getErrors(), true))); |
|
|
|
|
114
|
|
|
} |
115
|
|
|
} |
116
|
|
|
}); |
117
|
|
|
|
118
|
|
|
return true; |
119
|
|
|
} |
120
|
|
|
|
121
|
|
|
/** |
122
|
|
|
* Converts a value into its string equivalent |
123
|
|
|
* |
124
|
|
|
* @param mixed $value Value to export. |
125
|
|
|
* @return string String value for database. |
126
|
|
|
*/ |
127
|
|
|
protected static function valueToString($value): string |
128
|
|
|
{ |
129
|
|
|
if ($value === null) { |
130
|
|
|
return 'null'; |
131
|
|
|
} |
132
|
|
|
if ($value === true) { |
133
|
|
|
return 'true'; |
134
|
|
|
} |
135
|
|
|
if ($value === false) { |
136
|
|
|
return 'false'; |
137
|
|
|
} |
138
|
|
|
|
139
|
|
|
return (string)$value; |
140
|
|
|
} |
141
|
|
|
|
142
|
|
|
/** |
143
|
|
|
* Converts a value from its string value to its 'natural' form. |
144
|
|
|
* |
145
|
|
|
* Note that for lowercased variant of 'true', 'false' and 'null' |
146
|
|
|
* are converted without errors from `json_decode()`. |
147
|
|
|
* |
148
|
|
|
* @param string $value Value to convert, if necessary. |
149
|
|
|
* @return mixed String Natural form value. |
150
|
|
|
*/ |
151
|
|
|
protected static function valueFromString($value) |
152
|
|
|
{ |
153
|
|
|
if ($value === 'NULL') { |
154
|
|
|
return null; |
155
|
|
|
} |
156
|
|
|
if ($value === 'TRUE') { |
157
|
|
|
return true; |
158
|
|
|
} |
159
|
|
|
if ($value === 'FALSE') { |
160
|
|
|
return false; |
161
|
|
|
} |
162
|
|
|
|
163
|
|
|
return $value; |
164
|
|
|
} |
165
|
|
|
} |
166
|
|
|
|