diff --git a/composer.json b/composer.json index 9e375ef..44c5e50 100644 --- a/composer.json +++ b/composer.json @@ -26,7 +26,7 @@ "ext-mbstring": "*" }, "require-dev": { - "phpunit/phpunit": "^12.0.4" + "phpunit/phpunit": "^12.1.4" }, "autoload": { "psr-4": { diff --git a/composer.lock b/composer.lock index 7adf2f6..cd9280b 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": "157bb444d3a207c9efb13c1562ce2a0a", + "content-hash": "8024da85d3650f107ba3254f5dfc3b79", "packages": [], "packages-dev": [ { @@ -245,16 +245,16 @@ }, { "name": "phpunit/php-code-coverage", - "version": "12.1.2", + "version": "12.2.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "05c33d01a856f9f62488d144bafddc3d7b7a4ebb" + "reference": "448f2c504d86dbff3949dcd02c95aa85db2c7617" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/05c33d01a856f9f62488d144bafddc3d7b7a4ebb", - "reference": "05c33d01a856f9f62488d144bafddc3d7b7a4ebb", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/448f2c504d86dbff3949dcd02c95aa85db2c7617", + "reference": "448f2c504d86dbff3949dcd02c95aa85db2c7617", "shasum": "" }, "require": { @@ -272,7 +272,7 @@ "theseer/tokenizer": "^1.2.3" }, "require-dev": { - "phpunit/phpunit": "^12.0" + "phpunit/phpunit": "^12.1" }, "suggest": { "ext-pcov": "PHP extension that provides line coverage", @@ -281,7 +281,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "12.1.x-dev" + "dev-main": "12.2.x-dev" } }, "autoload": { @@ -310,15 +310,27 @@ "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.1.2" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/12.2.1" }, "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/phpunit/php-code-coverage", + "type": "tidelift" } ], - "time": "2025-04-03T14:34:39+00:00" + "time": "2025-05-04T05:25:05+00:00" }, { "name": "phpunit/php-file-iterator", @@ -567,16 +579,16 @@ }, { "name": "phpunit/phpunit", - "version": "12.1.3", + "version": "12.1.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "72ca50e817dd7d65356c16772c30f06c01a6fae2" + "reference": "5ee57ad690bda2c487594577600931a99053436c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/72ca50e817dd7d65356c16772c30f06c01a6fae2", - "reference": "72ca50e817dd7d65356c16772c30f06c01a6fae2", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/5ee57ad690bda2c487594577600931a99053436c", + "reference": "5ee57ad690bda2c487594577600931a99053436c", "shasum": "" }, "require": { @@ -586,7 +598,7 @@ "ext-mbstring": "*", "ext-xml": "*", "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.13.0", + "myclabs/deep-copy": "^1.13.1", "phar-io/manifest": "^2.0.4", "phar-io/version": "^3.2.1", "php": ">=8.3", @@ -644,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.1.3" + "source": "https://github.com/sebastianbergmann/phpunit/tree/12.1.4" }, "funding": [ { @@ -668,7 +680,7 @@ "type": "tidelift" } ], - "time": "2025-04-22T06:11:09+00:00" + "time": "2025-05-02T07:01:56+00:00" }, { "name": "sebastian/cli-parser", diff --git a/sources/classes/ActionState.php b/sources/classes/ActionState.php index 62dc3d0..c907ad3 100644 --- a/sources/classes/ActionState.php +++ b/sources/classes/ActionState.php @@ -7,10 +7,12 @@ namespace goodboyalex\php_components_pack\classes; -use Closure; -use goodboyalex\php_components_pack\enums\MessageType; use goodboyalex\php_components_pack\interfaces\ISerializable; use goodboyalex\php_components_pack\models\ActionStateMessageModel; +use goodboyalex\php_components_pack\traits\ActionState\ActionStateAddTrait; +use goodboyalex\php_components_pack\traits\ActionState\ActionStateGetTrait; +use goodboyalex\php_components_pack\traits\ActionState\ActionStateHasTrait; +use goodboyalex\php_components_pack\traits\ActionState\ActionStateStaticTrait; /** * Состояние действия. @@ -28,9 +30,9 @@ final class ActionState implements ISerializable public mixed $Value; /** - * @var array $Messages Список информации + * @var ObjectArray $Messages Список информации */ - private array $Messages = []; + private ObjectArray $Messages; /** * Конструктор @@ -39,218 +41,24 @@ final class ActionState implements ISerializable */ public function __construct (mixed $defValue = null) { + // Присваиваю значение по умолчанию $this->Value = $defValue; + + // Создаю список сообщений + $this->Messages = new ObjectArray([]); } - /** - * При выводе GetStringMessages выводит только ошибки. - * - * @return Closure Возвращает функцию, проверяющую сообщение на соответствие типу. - */ - public static function GET_STRING_ERROR_ONLY (): Closure - { - return fn (ActionStateMessageModel $message) - => $message->MessageType === MessageType::Error; - } + // Статичные методы и константы + use ActionStateStaticTrait; - /** - * При выводе GetStringMessages выводит ошибки и предупреждения. - * - * @return Closure Возвращает функцию, проверяющую сообщение на соответствие типу. - */ - public static function GET_STRING_ERROR_AND_WARNING (): Closure - { - return fn (ActionStateMessageModel $message) - => $message->MessageType === MessageType::Error - || $message->MessageType === MessageType::Warning; - } + // Методы добавления сообщений + use ActionStateAddTrait; - /** - * При выводе GetStringMessages выводит все сообщения. - * - * @return Closure Возвращает функцию, проверяющую сообщение на соответствие типу. - */ - public static function GET_STRING_ALL (): Closure - { - return fn (ActionStateMessageModel $message) => true; - } + // Методы проверки на наличие сообщений + use ActionStateHasTrait; - /** - * Добавляет данные из другого состояния. - * - * @param ActionState $state Другое состояние - * @param bool $clearAllBefore Очищать сообщения перед добавлением (true) или просто добавить к текущим (false) - * - * @return void - */ - public function AddState (ActionState $state, bool $clearAllBefore = false): void - { - // Если нужно очистить список сообщений - if ($clearAllBefore) - // - то очищаю список сообщений - $this->Clear(fn (ActionStateMessageModel $message) => true); - - // Добавляю сообщения из другого состояния - $this->AddRange($state->GetMessages(function (ActionStateMessageModel $message) - { - return true; - })); - - // Добавляю значение - $this->Value = $state->Value; - } - - /** - * Очищает список сообщений, согласно условию. - * - * @param callable $predicate Условие выборки - * - * @return void - */ - public function Clear (callable $predicate): void - { - // Выбираю все сообщения, удовлетворяющие условию - $list = $this->GetMessages($predicate); - - // Удаляю их из списка - $this->Messages = array_diff($this->Messages, $list); - } - - /** - * Выбирает сообщения по условию predicate. - * - * @param callable $predicate Условие выборки - * - * @return array Список отобранных сообщений - */ - public function GetMessages (callable $predicate): array - { - // Получаю список элементов - $list = []; - - // Для каждого элемента - foreach ($this->Messages as $actionStateMessage) - // - если он подходит под условие - if ($predicate($actionStateMessage)) - // - добавляю его в список - $list[] = $actionStateMessage; - - // Возвращаю список - return $list; - } - - /** - * Добавляет список - * - * @param array $messages Список сообщений - * - * @return void - */ - public function AddRange (array $messages): void - { - $this->Messages = array_merge($this->Messages, $messages); - } - - /** - * Возвращает список сообщений (параметр Message у каждого сообщения). - * - * @param callable $predicate Условие выборки - * @param string $separator Разделитель - * - * @return string Список сообщений - */ - public function GetStringMessages (callable $predicate, string $separator = '\n'): string - { - // Делаю выборку - $list = $this->GetMessages($predicate); - - // Формирую список сообщений - $result = []; - - // Для каждого сообщения из выборки - foreach ($list as $message) { - // - если оно не нужного нам класса - if (!$message instanceof ActionStateMessageModel) - // -- то пропускаю - continue; - - // - добавляю сообщение - $result[] = $message->Message; - } - - // Возвращаю список - return implode($separator, $result); - } - - /** - * Добавляет сообщение о критической ошибке. - * - * @param string $message Сообщение - * - * @return void - */ - public function AddCritical (string $message): void - { - $this->Add(new ActionStateMessageModel(MessageType::Error, true, $message)); - } - - /** - * Добавление сообщения. - * - * @param ActionStateMessageModel $message Сообщение - * - * @return void - */ - public function Add (ActionStateMessageModel $message): void - { - $this->Messages[] = $message; - } - - /** - * Добавляет сообщение об ошибке. - * - * @param string $message Сообщение - * - * @return void - */ - public function AddError (string $message): void - { - $this->Add(new ActionStateMessageModel(MessageType::Error, false, $message)); - } - - /** - * Добавляет предупреждение. - * - * @param string $message Сообщение. - * - * @return void - */ - public function AddWarning (string $message): void - { - $this->Add(new ActionStateMessageModel(MessageType::Warning, false, $message)); - } - - /** - * Добавляет информационное сообщение. - * - * @param string $message Сообщение. - * - * @return void - */ - public function AddInfo (string $message): void - { - $this->Add(new ActionStateMessageModel(MessageType::Info, false, $message)); - } - - /** - * Проверяет, есть ли информационные сообщения. - * - * @return bool Наличие сообщений - */ - public function HasInfos (): bool - { - return $this->Count(fn (ActionStateMessageModel $message) => $message->MessageType == MessageType::Info) > 0; - } + // Методы получения сообщений + use ActionStateGetTrait; /** * Количество сообщений, удовлетворяющих условию. @@ -261,65 +69,7 @@ final class ActionState implements ISerializable */ public function Count (callable $predicate): int { - // Получаю список сообщений - $list = $this->GetMessages($predicate); - - // Возвращаю результат - return count($list); - } - - /** - * Проверяет, успешно ли завершилась операция. - * - * @param bool $onlyCritical Игнорировать все некритические ошибки и предупреждения (не рекомендуется!) - * - * @return bool Успешно ли завершилась операция. - */ - public function IsSuccess (bool $onlyCritical = false): bool - { - // Если нужно учитывать только критические ошибки - if ($onlyCritical) - // - то проверяю наличие критических ошибок - return !$this->HasErrors($onlyCritical); - - // Возвращаю результат - return !$this->HasErrors() && !$this->HasWarnings(); - } - - /** - * Проверяет, есть ли ошибки. - * - * @param bool $onlyCritical Учитывать только критические ошибки. - * - * @return bool Наличие ошибок. - */ - public function HasErrors (bool $onlyCritical = false): bool - { - return $this->Count(function (ActionStateMessageModel $message) use ($onlyCritical): bool - { - // - сравниваю тип сообщения - if ($message->MessageType != MessageType::Error) - // -- если не совпадает, то возвращаю false - return false; - - // - если нужно выводить только критические ошибки, а сообщение не критическое - if ($onlyCritical && !$message->IsCritical) - // -- то возвращаю false - return false; - - // Возвращаю true - return true; - }); - } - - /** - * Проверяет, есть ли предупреждения. - * - * @return bool Наличие предупреждений - */ - public function HasWarnings (): bool - { - return $this->Count(fn (ActionStateMessageModel $message) => $message->MessageType == MessageType::Warning) > 0; + return $this->Messages->Count($predicate); } /** @@ -336,7 +86,7 @@ final class ActionState implements ISerializable $list[] = $message->Serialize(); // Возвращаю результат - return serialize($list); + return json_encode($list); } /** @@ -345,10 +95,10 @@ final class ActionState implements ISerializable public function UnSerialize (string $serialized): void { // Очищаю список сообщений - $this->Clear(fn (ActionStateMessageModel $message) => true); + $this->Clear(self::GET_STRING_ALL()); // Десериализую список сообщений - $list = unserialize($serialized); + $list = json_decode($serialized, true); // Для каждого сообщения foreach ($list as $messageSerialized) { @@ -360,4 +110,16 @@ final class ActionState implements ISerializable $this->Add($message); } } + + /** + * Очищает список сообщений, согласно условию. + * + * @param callable $predicate Условие выборки + * + * @return void + */ + public function Clear (callable $predicate): void + { + $this->Messages->Delete($predicate); + } } \ No newline at end of file diff --git a/sources/models/ActionStateMessageModel.php b/sources/models/ActionStateMessageModel.php index a690eaa..8cdc421 100644 --- a/sources/models/ActionStateMessageModel.php +++ b/sources/models/ActionStateMessageModel.php @@ -2,11 +2,8 @@ namespace goodboyalex\php_components_pack\models; -use Exception; -use goodboyalex\php_components_pack\classes\ClassMapper; use goodboyalex\php_components_pack\enums\MessageType; use goodboyalex\php_components_pack\interfaces\ISerializable; -use UnitEnum; /** * Класс сообщения состояния. @@ -53,18 +50,13 @@ final class ActionStateMessageModel implements ISerializable public function UnSerialize (string $serialized): void { // Десериализую массив - $thisNew = unserialize($serialized); + $array = json_decode($serialized, true); - try { - // Получаю класс - $class = ClassMapper::MapToClassProperty(get_class($this), $thisNew); - } - catch (Exception) { - $class = new ActionStateMessageModel(); - } - - // Заполняю текущий класс - ClassMapper::MapClass($class, $this); + // Заполняю поля + $this->MessageType = + isset($array["MessageType"]) ? MessageType::FromName($array["MessageType"]) : MessageType::Info; + $this->IsCritical = isset($array["IsCritical"]) && $array["IsCritical"] == 1; + $this->Message = $array["Message"] ?? ""; } /** @@ -75,34 +67,12 @@ final class ActionStateMessageModel implements ISerializable // Создаю массив результата $result = []; - // Получаю свойства класса - $properties = get_object_vars($this); + // Заполняю массив + $result["MessageType"] = $this->MessageType->GetValue(); + $result["IsCritical"] = $this->IsCritical ? 1 : 0; + $result["Message"] = $this->Message; - // Для каждого свойства класса - foreach ($properties as $key => $value) { - - // - если значение является перечислением - if ($value instanceof UnitEnum) { - // -- получаю перечисление - $result[$key] = $value->name; - - // -- следующий элемент - continue; - } - - // - если значение является NULL - if ($value == null) { - // -- присваиваю NULL - $result[$key] = "null"; - // -- следующий элемент - continue; - } - - // - присваиваю значение - $result[$key] = $value; - } - - // Сериализую массив и вывожу его - return serialize($result); + // Сериализую + return json_encode($result); } } \ No newline at end of file diff --git a/sources/traits/ActionState/ActionStateAddTrait.php b/sources/traits/ActionState/ActionStateAddTrait.php new file mode 100644 index 0000000..ffe4b65 --- /dev/null +++ b/sources/traits/ActionState/ActionStateAddTrait.php @@ -0,0 +1,114 @@ +Clear(fn (ActionStateMessageModel $message) => true); + + // Добавляю сообщения из другого состояния + $this->AddRange($state->GetMessages(ActionState::GET_STRING_ALL())); + + // Добавляю значение + $this->Value = $state->Value; + } + + /** + * Добавляет список + * + * @param ObjectArray|array $messages Список сообщений + * + * @return void + */ + public function AddRange (ObjectArray|array $messages): void + { + // Добавляю сообщения + $this->Messages->AddRange($messages); + } + + /** + * Добавляет сообщение о критической ошибке. + * + * @param string $message Сообщение + * + * @return void + */ + public function AddCritical (string $message): void + { + $this->Add(new ActionStateMessageModel(MessageType::Error, true, $message)); + } + + /** + * Добавление сообщения. + * + * @param ActionStateMessageModel $message Сообщение + * + * @return void + */ + public function Add (ActionStateMessageModel $message): void + { + $this->Messages->Add($message); + } + + /** + * Добавляет сообщение об ошибке. + * + * @param string $message Сообщение + * + * @return void + */ + public function AddError (string $message): void + { + $this->Add(new ActionStateMessageModel(MessageType::Error, false, $message)); + } + + /** + * Добавляет предупреждение. + * + * @param string $message Сообщение. + * + * @return void + */ + public function AddWarning (string $message): void + { + $this->Add(new ActionStateMessageModel(MessageType::Warning, false, $message)); + } + + /** + * Добавляет информационное сообщение. + * + * @param string $message Сообщение. + * + * @return void + */ + public function AddInfo (string $message): void + { + $this->Add(new ActionStateMessageModel(MessageType::Info, false, $message)); + } +} \ No newline at end of file diff --git a/sources/traits/ActionState/ActionStateGetTrait.php b/sources/traits/ActionState/ActionStateGetTrait.php new file mode 100644 index 0000000..04aa925 --- /dev/null +++ b/sources/traits/ActionState/ActionStateGetTrait.php @@ -0,0 +1,45 @@ +Messages->GetColumn("Message", $predicate); + + // Возвращаю список + return implode($separator, $result); + } + + /** + * Выбирает сообщения по условию predicate. + * + * @param callable $predicate Условие выборки + * + * @return ObjectArray Список отобранных сообщений + */ + public function GetMessages (callable $predicate): ObjectArray + { + return $this->Messages->GetRows($predicate); + } +} \ No newline at end of file diff --git a/sources/traits/ActionState/ActionStateHasTrait.php b/sources/traits/ActionState/ActionStateHasTrait.php new file mode 100644 index 0000000..09b3310 --- /dev/null +++ b/sources/traits/ActionState/ActionStateHasTrait.php @@ -0,0 +1,68 @@ +Messages->IsExist(fn (ActionStateMessageModel $message) + => $message->MessageType + == MessageType::Info); + } + + /** + * Проверяет, успешно ли завершилась операция. + * + * @param bool $onlyCritical Игнорировать все некритические ошибки и предупреждения (не рекомендуется!) + * + * @return bool Успешно ли завершилась операция. + */ + public function IsSuccess (bool $onlyCritical = false): bool + { + return ($onlyCritical) ? !$this->HasErrors($onlyCritical) : !$this->HasErrors() && !$this->HasWarnings(); + } + + /** + * Проверяет, есть ли ошибки. + * + * @param bool $onlyCritical Учитывать только критические ошибки. + * + * @return bool Наличие ошибок. + */ + public function HasErrors (bool $onlyCritical = false): bool + { + return $this->Messages->IsExist(fn (ActionStateMessageModel $message): bool + => $onlyCritical + ? $message->MessageType == MessageType::Error && $message->IsCritical + : $message->MessageType == MessageType::Error); + } + + /** + * Проверяет, есть ли предупреждения. + * + * @return bool Наличие предупреждений + */ + public function HasWarnings (): bool + { + return $this->Messages->IsExist(fn (ActionStateMessageModel $message) + => $message->MessageType + == MessageType::Warning); + } +} \ No newline at end of file diff --git a/sources/traits/ActionState/ActionStateStaticTrait.php b/sources/traits/ActionState/ActionStateStaticTrait.php new file mode 100644 index 0000000..2f12712 --- /dev/null +++ b/sources/traits/ActionState/ActionStateStaticTrait.php @@ -0,0 +1,51 @@ + $message->MessageType === MessageType::Error; + } + + /** + * При выводе GetStringMessages выводит ошибки и предупреждения. + * + * @return Closure Возвращает функцию, проверяющую сообщение на соответствие типу. + */ + public static function GET_STRING_ERROR_AND_WARNING (): Closure + { + return fn (ActionStateMessageModel $message) + => $message->MessageType === MessageType::Error + || $message->MessageType === MessageType::Warning; + } + + /** + * При выводе GetStringMessages выводит все сообщения. + * + * @return Closure Возвращает функцию, проверяющую сообщение на соответствие типу. + */ + public static function GET_STRING_ALL (): Closure + { + return fn (ActionStateMessageModel $message) => true; + } +} \ No newline at end of file diff --git a/tests/classes/ActionStateTest.php b/tests/classes/ActionStateTest.php new file mode 100644 index 0000000..b436b95 --- /dev/null +++ b/tests/classes/ActionStateTest.php @@ -0,0 +1,54 @@ +PrepareForTest(); + $actionState = new ActionState('123'); + + $this->assertEquals('123', $actionState->Value); + + $actionState->AddError("Non critical error"); + $actionState->AddCritical("Critical error"); + $actionState->AddWarning("Its a warning"); + + $this->assertTrue($actionState->HasErrors()); + $this->assertTrue($actionState->HasErrors(true)); + $this->assertTrue($actionState->HasWarnings()); + $this->assertFalse($actionState->IsSuccess()); + + $messages = $actionState->GetMessages(ActionState::GET_STRING_ERROR_ONLY()); + $this->assertEquals(2, $messages->Count()); + + $this->assertEquals("Non critical error", + $actionState->GetStringMessages(fn (ActionStateMessageModel $message) + => $message->MessageType + == MessageType::Error + && !$message->IsCritical)); + + $actionState2 = new ActionState('321'); + + $actionState2->AddState($actionState); + + $this->assertEquals(3, $actionState2->Count(ActionState::GET_STRING_ALL())); + $this->assertEquals('123', $actionState2->Value); + } + + private function PrepareForTest (): void + { + require_once __DIR__ . '/../../sources/classes/ActionState.php'; + require_once __DIR__ . '/../../sources/traits/ActionState/ActionStateAddTrait.php'; + require_once __DIR__ . '/../../sources/traits/ActionState/ActionStateGetTrait.php'; + require_once __DIR__ . '/../../sources/traits/ActionState/ActionStateHasTrait.php'; + require_once __DIR__ . '/../../sources/traits/ActionState/ActionStateStaticTrait.php'; + require_once __DIR__ . '/../../sources/enums/MessageType.php'; + } +}