diff --git a/sources/exceptions/TypeException.php b/sources/exceptions/TypeException.php new file mode 100644 index 0000000..6eb56b4 --- /dev/null +++ b/sources/exceptions/TypeException.php @@ -0,0 +1,36 @@ +TypeName = $typeName; + } +} \ No newline at end of file diff --git a/sources/extensions/TypeExtension.php b/sources/extensions/TypeExtension.php index f3d48d2..72156cf 100644 --- a/sources/extensions/TypeExtension.php +++ b/sources/extensions/TypeExtension.php @@ -2,11 +2,13 @@ namespace goodboyalex\php_components_pack\extensions; +use Closure; use DateMalformedStringException; use DateTime; use DateTimeImmutable; use DateTimeInterface; use Exception; +use goodboyalex\php_components_pack\exceptions\TypeException; use UnitEnum; /** @@ -19,16 +21,38 @@ use UnitEnum; */ 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 Массив свойств типа. + * @throws TypeException Исключение, если объект не является классом. */ - public function ToArray (object $class): array + public static function ToArray (object $class, callable $onClass): array { // Создаю массив результата $result = []; + // Сперва проверяю, что объект является классом + if (!is_object($class)) + // - если нет, то выбрасываю исключение + throw new TypeException($class::class, "Object is not class / Объект не является классом."); + + // Затем записываю имя класса + $result["type_class"] = $class::class; + // Получаю свойства класса $properties = get_object_vars($class); @@ -61,6 +85,15 @@ final class TypeExtension continue; } + // - если значение является классом + if (is_object($value)) { + // -- добавляю в массив через рекурсию + $result[$key] = $onClass($value); + + // -- следующий элемент + continue; + } + // - присваиваю значение $result[$key] = $value; } @@ -73,21 +106,28 @@ final class TypeExtension * Переводит массив в объект. * * @param array $array Массив свойств. - * @param string $className Требуемый класс (внимание: с namespace!). * * @return mixed Объект типа $className. - * @throws Exception Исключение, если объект не создан, или дата не корректного формата или пытается передать null - * не nullable типу. + * @throws TypeException Исключение, если массив не создан через ToArray, объект не создан, дата не корректного + * формата или пытается передать 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(); // Проверяем, что объект создан 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); @@ -109,7 +149,8 @@ final class TypeExtension $instance->$key = new DateTime ('@' . $value); } 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); } catch (DateMalformedStringException) { - // -- создаю дату с нулевым временем, если ошибка - $instance->$key = new DateTimeImmutable(); + throw new TypeException($className . "->{$key}::DateTimeImmutable", + "Date is not correct format / Дата не корректного формата."); } // -- следующий элемент @@ -151,13 +192,23 @@ final class TypeExtension $instance->$key = null; } 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; } + // - если значение является классом + 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; } diff --git a/tests/data/MenuCssClassModel.php b/tests/data/MenuCssClassModel.php new file mode 100644 index 0000000..850b9cc --- /dev/null +++ b/tests/data/MenuCssClassModel.php @@ -0,0 +1,39 @@ +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; + } +} \ No newline at end of file diff --git a/tests/data/MenuItems.php b/tests/data/MenuItems.php new file mode 100644 index 0000000..9309650 --- /dev/null +++ b/tests/data/MenuItems.php @@ -0,0 +1,555 @@ +_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); + } +} \ No newline at end of file diff --git a/tests/data/MenuModel.php b/tests/data/MenuModel.php new file mode 100644 index 0000000..9db8c91 --- /dev/null +++ b/tests/data/MenuModel.php @@ -0,0 +1,139 @@ +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; + } +} \ No newline at end of file diff --git a/tests/extensions/TypeExtensionTest.php b/tests/extensions/TypeExtensionTest.php new file mode 100644 index 0000000..4708b10 --- /dev/null +++ b/tests/extensions/TypeExtensionTest.php @@ -0,0 +1,71 @@ +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'; + } +}