20250711 1.1.1 Beta 3
This commit is contained in:
		
							
								
								
									
										36
									
								
								sources/exceptions/TypeException.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								sources/exceptions/TypeException.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace goodboyalex\php_components_pack\exceptions; | ||||||
|  |  | ||||||
|  | use Exception; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Ошибка работы с расширением типов. | ||||||
|  |  * | ||||||
|  |  * @author Александр Бабаев | ||||||
|  |  * @package php_components_pack | ||||||
|  |  * @version 1.0 | ||||||
|  |  * @since 1.1.1 | ||||||
|  |  */ | ||||||
|  | final class TypeException extends Exception | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * @var string $TypeName Имя типа. | ||||||
|  |      */ | ||||||
|  |     public string $TypeName; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Конструктор. | ||||||
|  |      * | ||||||
|  |      * @param string $typeName Имя типа. | ||||||
|  |      * @param string $message Сообщение об ошибке. | ||||||
|  |      */ | ||||||
|  |     public function __construct (string $typeName = "", string $message = "") | ||||||
|  |     { | ||||||
|  |         // Запускаем базовый конструктор | ||||||
|  |         parent::__construct($message); | ||||||
|  |  | ||||||
|  |         // Присваиваем тип | ||||||
|  |         $this->TypeName = $typeName; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -2,11 +2,13 @@ | |||||||
|  |  | ||||||
| namespace goodboyalex\php_components_pack\extensions; | namespace goodboyalex\php_components_pack\extensions; | ||||||
|  |  | ||||||
|  | use Closure; | ||||||
| use DateMalformedStringException; | use DateMalformedStringException; | ||||||
| use DateTime; | use DateTime; | ||||||
| use DateTimeImmutable; | use DateTimeImmutable; | ||||||
| use DateTimeInterface; | use DateTimeInterface; | ||||||
| use Exception; | use Exception; | ||||||
|  | use goodboyalex\php_components_pack\exceptions\TypeException; | ||||||
| use UnitEnum; | use UnitEnum; | ||||||
|  |  | ||||||
| /** | /** | ||||||
| @@ -19,16 +21,38 @@ use UnitEnum; | |||||||
|  */ |  */ | ||||||
| final class TypeExtension | final class TypeExtension | ||||||
| { | { | ||||||
|  |     /** | ||||||
|  |      * Дефолтный метод обработки классов для ToArray. | ||||||
|  |      * | ||||||
|  |      * @return Closure Метод обработки классов для ToArray. | ||||||
|  |      */ | ||||||
|  |     public static function DEFAULT_TO_ARRAY_ON_CLASS (): Closure | ||||||
|  |     { | ||||||
|  |         return fn (object $class) => self::ToArray($class, self::DEFAULT_TO_ARRAY_ON_CLASS()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Переводит объект в массив. |      * Переводит объект в массив. | ||||||
|      * |      * | ||||||
|  |      * @param object $class Объект. | ||||||
|  |      * @param callable $onClass Метод обработки классов. | ||||||
|  |      * | ||||||
|      * @return array Массив свойств типа. |      * @return array Массив свойств типа. | ||||||
|  |      * @throws TypeException Исключение, если объект не является классом. | ||||||
|      */ |      */ | ||||||
|     public function ToArray (object $class): array |     public static function ToArray (object $class, callable $onClass): array | ||||||
|     { |     { | ||||||
|         // Создаю массив результата |         // Создаю массив результата | ||||||
|         $result = []; |         $result = []; | ||||||
|  |  | ||||||
|  |         // Сперва проверяю, что объект является классом | ||||||
|  |         if (!is_object($class)) | ||||||
|  |             // - если нет, то выбрасываю исключение | ||||||
|  |             throw new TypeException($class::class, "Object is not class / Объект не является классом."); | ||||||
|  |  | ||||||
|  |         // Затем записываю имя класса | ||||||
|  |         $result["type_class"] = $class::class; | ||||||
|  |  | ||||||
|         // Получаю свойства класса |         // Получаю свойства класса | ||||||
|         $properties = get_object_vars($class); |         $properties = get_object_vars($class); | ||||||
|  |  | ||||||
| @@ -61,6 +85,15 @@ final class TypeExtension | |||||||
|                 continue; |                 continue; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|  |             // - если значение является классом | ||||||
|  |             if (is_object($value)) { | ||||||
|  |                 // -- добавляю в массив через рекурсию | ||||||
|  |                 $result[$key] = $onClass($value); | ||||||
|  |  | ||||||
|  |                 // -- следующий элемент | ||||||
|  |                 continue; | ||||||
|  |             } | ||||||
|  |  | ||||||
|             // - присваиваю значение |             // - присваиваю значение | ||||||
|             $result[$key] = $value; |             $result[$key] = $value; | ||||||
|         } |         } | ||||||
| @@ -73,21 +106,28 @@ final class TypeExtension | |||||||
|      * Переводит массив в объект. |      * Переводит массив в объект. | ||||||
|      * |      * | ||||||
|      * @param array $array Массив свойств. |      * @param array $array Массив свойств. | ||||||
|      * @param string $className Требуемый класс (внимание: с namespace!). |  | ||||||
|      * |      * | ||||||
|      * @return mixed Объект типа $className. |      * @return mixed Объект типа $className. | ||||||
|      * @throws Exception Исключение, если объект не создан, или дата не корректного формата или пытается передать null |      * @throws TypeException Исключение, если массив не создан через ToArray, объект не создан, дата не корректного | ||||||
|      *     не nullable типу. |      *     формата или пытается передать null не nullable типу. | ||||||
|      */ |      */ | ||||||
|     public function FromArray (array $array, string $className): object |     public function FromArray (array $array): object | ||||||
|     { |     { | ||||||
|  |         // Проверяю, что массив является массивом, созданным через ToArray, то есть содержит ключ type_class | ||||||
|  |         if (!array_key_exists("type_class", $array)) | ||||||
|  |             // - если нет, то выбрасываю исключение | ||||||
|  |             throw new TypeException("array", "Array is not created by ToArray / Массив не создан через ToArray."); | ||||||
|  |  | ||||||
|  |         // Получаю имя класса | ||||||
|  |         $className = $array["type_class"]; | ||||||
|  |  | ||||||
|         // Создаем объект |         // Создаем объект | ||||||
|         $instance = new $className(); |         $instance = new $className(); | ||||||
|  |  | ||||||
|         // Проверяем, что объект создан |         // Проверяем, что объект создан | ||||||
|         if (!is_object($instance) && $instance instanceof $className) |         if (!is_object($instance) && $instance instanceof $className) | ||||||
|             // - если нет, то выбрасываю исключение |             // - если нет, то выбрасываю исключение | ||||||
|             throw new Exception("Object is not created / Объект не создан."); |             throw new TypeException($className, "Object is not created / Объект не создан."); | ||||||
|  |  | ||||||
|         // Получаю свойства класса |         // Получаю свойства класса | ||||||
|         $properties = get_object_vars($instance); |         $properties = get_object_vars($instance); | ||||||
| @@ -109,7 +149,8 @@ final class TypeExtension | |||||||
|                     $instance->$key = new DateTime ('@' . $value); |                     $instance->$key = new DateTime ('@' . $value); | ||||||
|                 } |                 } | ||||||
|                 catch (DateMalformedStringException) { |                 catch (DateMalformedStringException) { | ||||||
|                     throw new Exception("Date is not correct format / Дата не корректного формата."); |                     throw new TypeException($className . "->{$key}::DateTime", | ||||||
|  |                         "Date is not correct format / Дата не корректного формата."); | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 // -- следующий элемент |                 // -- следующий элемент | ||||||
| @@ -123,8 +164,8 @@ final class TypeExtension | |||||||
|                     $instance->$key = new DateTimeImmutable('@' . $value); |                     $instance->$key = new DateTimeImmutable('@' . $value); | ||||||
|                 } |                 } | ||||||
|                 catch (DateMalformedStringException) { |                 catch (DateMalformedStringException) { | ||||||
|                     // -- создаю дату с нулевым временем, если ошибка |                     throw new TypeException($className . "->{$key}::DateTimeImmutable", | ||||||
|                     $instance->$key = new DateTimeImmutable(); |                         "Date is not correct format / Дата не корректного формата."); | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 // -- следующий элемент |                 // -- следующий элемент | ||||||
| @@ -151,13 +192,23 @@ final class TypeExtension | |||||||
|                     $instance->$key = null; |                     $instance->$key = null; | ||||||
|                 } |                 } | ||||||
|                 catch (Exception $exception) { |                 catch (Exception $exception) { | ||||||
|                     throw new Exception("Cannot assign null to non-nullable property. / Невозможно присвоить null не nullable типу: {$exception->getMessage()}."); |                     throw new TypeException($className . "->$key", | ||||||
|  |                         "Cannot assign null to non-nullable property. / Невозможно присвоить null не nullable типу: {$exception->getMessage()}."); | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 // -- следующий элемент |                 // -- следующий элемент | ||||||
|                 continue; |                 continue; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|  |             // - если значение является классом | ||||||
|  |             if (is_object($instance->$key) && is_array($array[$key]) && array_key_exists("type_class", $array[$key])) { | ||||||
|  |                 // -- добавляю в массив через рекурсию | ||||||
|  |                 $instance->$key = self::FromArray($array[$key]); | ||||||
|  |  | ||||||
|  |                 // -- следующий элемент | ||||||
|  |                 continue; | ||||||
|  |             } | ||||||
|  |  | ||||||
|             // - присваиваю значение |             // - присваиваю значение | ||||||
|             $instance->$key = $value; |             $instance->$key = $value; | ||||||
|         } |         } | ||||||
|   | |||||||
							
								
								
									
										39
									
								
								tests/data/MenuCssClassModel.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								tests/data/MenuCssClassModel.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace goodboyalex\php_components_pack\tests\data; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Модель, описывающая css классы, используемые в меню. | ||||||
|  |  * | ||||||
|  |  * @author Александр Бабаев | ||||||
|  |  * @package freecms | ||||||
|  |  * @version 0.1 | ||||||
|  |  * @since 0.1 | ||||||
|  |  */ | ||||||
|  | final class MenuCssClassModel | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * @var string $MenuClass Класс всего списка меню. | ||||||
|  |      */ | ||||||
|  |     public string $MenuClass = ""; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @var string $ItemClass Класс элемента меню. | ||||||
|  |      */ | ||||||
|  |     public string $ItemClass = ""; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @var string $ItemSubMenuClass Класс элемента, вызывающего вложенный список. | ||||||
|  |      */ | ||||||
|  |     public string $ItemSubMenuClass = ""; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @var string $SubMenuClass Класс вложенного списка. | ||||||
|  |      */ | ||||||
|  |     public string $SubMenuClass = ""; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @var string $SubItemClass Класс элемента вложенного списка. | ||||||
|  |      */ | ||||||
|  |     public string $SubItemClass = ""; | ||||||
|  | } | ||||||
							
								
								
									
										100
									
								
								tests/data/MenuItemModel.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								tests/data/MenuItemModel.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,100 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace goodboyalex\php_components_pack\tests\data; | ||||||
|  |  | ||||||
|  | use Exception; | ||||||
|  | use goodboyalex\php_components_pack\classes\ClassMapper; | ||||||
|  | use goodboyalex\php_components_pack\extensions\GUIDExtension; | ||||||
|  | use goodboyalex\php_components_pack\interfaces\IDuplicated; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Модель элемента меню. | ||||||
|  |  * | ||||||
|  |  * @author Александр Бабаев | ||||||
|  |  * @package freecms | ||||||
|  |  * @version 0.1 | ||||||
|  |  * @since 0.1 | ||||||
|  |  */ | ||||||
|  | final class MenuItemModel implements IDuplicated | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * @var string $Id Идентификатор элемента. | ||||||
|  |      */ | ||||||
|  |     public string $Id { | ||||||
|  |         get { | ||||||
|  |             return $this->Id ?? GUIDExtension::GUIDEmpty; | ||||||
|  |         } | ||||||
|  |         set { | ||||||
|  |             // Проверка идентификатора | ||||||
|  |             if (!GUIDExtension::Validate($value)) | ||||||
|  |                 // - исключение | ||||||
|  |                 throw new Exception("Неверный идентификатор (GUID)"); | ||||||
|  |  | ||||||
|  |             // Установка идентификатора | ||||||
|  |             $this->Id = $value; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @var string $Name Имя элемента. | ||||||
|  |      */ | ||||||
|  |     public string $Name; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @var string|null $Description Описание элемента. | ||||||
|  |      */ | ||||||
|  |     public ?string $Description; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @var string $URL Адрес URL элемента. | ||||||
|  |      */ | ||||||
|  |     public string $URL; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @var bool $OpenInNewWindow Открывать ли в новом окне (добавлять к ссылке target="_blank"). | ||||||
|  |      */ | ||||||
|  |     public bool $OpenInNewWindow; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @var string|null $IconClass Класс иконки. | ||||||
|  |      */ | ||||||
|  |     public ?string $IconClass; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @var string $ParentId Идентификатор родительского элемента. | ||||||
|  |      */ | ||||||
|  |     public string $ParentId { | ||||||
|  |         get { | ||||||
|  |             return $this->ParentId ?? GUIDExtension::GUIDEmpty; | ||||||
|  |         } | ||||||
|  |         set { | ||||||
|  |             // Проверка идентификатора | ||||||
|  |             if (!GUIDExtension::Validate($value)) | ||||||
|  |                 // - исключение | ||||||
|  |                 throw new Exception("Неверный идентификатор (GUID)"); | ||||||
|  |  | ||||||
|  |             // Установка идентификатора | ||||||
|  |             $this->ParentId = $value; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @var int $Order Порядок. | ||||||
|  |      */ | ||||||
|  |     public int $Order; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @inheritdoc | ||||||
|  |      */ | ||||||
|  |     public function Duplicate (): MenuItemModel | ||||||
|  |     { | ||||||
|  |         // Создание дубликата модели | ||||||
|  |         $model = new MenuItemModel(); | ||||||
|  |  | ||||||
|  |         // Копирование свойств | ||||||
|  |         ClassMapper::MapClass($this, $model); | ||||||
|  |  | ||||||
|  |         // Возврат дубликата | ||||||
|  |         return $model; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										555
									
								
								tests/data/MenuItems.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										555
									
								
								tests/data/MenuItems.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,555 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace goodboyalex\php_components_pack\tests\data; | ||||||
|  |  | ||||||
|  | use goodboyalex\php_components_pack\classes\ActionState; | ||||||
|  | use goodboyalex\php_components_pack\classes\ObjectArray; | ||||||
|  | use goodboyalex\php_components_pack\extensions\GUIDExtension; | ||||||
|  | use goodboyalex\php_components_pack\interfaces\IDuplicated; | ||||||
|  | use goodboyalex\php_components_pack\interfaces\ISerializable; | ||||||
|  | use IteratorAggregate; | ||||||
|  | use Traversable; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Класс списка элементов меню. | ||||||
|  |  * | ||||||
|  |  * @author Александр Бабаев | ||||||
|  |  * @package freecms | ||||||
|  |  * @version 0.1 | ||||||
|  |  * @since 0.1 | ||||||
|  |  */ | ||||||
|  | final class MenuItems implements ISerializable, IteratorAggregate, IDuplicated | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * @var ObjectArray Переменная для хранения списка. | ||||||
|  |      */ | ||||||
|  |     private ObjectArray $_items; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Конструктор. | ||||||
|  |      * | ||||||
|  |      * @param ObjectArray|array $items Список элементов меню. | ||||||
|  |      */ | ||||||
|  |     public function __construct (ObjectArray|array $items) | ||||||
|  |     { | ||||||
|  |         $this->_items = is_array($items) ? new ObjectArray($items) : $items; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Добавляет список элементов. | ||||||
|  |      * | ||||||
|  |      * @param ObjectArray|array $items Список элементов меню. | ||||||
|  |      * | ||||||
|  |      * @return void | ||||||
|  |      */ | ||||||
|  |     public function AddItems (ObjectArray|array $items): void | ||||||
|  |     { | ||||||
|  |         // Получаю список | ||||||
|  |         $itemsToAdd = is_array($items) ? new ObjectArray($items) : $items; | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * @var MenuItemModel $item Элемент меню | ||||||
|  |          */ | ||||||
|  |         foreach ($itemsToAdd as $item) | ||||||
|  |             // - добавляю элемент | ||||||
|  |             $this->AddItem($item); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Добавляет элемент меню в список. | ||||||
|  |      * | ||||||
|  |      * @param MenuItemModel $item Элемент меню. | ||||||
|  |      * | ||||||
|  |      * @return void | ||||||
|  |      */ | ||||||
|  |     public function AddItem (MenuItemModel $item): void | ||||||
|  |     { | ||||||
|  |         // Добавляю | ||||||
|  |         $this->_items[] = $item; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Содержится ли элемент в списке. | ||||||
|  |      * | ||||||
|  |      * @param string $id Идентификатор элемента меню. | ||||||
|  |      * | ||||||
|  |      * @return bool Содержится ли элемент в списке. | ||||||
|  |      */ | ||||||
|  |     public function ContainsItem (string $id): bool | ||||||
|  |     { | ||||||
|  |         // Проверяю, что идентификатор не пустой | ||||||
|  |         if (GUIDExtension::IsNotValidOrEmpty($id)) | ||||||
|  |             // - возвращаю отрицательный результат | ||||||
|  |             return false; | ||||||
|  |  | ||||||
|  |         // Получаю, что элемент с таким идентификатором существует | ||||||
|  |         return $this->_items->IsExist(fn (MenuItemModel $item) => $item->Id == $id); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Вычисляет количество элементов меню. | ||||||
|  |      * | ||||||
|  |      * @param callable|null $predicate Выражение, уточняющее детали. | ||||||
|  |      * | ||||||
|  |      * @return int Количество элементов меню. | ||||||
|  |      */ | ||||||
|  |     public function Count (?callable $predicate = null): int | ||||||
|  |     { | ||||||
|  |         return $this->_items->Count($predicate); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Очищает список элементов. | ||||||
|  |      * | ||||||
|  |      * @return void | ||||||
|  |      */ | ||||||
|  |     public function Clear (): void | ||||||
|  |     { | ||||||
|  |         // Очищаю | ||||||
|  |         $this->_items->Clear(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Перемещает элемент меню вверх. | ||||||
|  |      * | ||||||
|  |      * @param string $id Идентификатор элемента меню. | ||||||
|  |      * | ||||||
|  |      * @return ActionState Результат выполнения. | ||||||
|  |      */ | ||||||
|  |     public function MoveUp (string $id): ActionState | ||||||
|  |     { | ||||||
|  |         // Создаю результат | ||||||
|  |         $result = new ActionState(); | ||||||
|  |  | ||||||
|  |         // Проверяю, что идентификатор не пустой | ||||||
|  |         if (GUIDExtension::IsNotValidOrEmpty($id)) { | ||||||
|  |             // - то выдаю ошибку | ||||||
|  |             $result->AddError("Неверный идентификатор (GUID)"); | ||||||
|  |  | ||||||
|  |             // - и прерываю | ||||||
|  |             return $result; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Загружаю элемент | ||||||
|  |         $item = $this->GetItem($id); | ||||||
|  |  | ||||||
|  |         // Если элемент не загружен | ||||||
|  |         if ($item == null) { | ||||||
|  |             // - то выдаю ошибку | ||||||
|  |             $result->AddError("Пункт меню с идентификатором 0%s не найден!"); | ||||||
|  |  | ||||||
|  |             // - и прерываю | ||||||
|  |             return $result; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Получаю его текущий порядковый номер | ||||||
|  |         $oldOrder = $item->Order; | ||||||
|  |  | ||||||
|  |         // Если порядковый номер не больше 1 | ||||||
|  |         if ($oldOrder <= 1) { | ||||||
|  |             // - то выдаю предупреждение | ||||||
|  |             $result->AddWarning("Пункт меню находится на первом месте. Перемещение не требуется!"); | ||||||
|  |  | ||||||
|  |             // - и прерываю | ||||||
|  |             return $result; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Получаю новый порядковый номер | ||||||
|  |         $newOrder = $oldOrder - 1; | ||||||
|  |  | ||||||
|  |         // Получаю элемент, находящийся на новом порядковом номере (или GuidExEmpty, если нет элемента) | ||||||
|  |         $oldPlaceItem = $this->_items->GetRow(fn (MenuItemModel $item) => $item->Order == $newOrder); | ||||||
|  |  | ||||||
|  |         // Присваиваю новый порядковый номер изменяемого элемента | ||||||
|  |         $item->Order = $newOrder; | ||||||
|  |  | ||||||
|  |         // Обновляю список элементов | ||||||
|  |         $this->UpdateItem($item); | ||||||
|  |  | ||||||
|  |         // И если на новом порядковом номере существовал элемент | ||||||
|  |         if ($oldPlaceItem !== false) { | ||||||
|  |             // - то присваиваю ему старый порядковый номер | ||||||
|  |             $oldPlaceItem->Order = $oldOrder; | ||||||
|  |  | ||||||
|  |             // - и обновляю список | ||||||
|  |             $this->UpdateItem($oldPlaceItem); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Возвращаю результат | ||||||
|  |         return $result; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Получает элемент меню. | ||||||
|  |      * | ||||||
|  |      * @param string $id Идентификатор элемента меню. | ||||||
|  |      * | ||||||
|  |      * @return MenuItemModel|null Элемент меню или null, если элемент не найден. | ||||||
|  |      */ | ||||||
|  |     public function GetItem (string $id): ?MenuItemModel | ||||||
|  |     { | ||||||
|  |         // Проверяю, что идентификатор не пустой | ||||||
|  |         if (GUIDExtension::IsNotValidOrEmpty($id)) | ||||||
|  |             // - то возвращаю null | ||||||
|  |             return null; | ||||||
|  |  | ||||||
|  |         // Получаю элемент | ||||||
|  |         $item = $this->_items->GetRow(fn (MenuItemModel $item) => $item->Id == $id); | ||||||
|  |  | ||||||
|  |         // Если элемент не найден, то возвращаю null, иначе возвращаю найденный элемент. | ||||||
|  |         return ($item === false) ? null : $item; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Обновляет элемент меню. | ||||||
|  |      * | ||||||
|  |      * @param MenuItemModel $item Обновлённый элемент меню. | ||||||
|  |      * | ||||||
|  |      * @return void | ||||||
|  |      */ | ||||||
|  |     public function UpdateItem (MenuItemModel $item): void | ||||||
|  |     { | ||||||
|  |         // Если элемент существует | ||||||
|  |         if ($this->_items->IsExist(fn (MenuItemModel $itemM) => $itemM->Id == $item->Id)) | ||||||
|  |             // - то удаляю его | ||||||
|  |             $this->RemoveItem($item->Id); | ||||||
|  |  | ||||||
|  |         // Добавляю новый | ||||||
|  |         $this->AddItem($item); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Удаление элемента меню. | ||||||
|  |      * | ||||||
|  |      * @param string $id Идентификатор элемента меню. | ||||||
|  |      * | ||||||
|  |      * @return bool Статус удаления. | ||||||
|  |      */ | ||||||
|  |     public function RemoveItem (string $id): bool | ||||||
|  |     { | ||||||
|  |         // Проверяю, что идентификатор не пустой | ||||||
|  |         if (GUIDExtension::IsNotValidOrEmpty($id)) | ||||||
|  |             // - возвращаю отрицательный результат | ||||||
|  |             return false; | ||||||
|  |  | ||||||
|  |         return $this->_items->Delete(fn (MenuItemModel $item) => $item->Id == $id); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Перемещает элемент меню вниз. | ||||||
|  |      * | ||||||
|  |      * @param string $id Идентификатор элемента меню. | ||||||
|  |      * | ||||||
|  |      * @return ActionState Результат выполнения. | ||||||
|  |      */ | ||||||
|  |     public function MoveDown (string $id): ActionState | ||||||
|  |     { | ||||||
|  |         // Создаю результат | ||||||
|  |         $result = new ActionState(); | ||||||
|  |  | ||||||
|  |         // Проверяю, что идентификатор не пустой | ||||||
|  |         if (GUIDExtension::IsNotValidOrEmpty($id)) { | ||||||
|  |             // - то выдаю ошибку | ||||||
|  |             $result->AddError("Неверный идентификатор (GUID)"); | ||||||
|  |  | ||||||
|  |             // - и прерываю | ||||||
|  |             return $result; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Загружаю элемент | ||||||
|  |         $item = $this->GetItem($id); | ||||||
|  |  | ||||||
|  |         // Если элемент не загружен | ||||||
|  |         if ($item == null) { | ||||||
|  |             // - то выдаю ошибку | ||||||
|  |             $result->AddError("Пункт меню с идентификатором 0%s не найден!"); | ||||||
|  |  | ||||||
|  |             // - и прерываю | ||||||
|  |             return $result; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Получаю его текущий порядковый номер | ||||||
|  |         $oldOrder = $item->Order; | ||||||
|  |  | ||||||
|  |         // Если порядковый номер не больше 1 | ||||||
|  |         if ($oldOrder >= $this->GetLastItemOrder($item->ParentId)) { | ||||||
|  |             // - то выдаю предупреждение | ||||||
|  |             $result->AddWarning("Пункт меню находится на последнем месте. Перемещение не требуется!"); | ||||||
|  |  | ||||||
|  |             // - и прерываю | ||||||
|  |             return $result; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Получаю новый порядковый номер | ||||||
|  |         $newOrder = $oldOrder + 1; | ||||||
|  |  | ||||||
|  |         // Получаю элемент, находящийся на новом порядковом номере (или GuidExEmpty, если нет элемента) | ||||||
|  |         $oldPlaceItem = $this->_items->GetRow(fn (MenuItemModel $item) => $item->Order == $newOrder); | ||||||
|  |  | ||||||
|  |         // Присваиваю новый порядковый номер изменяемого элемента | ||||||
|  |         $item->Order = $newOrder; | ||||||
|  |  | ||||||
|  |         // Обновляю список элементов | ||||||
|  |         $this->UpdateItem($item); | ||||||
|  |  | ||||||
|  |         // И если на новом порядковом номере существовал элемент | ||||||
|  |         if ($oldPlaceItem !== false) { | ||||||
|  |             // - то присваиваю ему старый порядковый номер | ||||||
|  |             $oldPlaceItem->Order = $oldOrder; | ||||||
|  |  | ||||||
|  |             // - и обновляю список | ||||||
|  |             $this->UpdateItem($oldPlaceItem); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Возвращаю результат | ||||||
|  |         return $result; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Получает порядковый номер последнего элемента в списке. | ||||||
|  |      * | ||||||
|  |      * @param string $parentItemId Идентификатор родителя. | ||||||
|  |      * | ||||||
|  |      * @return int Порядковый номер последнего элемента в списке. | ||||||
|  |      */ | ||||||
|  |     public function GetLastItemOrder (string $parentItemId): int | ||||||
|  |     { | ||||||
|  |         // Проверяю, что идентификатор не пустой | ||||||
|  |         if (GUIDExtension::IsNotValidOrEmpty($parentItemId) && $parentItemId !== GUIDExtension::GUIDEmpty) | ||||||
|  |             // - возвращаю отрицательный результат | ||||||
|  |             return 0; | ||||||
|  |  | ||||||
|  |         // Получаю последний элемент | ||||||
|  |         $item = $this->GetSubItems($parentItemId)->Last(false); | ||||||
|  |  | ||||||
|  |         // Если элемент не найден | ||||||
|  |         if ($item === false) | ||||||
|  |             // - возвращаю нулевой результат | ||||||
|  |             return 0; | ||||||
|  |  | ||||||
|  |         // Возвращаю порядок последнего элемента | ||||||
|  |         return $item->Order; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Получает список вложенных элементов. | ||||||
|  |      * | ||||||
|  |      * @param string $parentItemId Идентификатор родителя. | ||||||
|  |      * @param bool $sortByOrder Нужно ли сортировать по порядку элементов. | ||||||
|  |      * | ||||||
|  |      * @return ObjectArray Список вложенных элементов. | ||||||
|  |      */ | ||||||
|  |     public function GetSubItems (string $parentItemId, bool $sortByOrder = true): ObjectArray | ||||||
|  |     { | ||||||
|  |         // Проверяю, что идентификатор корректен | ||||||
|  |         if (GUIDExtension::IsNotValidOrEmpty($parentItemId) && $parentItemId !== GUIDExtension::GUIDEmpty) | ||||||
|  |             // - возвращаю отрицательный результат | ||||||
|  |             return new ObjectArray([]); | ||||||
|  |  | ||||||
|  |         // Получаю список элементов | ||||||
|  |         $result = $this->_items->GetRows(fn (MenuItemModel $item) => $item->ParentId == $parentItemId); | ||||||
|  |  | ||||||
|  |         // Если нужно сортировать | ||||||
|  |         if ($sortByOrder) | ||||||
|  |             // - сортирую | ||||||
|  |             $result->Sort("Order"); | ||||||
|  |  | ||||||
|  |         // Возвращаю результат | ||||||
|  |         return $result; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Изменяет родителя у элемента. | ||||||
|  |      * | ||||||
|  |      * @param string $id Идентификатор элемента. | ||||||
|  |      * @param string $newParentId Идентификатор нового родителя. | ||||||
|  |      * | ||||||
|  |      * @return ActionState Результат выполнения. | ||||||
|  |      */ | ||||||
|  |     public function ChangeParent (string $id, string $newParentId): ActionState | ||||||
|  |     { | ||||||
|  |         // Создаю результат | ||||||
|  |         $result = new ActionState(); | ||||||
|  |  | ||||||
|  |         // Проверяю, что идентификатор не пустой | ||||||
|  |         if (GUIDExtension::IsNotValidOrEmpty($id) || GUIDExtension::IsNotValidOrEmpty($newParentId)) { | ||||||
|  |             // - то выдаю ошибку | ||||||
|  |             $result->AddError("Неверный идентификатор (GUID)"); | ||||||
|  |  | ||||||
|  |             // - и прерываю | ||||||
|  |             return $result; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Если имеет дочерние | ||||||
|  |         if ($this->HasSubItems($id)) { | ||||||
|  |             // - то выдаю ошибку | ||||||
|  |             $result->AddError( | ||||||
|  |                 "Пункт меню с идентификатором 0%s имеет дочерние пункты (подпункты). Пожалуйста, сперва переместите их, а потом будет возможно сменить родителя у данного элемента!"); | ||||||
|  |  | ||||||
|  |             // - и прерываю | ||||||
|  |             return $result; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Загружаю элемент | ||||||
|  |         $item = $this->GetItem($id); | ||||||
|  |  | ||||||
|  |         // Если элемент не загружен | ||||||
|  |         if ($item == null) { | ||||||
|  |             // - то выдаю ошибку | ||||||
|  |             $result->AddError("Пункт меню с идентификатором 0%s не найден!"); | ||||||
|  |  | ||||||
|  |             // - и прерываю | ||||||
|  |             return $result; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Получаю список свободных порядковых номеров | ||||||
|  |         $freeOrdersList = $this->GetFreeOrders($newParentId); | ||||||
|  |  | ||||||
|  |         // Получаю первый свободный порядковый номер | ||||||
|  |         $newOrder = count($freeOrdersList) > 0 ? min($freeOrdersList) : $this->GetLastItemOrder($newParentId) + 1; | ||||||
|  |  | ||||||
|  |         // Присваиваю элементу идентификатор нового родителя | ||||||
|  |         $item->ParentId = $newParentId; | ||||||
|  |  | ||||||
|  |         // Устанавливаю его порядок | ||||||
|  |         $item->Order = $newOrder; | ||||||
|  |  | ||||||
|  |         // Обновляю список элементов | ||||||
|  |         $this->UpdateItem($item); | ||||||
|  |  | ||||||
|  |         // Возвращаю результат | ||||||
|  |         return $result; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Проверяет, имеет ли элемент дочерние. | ||||||
|  |      * | ||||||
|  |      * @param string $id Идентификатор элемента меню. | ||||||
|  |      * | ||||||
|  |      * @return bool Имеет ли элемент дочерние. | ||||||
|  |      */ | ||||||
|  |     public function HasSubItems (string $id): bool | ||||||
|  |     { | ||||||
|  |         // Проверяю, что идентификатор не пустой | ||||||
|  |         if (GUIDExtension::IsNotValidOrEmpty($id)) | ||||||
|  |             // - возвращаю отрицательный результат | ||||||
|  |             return false; | ||||||
|  |  | ||||||
|  |         // Проверяю, существует ли элемент, у которого идентификатор родителя совпадает | ||||||
|  |         // с идентификатором указанного элемента | ||||||
|  |         return $this->_items->IsExist(fn (MenuItemModel $item) => $item->ParentId == $id); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Получает порядковый номер отсутствующего элемента в списке между первым и последним. | ||||||
|  |      * | ||||||
|  |      * @param string $parentItemId Идентификатор родителя. | ||||||
|  |      * | ||||||
|  |      * @return array Список порядковых номеров, которые не используются. | ||||||
|  |      */ | ||||||
|  |     public function GetFreeOrders (string $parentItemId): array | ||||||
|  |     { | ||||||
|  |         // Проверяю, что идентификатор не пустой | ||||||
|  |         if (GUIDExtension::IsNotValidOrEmpty($parentItemId) && $parentItemId !== GUIDExtension::GUIDEmpty) | ||||||
|  |             // - возвращаю отрицательный результат | ||||||
|  |             return []; | ||||||
|  |  | ||||||
|  |         // Получаю список элементов | ||||||
|  |         $items = $this->GetSubItems($parentItemId); | ||||||
|  |  | ||||||
|  |         // Создаю список-результат | ||||||
|  |         $result = []; | ||||||
|  |  | ||||||
|  |         // Получаю минимальный порядок элементов | ||||||
|  |         $min = $this->GetFirstItemOrder($parentItemId); | ||||||
|  |  | ||||||
|  |         // Получаю максимальный порядок элементов | ||||||
|  |         $max = $this->GetLastItemOrder($parentItemId); | ||||||
|  |  | ||||||
|  |         // Если произошёл уникальный случай, когда нет элементов | ||||||
|  |         if ($min == 0 || $max == 0) | ||||||
|  |             return $result; | ||||||
|  |  | ||||||
|  |         // Заношу в список все до минимума | ||||||
|  |         if ($min > 0) | ||||||
|  |             for ($ind = 1; $ind < $min; $ind++) | ||||||
|  |                 $result[] = $ind; | ||||||
|  |  | ||||||
|  |         // Прохожу "занятые" элементы | ||||||
|  |         for ($ind = $min; $ind <= $max; $ind++) | ||||||
|  |             // - и проверяю их на свободные | ||||||
|  |             if (!$items->IsExist(fn (MenuItemModel $item) => $item->Order == $ind)) | ||||||
|  |                 // -- заношу свободные в список | ||||||
|  |                 $result[] = $ind; | ||||||
|  |  | ||||||
|  |         // Сортирую список | ||||||
|  |         sort($result, SORT_NUMERIC); | ||||||
|  |  | ||||||
|  |         // Возвращаю результат | ||||||
|  |         return $result; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Получает порядковый номер первого элемента в списке. | ||||||
|  |      * | ||||||
|  |      * @param string $parentItemId Идентификатор родителя. | ||||||
|  |      * | ||||||
|  |      * @return int Порядковый номер первого элемента в списке. | ||||||
|  |      */ | ||||||
|  |     public function GetFirstItemOrder (string $parentItemId): int | ||||||
|  |     { | ||||||
|  |         // Проверяю, что идентификатор не пустой | ||||||
|  |         if (GUIDExtension::IsNotValidOrEmpty($parentItemId) && $parentItemId !== GUIDExtension::GUIDEmpty) | ||||||
|  |             // - возвращаю отрицательный результат | ||||||
|  |             return 0; | ||||||
|  |  | ||||||
|  |         // Получаю первый элемент | ||||||
|  |         $item = $this->GetSubItems($parentItemId)->First(false); | ||||||
|  |  | ||||||
|  |         // Если элемент не найден | ||||||
|  |         if ($item === false) | ||||||
|  |             // - возвращаю нулевой результат | ||||||
|  |             return 0; | ||||||
|  |  | ||||||
|  |         // Возвращаю порядок первого элемента | ||||||
|  |         return $item->Order; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @inheritdoc | ||||||
|  |      */ | ||||||
|  |     public function getIterator (): Traversable | ||||||
|  |     { | ||||||
|  |         return $this->_items->getIterator(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @inheritdoc | ||||||
|  |      */ | ||||||
|  |     public function Duplicate (): MenuItems | ||||||
|  |     { | ||||||
|  |         return new MenuItems($this->_items); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @inheritdoc | ||||||
|  |      */ | ||||||
|  |     public | ||||||
|  |     function Serialize (): string | ||||||
|  |     { | ||||||
|  |         return $this->_items->Serialize(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @inheritdoc | ||||||
|  |      */ | ||||||
|  |     public | ||||||
|  |     function UnSerialize (string $serialized): void | ||||||
|  |     { | ||||||
|  |         // Создаю новый класс списка элементов | ||||||
|  |         $this->_items = new ObjectArray([]); | ||||||
|  |  | ||||||
|  |         // Восстанавливаю данные | ||||||
|  |         $this->_items->UnSerialize($serialized); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										139
									
								
								tests/data/MenuModel.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										139
									
								
								tests/data/MenuModel.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,139 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace goodboyalex\php_components_pack\tests\data; | ||||||
|  |  | ||||||
|  | use Exception; | ||||||
|  | use goodboyalex\php_components_pack\classes\ClassMapper; | ||||||
|  | use goodboyalex\php_components_pack\extensions\GUIDExtension; | ||||||
|  | use goodboyalex\php_components_pack\interfaces\IDuplicated; | ||||||
|  | use goodboyalex\php_components_pack\interfaces\IStoredAtSQL; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Модель меню. | ||||||
|  |  * | ||||||
|  |  * @author Александр Бабаев | ||||||
|  |  * @package freecms | ||||||
|  |  * @version 0.1 | ||||||
|  |  * @since 0.1 | ||||||
|  |  */ | ||||||
|  | final class MenuModel implements IDuplicated, IStoredAtSQL | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * @var string $Id Идентификатор меню. | ||||||
|  |      */ | ||||||
|  |     public string $Id { | ||||||
|  |         get { | ||||||
|  |             return $this->Id ?? GUIDExtension::GUIDEmpty; | ||||||
|  |         } | ||||||
|  |         set { | ||||||
|  |             // Проверка идентификатора | ||||||
|  |             if (!GUIDExtension::Validate($value)) | ||||||
|  |                 // - исключение | ||||||
|  |                 throw new Exception("Неверный идентификатор (GUID)"); | ||||||
|  |  | ||||||
|  |             // Установка идентификатора | ||||||
|  |             $this->Id = $value; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @var string $Name Имя меню. | ||||||
|  |      */ | ||||||
|  |     public string $Name = ""; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @var string $Description Описание меню. | ||||||
|  |      */ | ||||||
|  |     public string $Description = ""; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @var MenuItems Элементы меню. | ||||||
|  |      */ | ||||||
|  |     public MenuItems $Items; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @var bool $AllowSubMenu Допустимо ли вложенное меню. | ||||||
|  |      */ | ||||||
|  |     public bool $AllowSubMenu = true; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @var MenuCssClassModel $Css Модель стилей оформления меню. | ||||||
|  |      */ | ||||||
|  |     public MenuCssClassModel $Css; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Конструктор. | ||||||
|  |      */ | ||||||
|  |     public function __construct () | ||||||
|  |     { | ||||||
|  |         $this->Items = new MenuItems([]); | ||||||
|  |         $this->Css = new MenuCssClassModel(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @inheritdoc | ||||||
|  |      */ | ||||||
|  |     public function Duplicate (): MenuModel | ||||||
|  |     { | ||||||
|  |         // Создаю новый класс | ||||||
|  |         $model = new MenuModel(); | ||||||
|  |  | ||||||
|  |         // Копирую свойства класса | ||||||
|  |         ClassMapper::MapClass($this, $model); | ||||||
|  |  | ||||||
|  |         // Возвращаю класс | ||||||
|  |         return $model; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @inheritDoc | ||||||
|  |      */ | ||||||
|  |     public function ToSQL (bool $withId = true): array | ||||||
|  |     { | ||||||
|  |         // Создаем результат | ||||||
|  |         $result = []; | ||||||
|  |  | ||||||
|  |         // Добавляем значения | ||||||
|  |         $result['Name'] = $this->Name; | ||||||
|  |         $result['Description'] = $this->Description; | ||||||
|  |         $result['Items'] = $this->Items->Serialize(); | ||||||
|  |         $result['AllowSubMenu'] = $this->AllowSubMenu ? 1 : 0; | ||||||
|  |         $result['Css'] = serialize($this->Css); | ||||||
|  |  | ||||||
|  |         // Если требуется идентификатор | ||||||
|  |         if ($withId) | ||||||
|  |             // - то добавляем его | ||||||
|  |             $result['Id'] = $this->Id; | ||||||
|  |  | ||||||
|  |         // Возвращаем результат | ||||||
|  |         return $result; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @inheritDoc | ||||||
|  |      */ | ||||||
|  |     public function FromSQL (array $sqlData): MenuModel | ||||||
|  |     { | ||||||
|  |         // Создаем результат | ||||||
|  |         $result = new MenuModel(); | ||||||
|  |  | ||||||
|  |         // Устанавливаем значения | ||||||
|  |         if (isset($sqlData['Id'])) | ||||||
|  |             $result->Id = $sqlData['Id']; | ||||||
|  |         if (isset($sqlData['Name'])) | ||||||
|  |             $result->Name = $sqlData['Name']; | ||||||
|  |         if (isset($sqlData['Description'])) | ||||||
|  |             $result->Description = $sqlData['Description']; | ||||||
|  |         $this->Items = new MenuItems([]); | ||||||
|  |         if (isset($sqlData['Items'])) | ||||||
|  |             $result->Items->UnSerialize($sqlData['Items']); | ||||||
|  |         if (isset($sqlData['AllowSubMenu'])) | ||||||
|  |             $result->AllowSubMenu = $sqlData['AllowSubMenu'] == 1; | ||||||
|  |         $this->Css = new MenuCssClassModel(); | ||||||
|  |         if (isset($sqlData['Css'])) | ||||||
|  |             $result->Css = unserialize($sqlData['Css']); | ||||||
|  |  | ||||||
|  |         // Возвращаем массив | ||||||
|  |         return $result; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										71
									
								
								tests/extensions/TypeExtensionTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								tests/extensions/TypeExtensionTest.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,71 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace goodboyalex\php_components_pack\tests\extensions; | ||||||
|  |  | ||||||
|  | use goodboyalex\php_components_pack\extensions\GUIDExtension; | ||||||
|  | use goodboyalex\php_components_pack\extensions\TypeExtension; | ||||||
|  | use goodboyalex\php_components_pack\tests\data\MenuCssClassModel; | ||||||
|  | use goodboyalex\php_components_pack\tests\data\MenuItemModel; | ||||||
|  | use goodboyalex\php_components_pack\tests\data\MenuItems; | ||||||
|  | use goodboyalex\php_components_pack\tests\data\MenuModel; | ||||||
|  | use PHPUnit\Framework\TestCase; | ||||||
|  |  | ||||||
|  | class TypeExtensionTest extends TestCase | ||||||
|  | { | ||||||
|  |     public function testFromArray () | ||||||
|  |     { | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testToArray () | ||||||
|  |     { | ||||||
|  |         $this->PrepareForTest(); | ||||||
|  |  | ||||||
|  |         $menu = new MenuModel(); | ||||||
|  |         $menu->Id = GUIDExtension::Generate(); | ||||||
|  |         $menu->Name = 'Menu'; | ||||||
|  |         $menu->Description = 'Description'; | ||||||
|  |         $menu->AllowSubMenu = true; | ||||||
|  |         $menu->Css = new MenuCssClassModel(); | ||||||
|  |         $menu->Css->MenuClass = "menuClass"; | ||||||
|  |         $menu->Css->ItemClass = "itemClass"; | ||||||
|  |         $menu->Css->SubItemClass = "subItemClass"; | ||||||
|  |         $menu->Css->ItemSubMenuClass = "itemSubMenuClass"; | ||||||
|  |  | ||||||
|  |         $menuItem1 = new MenuItemModel(); | ||||||
|  |         $menuItem1->Id = GUIDExtension::Generate(); | ||||||
|  |         $menuItem1->Name = 'MenuItem1'; | ||||||
|  |         $menuItem1->Description = 'Description'; | ||||||
|  |         $menuItem1->Order = 1; | ||||||
|  |         $menuItem1->ParentId = GUIDExtension::GUIDEmpty; | ||||||
|  |         $menuItem1->URL = 'https://www.google.com'; | ||||||
|  |         $menu->Items->AddItem($menuItem1); | ||||||
|  |         $menuItem2 = new MenuItemModel(); | ||||||
|  |         $menuItem2->Id = GUIDExtension::Generate(); | ||||||
|  |         $menuItem2->Name = 'MenuItem2'; | ||||||
|  |         $menuItem2->Description = 'Description'; | ||||||
|  |         $menuItem2->ParentId = $menuItem1->Id; | ||||||
|  |         $menuItem2->Order = 1; | ||||||
|  |         $menuItem2->URL = 'https://www.google.ru'; | ||||||
|  |         $menu->Items->AddItem($menuItem2); | ||||||
|  |  | ||||||
|  |         $closure = fn (object $class) => $class::class == MenuItems::class ? $class->Serialize() | ||||||
|  |             : TypeExtension::ToArray($class, TypeExtension::DEFAULT_TO_ARRAY_ON_CLASS()); | ||||||
|  |  | ||||||
|  |         $array = TypeExtension::ToArray($menu, $closure); | ||||||
|  |  | ||||||
|  |         file_put_contents(__DIR__ . "/class.txt", json_encode($array, JSON_PRETTY_PRINT)); | ||||||
|  |         var_dump($array); | ||||||
|  |         die(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private function PrepareForTest (): void | ||||||
|  |     { | ||||||
|  |         require_once __DIR__ . '/../../sources/exceptions/TypeException.php'; | ||||||
|  |         require_once __DIR__ . '/../../sources/extensions/TypeExtension.php'; | ||||||
|  |         require_once __DIR__ . '/../data/MenuItemModel.php'; | ||||||
|  |         require_once __DIR__ . '/../data/MenuCssClassModel.php'; | ||||||
|  |         require_once __DIR__ . '/../data/MenuItems.php'; | ||||||
|  |         require_once __DIR__ . '/../data/MenuModel.php'; | ||||||
|  |     } | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user