Instantly share code, notes, and snippets.
Last active
April 13, 2017 12:28
-
Star
(2)
2
You must be signed in to star a gist -
Fork
(1)
1
You must be signed in to fork a gist
-
Save bwaidelich/f3a3d6373acb558a7aa6 to your computer and use it in GitHub Desktop.
A DTO that can be used to create simple menus in a TYPO3 Flow application
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<ul class="nav"> | |
<f:for each="{menu.menuItems}" as="menuItem"> | |
<f:render section="menuItem" arguments="{menuItem: menuItem}" /> | |
</f:for> | |
</ul> | |
<f:section name="menuItem"> | |
<f:if condition="{menuItem.header}"> | |
<f:then> | |
<li class="nav-header">{menuItem.label}</li> | |
</f:then> | |
<f:else> | |
<f:if condition="{menuItem.separator}"> | |
<f:then> | |
<li class="divider"></li> | |
</f:then> | |
<f:else> | |
<li class="{f:if(condition: menuItem.active, then: 'active')}"> | |
<a href="{f:uri.action(action: menuItem.targetActionName, controller: menuItem.targetControllerName, package: menuItem.targetPackageKey)}"> | |
<f:if condition="{menuItem.icon}"> | |
<i class="fa fa-fw fa-{menuItem.icon}"></i> | |
</f:if> | |
{menuItem.label} | |
<f:if condition="{menuItem.badge}"> | |
<span class="pull-right badge badge-info badge-hidden">{menuItem.badge}</span> | |
</f:if> | |
</a> | |
<f:if condition="{menuItem.subMenuItems}"> | |
<ul> | |
<f:for each="{menuItem.subMenuItems}" as="subMenuItem"> | |
<f:render section="menuItem" arguments="{menuItem: subMenuItem}" /> | |
</f:for> | |
</ul> | |
</f:if> | |
</li> | |
</f:else> | |
</f:if> | |
</f:else> | |
</f:if> | |
</f:section> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Acme\SomePackage\Domain\Dto; | |
use TYPO3\Flow\Annotations as Flow; | |
use TYPO3\Flow\Mvc\ActionRequest; | |
/** | |
* Simple Menu that can be rendered with Fluid | |
*/ | |
class Menu { | |
/** | |
* @var ActionRequest | |
*/ | |
protected $actionRequest; | |
/** | |
* @var MenuItem[] | |
*/ | |
protected $menuItems = []; | |
/** | |
* @param ActionRequest $actionRequest | |
* @param array $configuration in the format ['label' => 'A', 'targetPackageKey' => 'Some.Package', ..., 'subMenuItems' => ['label' => A.1', ...], ...] | |
*/ | |
public function __construct(ActionRequest $actionRequest, array $configuration = NULL) { | |
$this->actionRequest = $actionRequest; | |
if ($configuration !== NULL && isset($configuration['menuItems'])) { | |
$this->menuItems = $this->createMenuItems($configuration['menuItems']); | |
$this->setActiveMenuItems(); | |
} | |
} | |
/** | |
* Recursively creates menu and sub menu items corresponding to the given $configuration | |
* | |
* @param array $menuItemsConfiguration | |
* @return MenuItem[] | |
*/ | |
protected function createMenuItems(array $menuItemsConfiguration) { | |
$menuItems = []; | |
foreach ($menuItemsConfiguration as $menuItemConfiguration) { | |
$label = isset($menuItemConfiguration['label']) ? $menuItemConfiguration['label'] : NULL; | |
$targetPackageKey = isset($menuItemConfiguration['package']) ? $menuItemConfiguration['package'] : NULL; | |
$targetControllerName = isset($menuItemConfiguration['controller']) ? $menuItemConfiguration['controller'] : NULL; | |
$targetActionName = isset($menuItemConfiguration['action']) ? $menuItemConfiguration['action'] : 'index'; | |
$targetActionArguments = isset($menuItemConfiguration['arguments']) ? $menuItemConfiguration['arguments'] : []; | |
$icon = isset($menuItemConfiguration['icon']) ? $menuItemConfiguration['icon'] : NULL; | |
$badge = isset($menuItemConfiguration['badge']) ? $menuItemConfiguration['badge'] : NULL; | |
$menuItem = new MenuItem($label, $targetPackageKey, $targetControllerName, $targetActionName, $targetActionArguments, $icon, $badge); | |
if (isset($menuItemConfiguration['menuItems'])) { | |
$menuItem->setSubMenuItems($this->createMenuItems($menuItemConfiguration['menuItems'])); | |
} | |
$menuItems[] = $menuItem; | |
} | |
return $menuItems; | |
} | |
/** | |
* @return MenuItem[] | |
*/ | |
public function getMenuItems() { | |
return $this->menuItems; | |
} | |
/** | |
* Adds a menu item to the end of this menu | |
* | |
* @param MenuItem $menuItem | |
* @return Menu the current instance to enable method chaining | |
*/ | |
public function addMenuItem(MenuItem $menuItem) { | |
$this->menuItems[] = $menuItem; | |
return $this; | |
} | |
/** | |
* Recursively activates all menu items that match the given actionRequest | |
* | |
* @return void | |
*/ | |
public function setActiveMenuItems() { | |
foreach ($this->menuItems as $menuItem) { | |
$menuItem->activateForRequest($this->actionRequest); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Acme\SomePackage\Domain\Dto; | |
use TYPO3\Flow\Annotations as Flow; | |
use TYPO3\Flow\Persistence\PersistenceManagerInterface; | |
use TYPO3\Flow\Security\Account; | |
use TYPO3\Flow\Security\Context; | |
use TYPO3\Flow\Utility\Arrays; | |
use TYPO3\Flow\Mvc\ActionRequest; | |
/** | |
* Simple Menu that can be rendered with Fluid | |
*/ | |
class MenuItem { | |
/** | |
* @Flow\Inject | |
* @var PersistenceManagerInterface | |
*/ | |
protected $persistenceManager; | |
/** | |
* @var string | |
*/ | |
protected $label = ''; | |
/** | |
* @var boolean | |
*/ | |
protected $active = FALSE; | |
/** | |
* @var string | |
*/ | |
protected $targetPackageKey; | |
/** | |
* @var string | |
*/ | |
protected $targetControllerName; | |
/** | |
* @var string | |
*/ | |
protected $targetActionName; | |
/** | |
* @var array | |
*/ | |
protected $targetActionArguments = []; | |
/** | |
* @var string | |
*/ | |
protected $icon; | |
/** | |
* @var string | |
*/ | |
protected $badge; | |
/** | |
* @var MenuItem[] | |
*/ | |
protected $subMenuItems = []; | |
/** | |
* @param string $label label of the menu item - if omitted, the resulting menu item is considered a separator | |
* @param string $targetPackageKey key of the target package - if omitted, the resulting menu item is considered a menu header | |
* @param string $targetControllerName name of the target controller | |
* @param string $targetActionName the target action name | |
* @param array $targetActionArguments the target action arguments | |
* @param string $icon an optional icon identifier (to be used from the fluid template) | |
* @param string $badge an optional badge text (to be used from the fluid template) | |
*/ | |
public function __construct($label, $targetPackageKey = NULL, $targetControllerName = NULL, $targetActionName = NULL, array $targetActionArguments = [], $icon = NULL, $badge = NULL) { | |
$this->label = $label; | |
$this->targetPackageKey = $targetPackageKey; | |
$this->targetControllerName = $targetControllerName; | |
$this->targetActionName = $targetActionName; | |
$this->targetActionArguments = $targetActionArguments; | |
$this->icon = $icon; | |
$this->badge = $badge; | |
} | |
/** | |
* Sets the menu item (and it's sub items) active if it matches the given $actionRequest: | |
* | |
* If the menu item has sub menu items, matching package and controller is enough to mark the item active. | |
* Otherwise the action name has to match as well (unless that is not defined). | |
* | |
* @param ActionRequest $actionRequest | |
* @return void | |
*/ | |
public function activateForRequest(ActionRequest $actionRequest) { | |
if ($this->isHeader() || $this->isSeparator()) { | |
return; | |
} | |
if (!$this->matchesRequest($actionRequest)) { | |
return; | |
} | |
$this->active = TRUE; | |
foreach ($this->subMenuItems as $subMenuItem) { | |
$subMenuItem->activateForRequest($actionRequest); | |
} | |
} | |
/** | |
* returns TRUE if the given $request points to the controller/action specified in this menu item | |
* | |
* @param ActionRequest $actionRequest | |
* @return boolean TRUE if this menuItem is active for the given $request, otherwise FALSE | |
*/ | |
protected function matchesRequest(ActionRequest $actionRequest) { | |
if ($this->hasSubMenuItems() || $this->targetActionName === NULL) { | |
return $this->targetPackageKey === $actionRequest->getControllerPackageKey() && $this->targetControllerName === $actionRequest->getControllerName(); | |
} | |
if ($this->targetPackageKey !== $actionRequest->getControllerPackageKey()) { | |
return FALSE; | |
} | |
if ($this->targetControllerName !== $actionRequest->getControllerName()) { | |
return FALSE; | |
} | |
// for items with sub items a matching controller is enough to turn it active | |
if ($this->hasSubMenuItems() || $this->targetActionName === NULL) { | |
return TRUE; | |
} | |
if ($this->targetActionName !== $actionRequest->getControllerActionName()) { | |
return FALSE; | |
} | |
$targetActionArguments = $this->targetActionArguments; | |
$targetActionArguments = $this->persistenceManager->convertObjectsToIdentityArrays($targetActionArguments); | |
Arrays::sortKeysRecursively($targetActionArguments); | |
$requestArguments = $actionRequest->getArguments(); | |
Arrays::sortKeysRecursively($requestArguments); | |
return ($targetActionArguments === $requestArguments); | |
} | |
/** | |
* @return boolean TRUE if this menu item is just a header (i.e. no target package set) | |
*/ | |
public function isHeader() { | |
return $this->targetPackageKey === NULL && $this->label !== ''; | |
} | |
/** | |
* @return boolean TRUE if this menu item is just a separator (i.e. no label set) | |
*/ | |
public function isSeparator() { | |
return $this->label === ''; | |
} | |
/** | |
* @return MenuItem[] | |
*/ | |
public function getSubMenuItems() { | |
return $this->subMenuItems; | |
} | |
/** | |
* @param MenuItem[] $subMenuItems | |
* @return void | |
*/ | |
public function setSubMenuItems(array $subMenuItems) { | |
$this->subMenuItems = $subMenuItems; | |
} | |
/** | |
* @param MenuItem $subMenuItem | |
* @return MenuItem the current instance to enable method chaining | |
*/ | |
public function addSubMenuItem(MenuItem $subMenuItem) { | |
$this->subMenuItems[] = $subMenuItem; | |
return $this; | |
} | |
/** | |
* @return boolean | |
*/ | |
public function hasSubMenuItems() { | |
return $this->subMenuItems !== []; | |
} | |
/** | |
* @return string | |
*/ | |
public function getTargetPackageKey() { | |
return $this->targetPackageKey; | |
} | |
/** | |
* @return string | |
*/ | |
public function getTargetControllerName() { | |
return $this->targetControllerName; | |
} | |
/** | |
* @return string | |
*/ | |
public function getTargetActionName() { | |
return $this->targetActionName; | |
} | |
/** | |
* @return array | |
*/ | |
public function getTargetActionArguments() { | |
return $this->targetActionArguments; | |
} | |
/** | |
* @return boolean | |
*/ | |
public function isActive() { | |
return $this->active; | |
} | |
/** | |
* @return string | |
*/ | |
public function getLabel() { | |
return $this->label; | |
} | |
/** | |
* @return string | |
*/ | |
public function getBadge() { | |
return $this->badge; | |
} | |
/** | |
* @return string | |
*/ | |
public function getIcon() { | |
return $this->icon; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Usage:
example settings:
... in your controller:
..and finally in your fluid template/layout: