234 lines
6.2 KiB
PHP
234 lines
6.2 KiB
PHP
<?php
|
||
|
||
namespace ctiso;
|
||
use ctiso\File,
|
||
Exception;
|
||
|
||
/**
|
||
* Класс реестра
|
||
* Реестр организован как ассоциативный многомерный массив
|
||
* array( 'name1' => parameters1, 'name2' => parameters1, ... )
|
||
*
|
||
* name1, name2 ... - Имена модулей
|
||
* parameters1, parameters1 - Массивы с параметрами модуля
|
||
* Имя необходимо чтобы потом легко было удалить ненужные ветки дерева
|
||
*/
|
||
class Settings
|
||
{
|
||
/** @var array */
|
||
public $data = [];
|
||
/** @var string */
|
||
protected $file;
|
||
/** @var string */
|
||
protected $format = 'php';
|
||
/** @var bool */
|
||
protected $is_read = false;
|
||
|
||
/**
|
||
* Конструктор
|
||
* @param string $file Путь к файлу
|
||
* @param 'php'|'json'|false $format Формат файла
|
||
*/
|
||
public function __construct ($file = null, $format = false)
|
||
{
|
||
$fileFormat = ['theme' => 'json'];
|
||
$extname = pathinfo($file, PATHINFO_EXTENSION);
|
||
|
||
$this->format = $format ?: Arr::get($fileFormat, $extname, $extname);
|
||
$this->file = $file;
|
||
}
|
||
|
||
/**
|
||
* Чтение настроек из файла
|
||
* @return Boolean
|
||
*/
|
||
public function read(): bool
|
||
{
|
||
if (!file_exists ($this->file)) {
|
||
$this->is_read = true;
|
||
return false;
|
||
}
|
||
// Не include_once т.к читать настройки можно несколько раз
|
||
$settings = [];
|
||
if ($this->format == 'json') {
|
||
$settings = json_decode(File::getContents($this->file), true);
|
||
} else {
|
||
$settings = include ($this->file);
|
||
}
|
||
|
||
if (!is_array($settings)) {
|
||
throw new Exception('no data in ' . $this->file);
|
||
}
|
||
|
||
$this->is_read = true;
|
||
$this->data = $settings;
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* Запись ключа в реестр (Реестр это многомерный массив)
|
||
*/
|
||
public function writeKey(array $key, $value)
|
||
{
|
||
// assert(count($key) >= 1);
|
||
$data = &$this->data;
|
||
|
||
while (count($key) > 1) {
|
||
$name = array_shift($key);
|
||
$data = &$data[$name];
|
||
}
|
||
|
||
// assert(count($key) == 1);
|
||
$name = array_shift($key);
|
||
if (is_array($value)) {
|
||
if (!isset($data[$name])) {
|
||
$data[$name] = [];
|
||
}
|
||
$this->merge($data[$name], $value);
|
||
} else {
|
||
$data[$name] = $value;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Обновляет массив в соответствии со значением
|
||
*/
|
||
protected function merge(array &$data, $value)
|
||
{
|
||
foreach ($value as $key => $subvalue) {
|
||
if (is_array($subvalue)) {
|
||
if (! isset($data[$key])) $data[$key] = [];
|
||
$this->merge($data[$key], $subvalue);
|
||
} else {
|
||
$data[$key] = $subvalue;
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Чтение ключа из реестра
|
||
* @param array $key Путь к значению ключа
|
||
* @return mixed
|
||
*/
|
||
public function readKey(array $key)
|
||
{
|
||
return $this->readKeyData($key, $this->data);
|
||
}
|
||
|
||
/**
|
||
* Чтение ключа из реестра
|
||
* @param array $key Путь к значению ключа
|
||
* @return mixed
|
||
*/
|
||
protected function readKeyData(array $key, $data)
|
||
{
|
||
// assert(count($key) >= 1);
|
||
while (count($key) > 1) {
|
||
$name = array_shift($key);
|
||
if (isset($data[$name])) {
|
||
$data = $data[$name];
|
||
} else {
|
||
return null;
|
||
}
|
||
}
|
||
|
||
// assert(count($key) == 1);
|
||
$name = array_shift($key);
|
||
if (isset($data[$name])) {
|
||
return $data[$name];
|
||
} else {
|
||
return null;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Чтение ключа из реестра (Собирает все ключи с определенным значением во всех модулях)
|
||
* @param mixed $key Путь к значению ключа внутри модуля
|
||
*/
|
||
public function readKeyList(...$key)
|
||
{
|
||
$result = [];
|
||
foreach ($this->data as $name => $value) {
|
||
$output = $this->readKeyData($key, $value);
|
||
if ($output) {
|
||
$result[$name] = $output;
|
||
}
|
||
}
|
||
return $result;
|
||
}
|
||
|
||
/**
|
||
* Удаление ключа из реестра
|
||
* @param string $name Имя ключа
|
||
*/
|
||
public function removeKey($name): void
|
||
{
|
||
unset($this->data[$name]);
|
||
}
|
||
|
||
|
||
public function removeNode(array $key): void
|
||
{
|
||
$data = &$this->data;
|
||
while (count($key) > 1) {
|
||
$name = array_shift($key);
|
||
$data = &$data[$name];
|
||
}
|
||
$name = array_shift($key);
|
||
unset($data[$name]);
|
||
}
|
||
|
||
/**
|
||
* Запись настроек в файл (Может переименовать в store)
|
||
*
|
||
* @param File $file
|
||
* @return void
|
||
*/
|
||
public function write($file = null)
|
||
{
|
||
if (!$this->is_read) {
|
||
throw new Exception('read settings before write');
|
||
}
|
||
|
||
if ($this->format == 'json') {
|
||
$result = json_encode($this->data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
|
||
} else {
|
||
$result = var_export($this->data, true);
|
||
$result = "<?php\nreturn ".$result.";\n?>";
|
||
}
|
||
file_put_contents (($file) ? $file : $this->file, $result);
|
||
}
|
||
|
||
public function set($key, $value) {
|
||
$this->data[$key] = $value;
|
||
}
|
||
|
||
public function get($key, $default = null)
|
||
{
|
||
return isset($this->data[$key]) && $this->data[$key] != '' ? $this->data[$key] : $default;
|
||
}
|
||
|
||
function export() {
|
||
return $this->data;
|
||
}
|
||
|
||
function import($data) {
|
||
$this->data = $data;
|
||
}
|
||
|
||
/**
|
||
* Список модулей/ключей
|
||
*/
|
||
public function getKeys()
|
||
{
|
||
return array_keys($this->data);
|
||
}
|
||
|
||
/**
|
||
* Проверка наличия ключа
|
||
*/
|
||
public function hasKey($name)
|
||
{
|
||
return isset($this->data[$name]);
|
||
}
|
||
}
|