From f5420ce2c0c58fd6da079ecd353b014a031b1cc6 Mon Sep 17 00:00:00 2001 From: babaev-an Date: Sat, 28 Jun 2025 18:15:18 +0300 Subject: [PATCH] 20250628 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Бета 1.1 --- composer.lock | 86 ++++----- sources/classes/JsonReWriter.php | 163 ++++++++++++++++++ sources/exceptions/JsonException.php | 67 +++++++ .../JsonReWriter/JsonReWriterReadTrait.php | 119 +++++++++++++ tests/classes/JsonReWriterTest.php | 32 ++++ 5 files changed, 424 insertions(+), 43 deletions(-) create mode 100644 sources/classes/JsonReWriter.php create mode 100644 sources/exceptions/JsonException.php create mode 100644 sources/traits/JsonReWriter/JsonReWriterReadTrait.php create mode 100644 tests/classes/JsonReWriterTest.php diff --git a/composer.lock b/composer.lock index 394af4a..8ebe28c 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "f5bf0ec4042cb12fb3a702cad65f099d", + "content-hash": "f5bf0ec4042cb12fb3a702cad65f099d", "packages": [], "packages-dev": [ { @@ -69,16 +69,16 @@ }, { "name": "nikic/php-parser", - "version": "v5.5.0", + "version": "v5.5.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "ae59794362fe85e051a58ad36b289443f57be7a9" + "reference": "ae59794362fe85e051a58ad36b289443f57be7a9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/ae59794362fe85e051a58ad36b289443f57be7a9", - "reference": "ae59794362fe85e051a58ad36b289443f57be7a9", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/ae59794362fe85e051a58ad36b289443f57be7a9", + "reference": "ae59794362fe85e051a58ad36b289443f57be7a9", "shasum": "" }, "require": { @@ -121,9 +121,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.5.0" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.5.0" }, - "time": "2025-05-31T08:24:38+00:00" + "time": "2025-05-31T08:24:38+00:00" }, { "name": "phar-io/manifest", @@ -245,16 +245,16 @@ }, { "name": "phpunit/php-code-coverage", - "version": "12.3.1", + "version": "12.3.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "ddec29dfc128eba9c204389960f2063f3b7fa170" + "reference": "ddec29dfc128eba9c204389960f2063f3b7fa170" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ddec29dfc128eba9c204389960f2063f3b7fa170", - "reference": "ddec29dfc128eba9c204389960f2063f3b7fa170", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ddec29dfc128eba9c204389960f2063f3b7fa170", + "reference": "ddec29dfc128eba9c204389960f2063f3b7fa170", "shasum": "" }, "require": { @@ -310,7 +310,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/12.3.1" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/12.3.1" }, "funding": [ { @@ -330,7 +330,7 @@ "type": "tidelift" } ], - "time": "2025-06-18T08:58:13+00:00" + "time": "2025-06-18T08:58:13+00:00" }, { "name": "phpunit/php-file-iterator", @@ -579,16 +579,16 @@ }, { "name": "phpunit/phpunit", - "version": "12.2.3", + "version": "12.2.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "60a8ea2d8b2f070000051b56778009e11576e7d1" + "reference": "b71849b29f7a8d7574e4401873cb8b539896613f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/60a8ea2d8b2f070000051b56778009e11576e7d1", - "reference": "60a8ea2d8b2f070000051b56778009e11576e7d1", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/b71849b29f7a8d7574e4401873cb8b539896613f", + "reference": "b71849b29f7a8d7574e4401873cb8b539896613f", "shasum": "" }, "require": { @@ -602,15 +602,15 @@ "phar-io/manifest": "^2.0.4", "phar-io/version": "^3.2.1", "php": ">=8.3", - "phpunit/php-code-coverage": "^12.3.1", + "phpunit/php-code-coverage": "^12.3.1", "phpunit/php-file-iterator": "^6.0.0", "phpunit/php-invoker": "^6.0.0", "phpunit/php-text-template": "^5.0.0", "phpunit/php-timer": "^8.0.0", "sebastian/cli-parser": "^4.0.0", - "sebastian/comparator": "^7.1.0", + "sebastian/comparator": "^7.1.0", "sebastian/diff": "^7.0.0", - "sebastian/environment": "^8.0.2", + "sebastian/environment": "^8.0.2", "sebastian/exporter": "^7.0.0", "sebastian/global-state": "^8.0.0", "sebastian/object-enumerator": "^7.0.0", @@ -624,7 +624,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "12.2-dev" + "dev-main": "12.2-dev" } }, "autoload": { @@ -656,7 +656,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/12.2.3" + "source": "https://github.com/sebastianbergmann/phpunit/tree/12.2.5" }, "funding": [ { @@ -680,7 +680,7 @@ "type": "tidelift" } ], - "time": "2025-06-20T11:33:06+00:00" + "time": "2025-06-27T04:37:55+00:00" }, { "name": "sebastian/cli-parser", @@ -741,16 +741,16 @@ }, { "name": "sebastian/comparator", - "version": "7.1.0", + "version": "7.1.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "03d905327dccc0851c9a08d6a979dfc683826b6f" + "reference": "03d905327dccc0851c9a08d6a979dfc683826b6f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/03d905327dccc0851c9a08d6a979dfc683826b6f", - "reference": "03d905327dccc0851c9a08d6a979dfc683826b6f", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/03d905327dccc0851c9a08d6a979dfc683826b6f", + "reference": "03d905327dccc0851c9a08d6a979dfc683826b6f", "shasum": "" }, "require": { @@ -761,7 +761,7 @@ "sebastian/exporter": "^7.0" }, "require-dev": { - "phpunit/phpunit": "^12.2" + "phpunit/phpunit": "^12.2" }, "suggest": { "ext-bcmath": "For comparing BcMath\\Number objects" @@ -769,7 +769,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "7.1-dev" + "dev-main": "7.1-dev" } }, "autoload": { @@ -809,27 +809,27 @@ "support": { "issues": "https://github.com/sebastianbergmann/comparator/issues", "security": "https://github.com/sebastianbergmann/comparator/security/policy", - "source": "https://github.com/sebastianbergmann/comparator/tree/7.1.0" + "source": "https://github.com/sebastianbergmann/comparator/tree/7.1.0" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" }, - { - "url": "https://liberapay.com/sebastianbergmann", - "type": "liberapay" - }, - { - "url": "https://thanks.dev/u/gh/sebastianbergmann", - "type": "thanks_dev" - }, - { - "url": "https://tidelift.com/funding/github/packagist/sebastian/comparator", - "type": "tidelift" + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/comparator", + "type": "tidelift" } ], - "time": "2025-06-17T07:41:58+00:00" + "time": "2025-06-17T07:41:58+00:00" }, { "name": "sebastian/complexity", @@ -1633,4 +1633,4 @@ }, "platform-dev": {}, "plugin-api-version": "2.6.0" -} \ No newline at end of file +} diff --git a/sources/classes/JsonReWriter.php b/sources/classes/JsonReWriter.php new file mode 100644 index 0000000..bf406a9 --- /dev/null +++ b/sources/classes/JsonReWriter.php @@ -0,0 +1,163 @@ +JsonData = []; + } + + /** + * Деструктор класса. + */ + public function __destruct () + { + unset($this->JsonData); + } + + /** + * Сохраняем JSON в файл. + * + * @param string $fileName Имя файла. + * + * @return void + * @throws JsonException Если файл не может быть сохранен. + */ + public function SaveToFile (string $fileName): void + { + // Запись данных в файл + file_put_contents($fileName, json_encode($this->JsonData, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)); + + // Проверка на ошибки + if (json_last_error() !== JSON_ERROR_NONE) + // - если есть ошибки, выбрасываем исключение + throw new JsonException($fileName, json_last_error(), json_last_error_msg()); + } + + /** + * Загрузка данных из JSON-файла. + * + * @param string $fileName Имя файла. + * + * @return void + * @throws JsonException Если файл не существует или содержит ошибки. + */ + public function LoadFromFile (string $fileName): void + { + // Проверка существования файла + if (!is_file($fileName)) + // - нет? Выбрасываем исключение + throw new JsonException($fileName, -1, "File does not exist / Файл не существует"); + + // Чтение содержимого файла и преобразование JSON в объект + $this->JsonData = json_decode(file_get_contents($fileName), true); + + // Проверка на ошибки + if ($this->JsonData === null && json_last_error() !== JSON_ERROR_NONE) + // - если есть ошибки, выбрасываем исключение + throw new JsonException($fileName, json_last_error(), json_last_error_msg()); + } + + /** + * Проверяем наличие ключа в JSON. + * + * @param string $key Ключ. + * + * @return bool true если ключ найден, false если нет. + */ + public function IsKeyExists (string $key): bool + { + // Получаем массив ключей по вложенности + $keys = $this->ParseKey($key); + + // Получаем текущий массив данных + $current = $this->JsonData; + + // Для каждого ключа + foreach ($keys as $key) { + // - проверяем наличие ключа в текущем массиве + if (!array_key_exists($key, $current)) + // - нет? Возвращаем false + return false; + + // Переходим ко вложенному массиву + $current = $current[$key]; + } + + // Возвращаем true, если все ключи найдены + return true; + } + + /** + * Получение ключей по вложенности. Т.е., ключи вида "key1/key2/key3" => ["key1", "key2", "key3"]. + * + * @param string $key Ключ. + * + * @return array Ключи по вложенности. + */ + private function ParseKey (string $key): array + { + return explode('/', $key); + } + + /** + * Создание ключа в JSON. + * + * @param string $key Ключ. + * @param mixed $value Значение. + * + * @return void + * @throws JsonException Если ключ не является массивом. + */ + private function CreateKey (string $key, mixed $value): void + { + // Получаем массив ключей по вложенности + $keys = $this->ParseKey($key); + + // Получаем текущий массив данных + $current = &$this->JsonData; + + // Для каждого ключа до предпоследнего + for ($i = 0; $i < count($keys) - 1; $i++) { + // - проверяем наличие ключа в текущем массиве + if (!isset($current[$keys[$i]])) + // - нет? Создаем ключ (массив) + $current[$keys[$i]] = []; + + // - проверяем, что ключ является массивом + if (!is_array($current[$keys[$i]])) + // - нет? Выбрасываем исключение + throw new JsonException(null, -1, "Key is not an array / Ключ не является массивом!"); + + // - переходим ко вложенному массиву + $current = &$current[$keys[$i]]; + } + + // Создаем ключ (значение) + $current[$keys[count($keys) - 1]] = $value; + } + + // Подключаем методы чтения JSON + use JsonReWriterReadTrait; +} \ No newline at end of file diff --git a/sources/exceptions/JsonException.php b/sources/exceptions/JsonException.php new file mode 100644 index 0000000..b3b3109 --- /dev/null +++ b/sources/exceptions/JsonException.php @@ -0,0 +1,67 @@ +JsonErrorMessage = $errorMessage; + + // Если сообщение пусто, то присваиваем ему "" для совместимости + $errorMessage = $errorMessage ?? ""; + + // Запускаем базовый конструктор + parent::__construct($errorMessage); + + // Присваиваем имя файла + $this->JsonFileName = $fileName; + + // Присваиваем код ошибки + $this->JsonErrorCode = $errorCode; + } +} \ No newline at end of file diff --git a/sources/traits/JsonReWriter/JsonReWriterReadTrait.php b/sources/traits/JsonReWriter/JsonReWriterReadTrait.php new file mode 100644 index 0000000..20a5b5d --- /dev/null +++ b/sources/traits/JsonReWriter/JsonReWriterReadTrait.php @@ -0,0 +1,119 @@ +Read($key, $default); + } + + /** + * Читает значение ключа JSON. + * + * @param string $key Ключ JSON. + * @param mixed $default Значение по умолчанию. + * + * @return mixed Значение ключа JSON или значение по умолчанию. + */ + public function Read (string $key, mixed $default = null): mixed + { + if (!$this->IsKeyExists($key)) + return $default; + + $keys = $this->ParseKey($key); + + // Получаем текущий массив данных + $current = $this->JsonData; + + // Для каждого ключа до предпоследнего + for ($i = 0; $i < count($keys) - 1; $i++) + // - переходим ко вложенному массиву + $current = &$current[$keys[$i]]; + + // Возвращаем значение последнего ключа и если его нет, то возвращаем значение по умолчанию + return $current[$keys[count($keys) - 1]] ?? $default; + } + + /** + * Читает значение ключа JSON как вещественное число. + * + * @param string $key Ключ JSON. + * @param float $default Значение по умолчанию. + * + * @return float Значение ключа JSON или значение по умолчанию. + */ + public function ReadFloat (string $key, float $default = 0.0): float + { + return (float)$this->Read($key, $default); + } + + /** + * Читает значение ключа JSON как логическое значение. + * + * @param string $key Ключ JSON. + * @param bool $default Значение по умолчанию. + * + * @return bool Значение ключа JSON или значение по умолчанию. + */ + public function ReadBool (string $key, bool $default = false): bool + { + return (bool)$this->Read($key, $default); + } + + /** + * Читает значение ключа JSON как массив. + * + * @param string $key Ключ JSON. + * @param array $default Значение по умолчанию. + * + * @return array Значение ключа JSON или значение по умолчанию. + */ + public function ReadArray (string $key, array $default = []): array + { + return (array)$this->Read($key, $default); + } + + /** + * Читает значение ключа JSON как объект. + * + * @param string $key Ключ JSON. + * @param object $default Значение по умолчанию. + * + * @return object Значение ключа JSON или значение по умолчанию. + */ + public function ReadObject (string $key, object $default): object + { + return (object)$this->Read($key, $default); + } + + /** + * Читает значение ключа JSON как строку. + * + * @param string $key Ключ JSON. + * @param string $default Значение по умолчанию. + * + * @return string Значение ключа JSON или значение по умолчанию. + */ + public function ReadString (string $key, string $default = ""): string + { + return (string)$this->Read($key, $default); + } +} \ No newline at end of file diff --git a/tests/classes/JsonReWriterTest.php b/tests/classes/JsonReWriterTest.php new file mode 100644 index 0000000..7cd5591 --- /dev/null +++ b/tests/classes/JsonReWriterTest.php @@ -0,0 +1,32 @@ +PrepareForTest(); + + $json = new JsonReWriter(); + $json->CreateKey("test/subtest/AAA", "123"); + + var_dump($json->JsonData); + + //$json->SaveToFile(__DIR__ . '/test.json'); + } + + private function PrepareForTest (): void + { + require_once __DIR__ . '/../../sources/exceptions/JsonException.php'; + require_once __DIR__ . '/../../sources/classes/JsonReWriter.php'; + } + + public function testLoadFromFile () + { + + } +}