6 declare(strict_types
=1);
8 namespace PhpMyAdmin\Config
;
10 use function array_combine
;
11 use function array_shift
;
12 use function array_walk
;
15 use function is_array
;
18 use function is_string
;
20 use function mb_strpos
;
21 use function mb_strrpos
;
22 use function mb_substr
;
23 use function str_replace
;
24 use function trigger_error
;
26 use const E_USER_ERROR
;
29 * Base class for forms, loads default configuration options, checks allowed
40 * Form fields (paths), filled by {@link readFormPaths()}, indexed by field name
44 public array $fields = [];
47 * Stores default values for some fields (eg. pmadb tables)
51 public array $default = [];
54 * Caches field types, indexed by field names
58 private array $fieldsTypes = [];
61 * A counter for the number of groups
63 private static int $groupCounter = 0;
66 * Reads default config values
68 * @param string $formName Form name
69 * @param mixed[] $form Form data
70 * @param ConfigFile $configFile ConfigFile instance
71 * @param int|null $index Arbitrary index, doesn't affect class' behavior
73 public function __construct(
76 private ConfigFile
$configFile,
77 public int|
null $index = null,
79 $this->loadForm($formName, $form);
83 * Returns type of given option
85 * @param string $optionName path or field name
87 * @return string|null one of: boolean, integer, double, string, select, array
89 public function getOptionType(string $optionName): string|
null
94 (int) mb_strrpos($optionName, '/'),
99 return $this->fieldsTypes
[$key] ??
null;
103 * Returns allowed values for select fields
105 * @param string $optionPath Option path
109 public function getOptionValueList(string $optionPath): array
111 $value = $this->configFile
->getDbEntry($optionPath);
112 if ($value === null) {
113 trigger_error($optionPath . ' - select options not defined', E_USER_ERROR
);
118 if (! is_array($value)) {
119 trigger_error($optionPath . ' - not a static value list', E_USER_ERROR
);
124 // convert array('#', 'a', 'b') to array('a', 'b')
125 if (isset($value[0]) && $value[0] === '#') {
126 // remove first element ('#')
129 // $value has keys and value names, return it
133 // convert value list array('a', 'b') to array('a' => 'a', 'b' => 'b')
134 $hasStringKeys = false;
136 for ($i = 0, $nb = count($value); $i < $nb; $i++
) {
137 if (! isset($value[$i])) {
138 $hasStringKeys = true;
142 $keys[] = is_bool($value[$i]) ?
(int) $value[$i] : $value[$i];
145 if (! $hasStringKeys) {
146 /** @var array $value */
147 $value = array_combine($keys, $value);
150 // $value has keys and value names, return it
155 * array_walk callback function, reads path of form fields from
156 * array (see docs for \PhpMyAdmin\Config\Forms\BaseForm::getForms)
158 * @param mixed $value Value
159 * @param mixed $key Key
160 * @param mixed $prefix Prefix
162 private function readFormPathsCallback(mixed $value, mixed $key, mixed $prefix): void
164 if (is_array($value)) {
165 $prefix .= $key . '/';
168 function ($value, $key, $prefix): void
{
169 $this->readFormPathsCallback($value, $key, $prefix);
177 if (! is_int($key)) {
178 $this->default[$prefix . $key] = $value;
182 // add unique id to group ends
183 if ($value === ':group:end') {
184 $value .= ':' . self
::$groupCounter++
;
187 $this->fields
[] = $prefix . $value;
191 * Reset the group counter, function for testing purposes
193 public static function resetGroupCounter(): void
195 self
::$groupCounter = 0;
199 * Reads form paths to {@link $fields}
201 * @param mixed[] $form Form
203 protected function readFormPaths(array $form): void
205 // flatten form fields' paths and save them to $fields
209 function ($value, $key, $prefix): void
{
210 $this->readFormPathsCallback($value, $key, $prefix);
215 // $this->fields is an array of the form: [0..n] => 'field path'
216 // change numeric indexes to contain field names (last part of the path)
217 /** @var string[] $paths */
218 $paths = $this->fields
;
220 foreach ($paths as $path) {
222 mb_substr($path, (int) mb_strrpos($path, '/')),
225 $this->fields
[$key] = $path;
227 // now $this->fields is an array of the form: 'field name' => 'field path'
231 * Reads fields' types to $this->fieldsTypes
233 protected function readTypes(): void
235 foreach ($this->fields
as $name => $path) {
236 if (mb_strpos((string) $name, ':group:') === 0) {
237 $this->fieldsTypes
[$name] = 'group';
241 $v = $this->configFile
->getDbEntry($path);
243 $type = is_array($v) ?
'select' : $v;
245 $type = gettype($this->configFile
->getDefault($path));
248 $this->fieldsTypes
[$name] = (string) $type;
253 * Remove slashes from group names
257 * @param mixed[] $form The form data
261 protected function cleanGroupPaths(array $form): array
263 foreach ($form as &$name) {
264 if (! is_string($name)) {
268 if (mb_strpos($name, ':group:') !== 0) {
272 $name = str_replace('/', '-', $name);
279 * Reads form settings and prepares class to work with given subset of
282 * @param string $formName Form name
283 * @param mixed[] $form Form
285 public function loadForm(string $formName, array $form): void
287 $this->name
= $formName;
288 $form = $this->cleanGroupPaths($form);
289 $this->readFormPaths($form);