- Fixed: mandatory fields / form validation for invoice template - Added: Duration as calendar title replacer (open: running records) - Fixed: HTML injection in Calendar - Fixed: Doctrine Proxies are not initialized (leads to empty customer/project) - Fixed: tag creation - Fixed: validation errors do not need to be logged in prod - Removed: Customer VCard download, as used library is outdated and not maintained - Added: supporting translations domains in many new places (menu, help_text, page_setup, report, exporter, calendar)
312 lines
6.9 KiB
PHP
312 lines
6.9 KiB
PHP
<?php
|
|
|
|
/*
|
|
* This file is part of the Kimai time-tracking app.
|
|
*
|
|
* For the full copyright and license information, please view the LICENSE
|
|
* file that was distributed with this source code.
|
|
*/
|
|
|
|
namespace App\Utils;
|
|
|
|
use KevinPapst\TablerBundle\Model\MenuItemInterface;
|
|
|
|
final class MenuItemModel implements MenuItemInterface
|
|
{
|
|
private string $identifier;
|
|
private string $label;
|
|
private ?string $route;
|
|
private array $routeArgs;
|
|
private bool $isActive = false;
|
|
/** @var array<MenuItemModel> */
|
|
private array $children = [];
|
|
private ?string $icon;
|
|
private ?MenuItemModel $parent = null;
|
|
private ?string $badge = null;
|
|
private ?string $badgeColor = null;
|
|
private static int $dividerId = 0;
|
|
private bool $divider = false;
|
|
private bool $lastWasDivider = false;
|
|
private bool $expanded = false;
|
|
private string $translationDomain = 'messages';
|
|
|
|
public function __construct(
|
|
string $id,
|
|
string $label,
|
|
?string $route = null,
|
|
array $routeArgs = [],
|
|
?string $icon = null
|
|
) {
|
|
$this->identifier = $id;
|
|
$this->label = $label;
|
|
$this->route = $route;
|
|
$this->routeArgs = $routeArgs;
|
|
$this->icon = $icon;
|
|
}
|
|
|
|
/**
|
|
* @return MenuItemModel[]
|
|
*/
|
|
public function getChildren(): array
|
|
{
|
|
return $this->children;
|
|
}
|
|
|
|
public function getChild(string $id): ?MenuItemModel
|
|
{
|
|
foreach ($this->children as $child) {
|
|
if ($child->getIdentifier() === $id) {
|
|
return $child;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* @param array<MenuItemModel> $children
|
|
*/
|
|
public function setChildren(array $children): void
|
|
{
|
|
$this->children = $children;
|
|
}
|
|
|
|
public function getIcon(): ?string
|
|
{
|
|
return $this->icon;
|
|
}
|
|
|
|
public function setIcon(string $icon): void
|
|
{
|
|
$this->icon = $icon;
|
|
}
|
|
|
|
public function getIdentifier(): string
|
|
{
|
|
return $this->identifier;
|
|
}
|
|
|
|
public function getIsActive(): bool
|
|
{
|
|
return $this->isActive;
|
|
}
|
|
|
|
public function setIsActive(bool $isActive): void
|
|
{
|
|
$this->getParent()?->setIsActive($isActive);
|
|
|
|
$this->isActive = $isActive;
|
|
}
|
|
|
|
public function hasParent(): bool
|
|
{
|
|
return $this->parent !== null;
|
|
}
|
|
|
|
public function getParent(): ?MenuItemModel
|
|
{
|
|
return $this->parent;
|
|
}
|
|
|
|
public function setParent(MenuItemInterface $parent): void
|
|
{
|
|
if (!($parent instanceof MenuItemModel)) {
|
|
throw new \Exception('MenuItemModel::setParent() expects a MenuItemModel');
|
|
}
|
|
$this->parent = $parent;
|
|
}
|
|
|
|
public function getLabel(): string
|
|
{
|
|
return $this->label;
|
|
}
|
|
|
|
public function setLabel(string $label): void
|
|
{
|
|
$this->label = $label;
|
|
}
|
|
|
|
public function getRoute(): ?string
|
|
{
|
|
return $this->route;
|
|
}
|
|
|
|
public function setRoute(?string $route): void
|
|
{
|
|
$this->route = $route;
|
|
}
|
|
|
|
public function getRouteArgs(): array
|
|
{
|
|
return $this->routeArgs;
|
|
}
|
|
|
|
public function setRouteArgs(array $routeArgs): void
|
|
{
|
|
$this->routeArgs = $routeArgs;
|
|
}
|
|
|
|
public function hasChildren(): bool
|
|
{
|
|
if (\count($this->children) < 1) {
|
|
return false;
|
|
}
|
|
|
|
foreach ($this->children as $child) {
|
|
if (!$child->isDivider()) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public function addChild(MenuItemInterface $child): void
|
|
{
|
|
if (!($child instanceof MenuItemModel)) {
|
|
throw new \Exception('MenuItemModel::addChild() expects a MenuItemModel');
|
|
}
|
|
|
|
// first item should not be a divider
|
|
if (!$this->hasChildren() && $child->isDivider()) {
|
|
return;
|
|
}
|
|
|
|
// two divider should not be added as direct siblings
|
|
if ($this->lastWasDivider && $child->isDivider()) {
|
|
return;
|
|
}
|
|
$this->lastWasDivider = $child->isDivider();
|
|
|
|
$child->setParent($this);
|
|
$this->children[] = $child;
|
|
}
|
|
|
|
public function removeChild(MenuItemInterface $child): void
|
|
{
|
|
if (false !== ($key = array_search($child, $this->children))) {
|
|
unset($this->children[$key]);
|
|
}
|
|
}
|
|
|
|
public function findChild(string $identifier): ?MenuItemModel
|
|
{
|
|
return $this->find($identifier, $this);
|
|
}
|
|
|
|
private function find(string $identifier, MenuItemModel $menu): ?MenuItemModel
|
|
{
|
|
if ($menu->getIdentifier() === $identifier) {
|
|
return $this;
|
|
}
|
|
|
|
foreach ($menu->getChildren() as $child) {
|
|
if ($child->getIdentifier() === $identifier) {
|
|
return $child;
|
|
}
|
|
if ($child->hasChildren()) {
|
|
if (($tmp = $this->find($identifier, $child)) !== null) {
|
|
return $tmp;
|
|
}
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public function getActiveChild(): ?MenuItemModel
|
|
{
|
|
foreach ($this->children as $child) {
|
|
if ($child->isActive()) {
|
|
return $child;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public function isActive(): bool
|
|
{
|
|
return $this->isActive;
|
|
}
|
|
|
|
public function setBadge(?string $badge): void
|
|
{
|
|
$this->badge = $badge;
|
|
}
|
|
|
|
public function setBadgeColor(?string $badgeColor): void
|
|
{
|
|
$this->badgeColor = $badgeColor;
|
|
}
|
|
|
|
public function getBadge(): ?string
|
|
{
|
|
return $this->badge;
|
|
}
|
|
|
|
public function getBadgeColor(): ?string
|
|
{
|
|
return $this->badgeColor;
|
|
}
|
|
|
|
private array $childRoutes = [];
|
|
|
|
public function setChildRoutes(array $routes): MenuItemModel
|
|
{
|
|
$this->childRoutes = $routes;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function addChildRoute(string $route): MenuItemModel
|
|
{
|
|
$this->childRoutes[] = $route;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function isChildRoute(string $route): bool
|
|
{
|
|
return \in_array($route, $this->childRoutes);
|
|
}
|
|
|
|
public static function createDivider(): MenuItemModel
|
|
{
|
|
$model = new MenuItemModel('divider_' . self::$dividerId++, '');
|
|
$model->setDivider(true);
|
|
|
|
return $model;
|
|
}
|
|
|
|
public function isDivider(): bool
|
|
{
|
|
return $this->divider;
|
|
}
|
|
|
|
public function setDivider(bool $divider): void
|
|
{
|
|
$this->divider = $divider;
|
|
}
|
|
|
|
public function isExpanded(): bool
|
|
{
|
|
return $this->expanded;
|
|
}
|
|
|
|
public function setExpanded(bool $expanded): void
|
|
{
|
|
$this->expanded = $expanded;
|
|
}
|
|
|
|
public function getTranslationDomain(): string
|
|
{
|
|
return $this->translationDomain;
|
|
}
|
|
|
|
public function setTranslationDomain(string $translationDomain): void
|
|
{
|
|
$this->translationDomain = $translationDomain;
|
|
}
|
|
}
|