Skip to content

Instantly share code, notes, and snippets.

@agh1
Last active April 27, 2017 15:42
Show Gist options
  • Save agh1/5c85e21e3fc274ef5dd798dd7a1ef6e5 to your computer and use it in GitHub Desktop.
Save agh1/5c85e21e3fc274ef5dd798dd7a1ef6e5 to your computer and use it in GitHub Desktop.
A class to prepare the menu array for an extension to add additional items
<?php
/**
* A class to prepare the menu array for an extension to add additional items.
*
* Usage:
* function yourextension_civicrm_navigationMenu(&$menu) {
* $adder = new CRM_Utils_NavAdd($menu);
* $attributes = array(
* 'label' => ts('One thing'),
* 'name' => 'One thing',
* 'url' => 'civicrm/onething',
* 'permission' => 'access CiviCRM, administer CiviCRM',
* 'operator' => 'AND',
* 'separator' => 1,
* 'active' => 1,
* );
* $adder->addItem($attributes, array('Administer'));
* $attributes = array(
* 'label' => ts('Other thing'),
* 'name' => 'Other thing',
* 'url' => 'civicrm/otherthing',
* 'permission' => 'access CiviCRM',
* 'separator' => 1,
* 'active' => 1,
* );
* $adder->addItem($attributes, array('Contributions', 'Pledges'));
* $menu = $adder->getMenu();
* }
*/
class CRM_Utils_NavAdd {
/**
* The menu array to fill.
*
* @param array $menu
*/
protected $menu;
/**
* The current maximum ID of a menu item.
*
* @param int $maxId
*/
protected $maxId = 0;
/**
* Prepare the adder.
*
* @param array $menu
* The current menu array from hook_civicrm_navigationMenu.
*/
public function __construct($menu) {
$this->menu = $menu;
$this->scanMaxNavId($menu);
}
/**
* Add an item to the menu
*
* @param array $itemAttr
* The attributes of the item to add, an array with the following keys:
* - `label`,
* - `name`,
* - `url`,
* - `permission`,
* - `operator`,
* - `separator`,
* - `active`
* @param array $idealTree
* A list of preferred ancestors for the item in the menu.
*/
public function addItem($attributes, $idealTree) {
// Walk down the menu to see if we can find them where we expect them.
$walkMenu = $this->menu;
$branches = array();
reset($idealTree);
foreach ($idealTree as $limb) {
foreach ($walkMenu as $id => $item) {
if ($item['attributes']['name'] == $limb) {
$walkMenu = CRM_Utils_Array::value('child', $item, array());
$branches[] = $id;
$branches[] = 'child';
continue 2;
}
}
// If the expected parent isn't at this level of the menu, we'll just drop
// it here.
break;
}
if (!empty($id)) {
$attributes['parentID'] = $id;
}
// Need to put together exactly where the item should be added;
$treeMenu = &$this->menu;
foreach ($branches as $branch) {
$treeMenu = &$treeMenu[$branch];
}
// Our ID is the next one after the current maximum.
$this->maxId++;
$attributes['navID'] = $this->maxId;
$treeMenu[$this->maxId] = array('attributes' => $attributes);
}
/**
* Getter for the menu that has been updated.
*
* @return array
*/
public function getMenu() {
return $this->menu;
}
/**
* Scans recursively for the highest ID in the navigation.
*
* Better than searching the database because other extensions may have added
* items in the meantime.
*
* @param array $menu
* The menu to scan.
*/
protected function scanMaxNavId($menu) {
foreach ($menu as $id => $item) {
$this->maxId = max($id, $this->maxId);
if (!empty($item['child'])) {
$this->scanMaxNavId($item['child']);
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment