Modify menu structure to objects (#4929)

* Modify menu structure to objects
This commit is contained in:
Klaas Poortinga 2020-03-01 08:10:37 +01:00 committed by GitHub
parent 56b2864ef5
commit bf8ab3612e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 309 additions and 32 deletions

View File

@ -0,0 +1,125 @@
<?php namespace Backend\Classes;
use October\Rain\Exception\SystemException;
/**
* Class MainMenuItem
*
* @package Backend\Classes
*/
class MainMenuItem
{
/**
* @var string
*/
public $code;
/**
* @var string
*/
public $owner;
/**
* @var string
*/
public $label;
/**
* @var null|string
*/
public $icon;
/**
* @var null|string
*/
public $iconSvg;
/**
* @var mixed
*/
public $counter;
/**
* @var null|string
*/
public $counterLabel;
/**
* @var string
*/
public $url;
/**
* @var array
*/
public $permissions = [];
/**
* @var int
*/
public $order = 500;
/**
* @var SideMenuItem[]
*/
public $sideMenu = [];
/**
* @param string $permission
* @param array $definition
*/
public function addPermission(string $permission, array $definition)
{
$this->permissions[$permission] = $definition;
}
/**
* @param SideMenuItem $sideMenu
*/
public function addSideMenuItem(SideMenuItem $sideMenu)
{
$this->sideMenu[$sideMenu->code] = $sideMenu;
}
/**
* @param string $code
* @return SideMenuItem
* @throws SystemException
*/
public function getSideMenuItem(string $code): SideMenuItem
{
if (!array_key_exists($code, $this->sideMenu)) {
throw new SystemException('No sidenavigation item available with code ' . $code);
}
return $this->sideMenu[$code];
}
/**
* @param string $code
*/
public function removeSideMenuItem(string $code)
{
unset($this->sideMenu[$code]);
}
/**
* @param array $data
* @return static
*/
public static function createFromArray(array $data)
{
$instance = new static();
$instance->code = $data['code'];
$instance->owner = $data['owner'];
$instance->label = $data['label'];
$instance->url = $data['url'];
$instance->icon = $data['icon'] ?? null;
$instance->iconSvg = $data['iconSvg'] ?? null;
$instance->counter = $data['counter'] ?? null;
$instance->counterLabel = $data['counterLabel'] ?? null;
$instance->permissions = $data['permissions'] ?? $instance->permissions;
$instance->order = $data['order'] ?? $instance->order;
return $instance;
}
}

View File

@ -24,7 +24,7 @@ class NavigationManager
protected $callbacks = []; protected $callbacks = [];
/** /**
* @var array List of registered items. * @var MainMenuItem[] List of registered items.
*/ */
protected $items; protected $items;
@ -61,7 +61,7 @@ class NavigationManager
]; ];
/** /**
* @var System\Classes\PluginManager * @var PluginManager
*/ */
protected $pluginManager; protected $pluginManager;
@ -76,6 +76,7 @@ class NavigationManager
/** /**
* Loads the menu items from modules and plugins * Loads the menu items from modules and plugins
* @return void * @return void
* @throws SystemException
*/ */
protected function loadItems() protected function loadItems()
{ {
@ -118,7 +119,7 @@ class NavigationManager
/* /*
* Sort menu items * Sort menu items
*/ */
uasort($this->items, function ($a, $b) { uasort($this->items, static function ($a, $b) {
return $a->order - $b->order; return $a->order - $b->order;
}); });
@ -147,7 +148,7 @@ class NavigationManager
/* /*
* Sort side menu items * Sort side menu items
*/ */
uasort($item->sideMenu, function ($a, $b) { uasort($item->sideMenu, static function ($a, $b) {
return $a->order - $b->order; return $a->order - $b->order;
}); });
@ -202,6 +203,7 @@ class NavigationManager
* - counterLabel - an optional string value to describe the numeric reference in counter. * - counterLabel - an optional string value to describe the numeric reference in counter.
* @param string $owner Specifies the menu items owner plugin or module in the format Author.Plugin. * @param string $owner Specifies the menu items owner plugin or module in the format Author.Plugin.
* @param array $definitions An array of the menu item definitions. * @param array $definitions An array of the menu item definitions.
* @throws SystemException
*/ */
public function registerMenuItems($owner, array $definitions) public function registerMenuItems($owner, array $definitions)
{ {
@ -222,9 +224,9 @@ class NavigationManager
$errorMessage = 'Invalid menu item detected in ' . $owner . '. Contact the plugin author to fix (' . $validator->errors()->first() . ')'; $errorMessage = 'Invalid menu item detected in ' . $owner . '. Contact the plugin author to fix (' . $validator->errors()->first() . ')';
if (Config::get('app.debug', false)) { if (Config::get('app.debug', false)) {
throw new SystemException($errorMessage); throw new SystemException($errorMessage);
} else {
Log::error($errorMessage);
} }
Log::error($errorMessage);
} }
$this->addMainMenuItems($owner, $definitions); $this->addMainMenuItems($owner, $definitions);
@ -246,7 +248,7 @@ class NavigationManager
* Dynamically add a single main menu item * Dynamically add a single main menu item
* @param string $owner * @param string $owner
* @param string $code * @param string $code
* @param array $definitions * @param array $definition
*/ */
public function addMainMenuItem($owner, $code, array $definition) public function addMainMenuItem($owner, $code, array $definition)
{ {
@ -256,20 +258,39 @@ class NavigationManager
$definition = array_merge((array) $this->items[$itemKey], $definition); $definition = array_merge((array) $this->items[$itemKey], $definition);
} }
$item = (object) array_merge(self::$mainItemDefaults, array_merge($definition, [ $item = array_merge($definition, [
'code' => $code, 'code' => $code,
'owner' => $owner 'owner' => $owner
])); ]);
$this->items[$itemKey] = $item; $this->items[$itemKey] = MainMenuItem::createFromArray($item);
if ($item->sideMenu) { if (array_key_exists('sideMenu', $item)) {
$this->addSideMenuItems($owner, $code, $item->sideMenu); $this->addSideMenuItems($owner, $code, $item['sideMenu']);
} }
} }
/**
* @param string $owner
* @param string $code
* @return MainMenuItem
* @throws SystemException
*/
public function getMainMenuItem(string $owner, string $code): MainMenuItem
{
$itemKey = $this->makeItemKey($owner, $code);
if (!array_key_exists($itemKey, $this->items)) {
throw new SystemException('No main menu item found with key ' . $itemKey);
}
return $this->items[$itemKey];
}
/** /**
* Removes a single main menu item * Removes a single main menu item
* @param $owner
* @param $code
*/ */
public function removeMainMenuItem($owner, $code) public function removeMainMenuItem($owner, $code)
{ {
@ -295,9 +316,10 @@ class NavigationManager
* @param string $owner * @param string $owner
* @param string $code * @param string $code
* @param string $sideCode * @param string $sideCode
* @param array $definitions * @param array $definition
* @return bool
*/ */
public function addSideMenuItem($owner, $code, $sideCode, array $definition) public function addSideMenuItem($owner, $code, $sideCode, array $definition): bool
{ {
$itemKey = $this->makeItemKey($owner, $code); $itemKey = $this->makeItemKey($owner, $code);
@ -316,15 +338,20 @@ class NavigationManager
$definition = array_merge((array) $mainItem->sideMenu[$sideCode], $definition); $definition = array_merge((array) $mainItem->sideMenu[$sideCode], $definition);
} }
$item = (object) array_merge(self::$sideItemDefaults, $definition); $item = SideMenuItem::createFromArray($definition);
$this->items[$itemKey]->sideMenu[$sideCode] = $item; $this->items[$itemKey]->addSideMenuItem($item);
return true;
} }
/** /**
* Removes a single main menu item * Removes a single main menu item
* @param string $owner
* @param string $code
* @param string $sideCode
* @return bool
*/ */
public function removeSideMenuItem($owner, $code, $sideCode) public function removeSideMenuItem($owner, $code, $sideCode): bool
{ {
$itemKey = $this->makeItemKey($owner, $code); $itemKey = $this->makeItemKey($owner, $code);
if (!isset($this->items[$itemKey])) { if (!isset($this->items[$itemKey])) {
@ -332,12 +359,14 @@ class NavigationManager
} }
$mainItem = $this->items[$itemKey]; $mainItem = $this->items[$itemKey];
unset($mainItem->sideMenu[$sideCode]); $mainItem->removeSideMenuItem($sideCode);
return true;
} }
/** /**
* Returns a list of the main menu items. * Returns a list of the main menu items.
* @return array * @return array
* @throws SystemException
*/ */
public function listMainMenuItems() public function listMainMenuItems()
{ {
@ -372,8 +401,12 @@ class NavigationManager
/** /**
* Returns a list of side menu items for the currently active main menu item. * Returns a list of side menu items for the currently active main menu item.
* The currently active main menu item is set with the setContext methods. * The currently active main menu item is set with the setContext methods.
* @param null $owner
* @param null $code
* @return SideMenuItem[]
* @throws SystemException
*/ */
public function listSideMenuItems($owner = null, $code = null) public function listSideMenuItems($owner = null, $code = null): array
{ {
$activeItem = null; $activeItem = null;
@ -467,17 +500,18 @@ class NavigationManager
/** /**
* Determines if a main menu item is active. * Determines if a main menu item is active.
* @param mixed $item Specifies the item object. * @param MainMenuItem $item Specifies the item object.
* @return boolean Returns true if the menu item is active. * @return boolean Returns true if the menu item is active.
*/ */
public function isMainMenuItemActive($item) public function isMainMenuItemActive($item): bool
{ {
return $this->contextOwner == $item->owner && $this->contextMainMenuItemCode == $item->code; return $this->contextOwner === $item->owner && $this->contextMainMenuItemCode === $item->code;
} }
/** /**
* Returns the currently active main menu item * Returns the currently active main menu item
* @param mixed $item Returns the item object or null. * @return null|MainMenuItem $item Returns the item object or null.
* @throws SystemException
*/ */
public function getActiveMainMenuItem() public function getActiveMainMenuItem()
{ {
@ -492,17 +526,17 @@ class NavigationManager
/** /**
* Determines if a side menu item is active. * Determines if a side menu item is active.
* @param mixed $item Specifies the item object. * @param SideMenuItem $item Specifies the item object.
* @return boolean Returns true if the side item is active. * @return boolean Returns true if the side item is active.
*/ */
public function isSideMenuItemActive($item) public function isSideMenuItemActive($item): bool
{ {
if ($this->contextSideMenuItemCode === true) { if ($this->contextSideMenuItemCode === true) {
$this->contextSideMenuItemCode = null; $this->contextSideMenuItemCode = null;
return true; return true;
} }
return $this->contextOwner == $item->owner && $this->contextSideMenuItemCode == $item->code; return $this->contextOwner === $item->owner && $this->contextSideMenuItemCode === $item->code;
} }
/** /**
@ -534,17 +568,17 @@ class NavigationManager
/** /**
* Removes menu items from an array if the supplied user lacks permission. * Removes menu items from an array if the supplied user lacks permission.
* @param User $user A user object * @param \Backend\Models\User $user A user object
* @param array $items A collection of menu items * @param MainMenuItem[]|SideMenuItem[] $items A collection of menu items
* @return array The filtered menu items * @return array The filtered menu items
*/ */
protected function filterItemPermissions($user, array $items) protected function filterItemPermissions($user, array $items): array
{ {
if (!$user) { if (!$user) {
return $items; return $items;
} }
$items = array_filter($items, function ($item) use ($user) { $items = array_filter($items, static function ($item) use ($user) {
if (!$item->permissions || !count($item->permissions)) { if (!$item->permissions || !count($item->permissions)) {
return true; return true;
} }
@ -557,10 +591,11 @@ class NavigationManager
/** /**
* Internal method to make a unique key for an item. * Internal method to make a unique key for an item.
* @param object $item * @param string $owner
* @param string $code
* @return string * @return string
*/ */
protected function makeItemKey($owner, $code) protected function makeItemKey($owner, $code): string
{ {
return strtoupper($owner).'.'.strtoupper($code); return strtoupper($owner).'.'.strtoupper($code);
} }

View File

@ -0,0 +1,117 @@
<?php namespace Backend\Classes;
/**
* Class SideMenuItem
*
* @package Backend\Classes
*/
class SideMenuItem
{
/**
* @var string
*/
public $code;
/**
* @var string
*/
public $owner;
/**
* @var string
*/
public $label;
/**
* @var null|string
*/
public $icon;
/**
* @var null|string
*/
public $iconSvg;
/**
* @var string
*/
public $url;
/**
* @var null|int|callable
*/
public $counter;
/**
* @var null|string
*/
public $counterLabel;
/**
* @var int
*/
public $order = -1;
/**
* @var array
*/
public $attributes = [];
/**
* @var array
*/
public $permissions = [];
/**
* @param null|string|int $attribute
* @param null|string|array $value
*/
public function addAttribute($attribute, $value)
{
$this->attributes[$attribute] = $value;
}
public function removeAttribute($attribute)
{
unset($this->attributes[$attribute]);
}
/**
* @param string $permission
* @param array $definition
*/
public function addPermission(string $permission, array $definition)
{
$this->permissions[$permission] = $definition;
}
/**
* @param string $permission
* @return void
*/
public function removePermission(string $permission)
{
unset($this->permissions[$permission]);
}
/**
* @param array $data
* @return static
*/
public static function createFromArray(array $data): self
{
$instance = new static();
$instance->code = $data['code'];
$instance->owner = $data['owner'];
$instance->label = $data['label'];
$instance->url = $data['url'];
$instance->icon = $data['icon'] ?? null;
$instance->iconSvg = $data['iconSvg'] ?? null;
$instance->counter = $data['counter'] ?? null;
$instance->counterLabel = $data['counterLabel'] ?? null;
$instance->attributes = $data['attributes'] ?? $instance->attributes;
$instance->permissions = $data['permissions'] ?? $instance->permissions;
$instance->order = $data['order'] ?? $instance->order;
return $instance;
}
}