// run the Navigation through a hook so users can modify it
CRM_Utils_Hook::navigationMenu($navigations);
+ self::fixNavigationMenu($navigations);
$i18n = CRM_Core_I18n::singleton();
return $navigationString;
}
+ /**
+ * Given a navigation menu, generate navIDs for any items which are
+ * missing them.
+ *
+ * @param array $nodes
+ * Each key is a numeral; each value is a node in
+ * the menu tree (with keys "child" and "attributes").
+ */
+ public static function fixNavigationMenu(&$nodes) {
+ $maxNavID = 1;
+ array_walk_recursive($nodes, function($item, $key) use (&$maxNavID) {
+ if ($key === 'navID') {
+ $maxNavID = max($maxNavID, $item);
+ }
+ });
+ self::_fixNavigationMenu($nodes, $maxNavID, NULL);
+ }
+
+ /**
+ * @param array $nodes
+ * Each key is a numeral; each value is a node in
+ * the menu tree (with keys "child" and "attributes").
+ */
+ private static function _fixNavigationMenu(&$nodes, &$maxNavID, $parentID) {
+ $origKeys = array_keys($nodes);
+ foreach ($origKeys as $origKey) {
+ if (!isset($nodes[$origKey]['attributes']['parentID']) && $parentID !== NULL) {
+ $nodes[$origKey]['attributes']['parentID'] = $parentID;
+ }
+ // If no navID, then assign navID and fix key.
+ if (!isset($nodes[$origKey]['attributes']['navID'])) {
+ $newKey = ++$maxNavID;
+ $nodes[$origKey]['attributes']['navID'] = $newKey;
+ $nodes[$newKey] = $nodes[$origKey];
+ unset($nodes[$origKey]);
+ $origKey = $newKey;
+ }
+ if (isset($nodes[$origKey]['child']) && is_array($nodes[$origKey]['child'])) {
+ self::_fixNavigationMenu($nodes[$origKey]['child'], $maxNavID, $nodes[$origKey]['attributes']['navID']);
+ }
+ }
+ }
+
/**
* Get Menu name.
*
"SELECT count(*) FROM civicrm_navigation WHERE url LIKE 'civicrm/report/instance/%'");
}
+ /**
+ * Run fixNavigationMenu() on a menu which already has navIDs
+ * everywhere. They should be unchanged.
+ */
+ public function testFixNavigationMenu_preserveIDs() {
+ $input[10] = array(
+ 'attributes' => array(
+ 'label' => 'Custom Menu Entry',
+ 'parentID' => NULL,
+ 'navID' => 10,
+ 'active' => 1,
+ ),
+ 'child' => array(
+ '11' => array(
+ 'attributes' => array(
+ 'label' => 'Custom Child Menu',
+ 'parentID' => 10,
+ 'navID' => 11,
+ ),
+ 'child' => NULL,
+ ),
+ ),
+ );
+
+ $output = $input;
+ CRM_Core_BAO_Navigation::fixNavigationMenu($output);
+
+ $this->assertEquals(NULL, $output[10]['attributes']['parentID']);
+ $this->assertEquals(10, $output[10]['attributes']['navID']);
+ $this->assertEquals(10, $output[10]['child'][11]['attributes']['parentID']);
+ $this->assertEquals(11, $output[10]['child'][11]['attributes']['navID']);
+ }
+
+ /**
+ * Run fixNavigationMenu() on a menu which is missing some navIDs. They
+ * should be filled in, and others should be preserved.
+ */
+ public function testFixNavigationMenu_inferIDs() {
+ $input[10] = array(
+ 'attributes' => array(
+ 'label' => 'Custom Menu Entry',
+ 'parentID' => NULL,
+ 'navID' => 10,
+ 'active' => 1,
+ ),
+ 'child' => array(
+ '0' => array(
+ 'attributes' => array(
+ 'label' => 'Custom Child Menu',
+ ),
+ 'child' => NULL,
+ ),
+ '100' => array(
+ 'attributes' => array(
+ 'label' => 'Custom Child Menu 2',
+ 'navID' => 100,
+ ),
+ 'child' => NULL,
+ ),
+ ),
+ );
+
+ $output = $input;
+ CRM_Core_BAO_Navigation::fixNavigationMenu($output);
+
+ $this->assertEquals('Custom Menu Entry', $output[10]['attributes']['label']);
+ $this->assertEquals(NULL, $output[10]['attributes']['parentID']);
+ $this->assertEquals(10, $output[10]['attributes']['navID']);
+
+ $this->assertEquals('Custom Child Menu', $output[10]['child'][101]['attributes']['label']);
+ $this->assertEquals(10, $output[10]['child'][101]['attributes']['parentID']);
+ $this->assertEquals(101, $output[10]['child'][101]['attributes']['navID']);
+
+ $this->assertEquals('Custom Child Menu 2', $output[10]['child'][100]['attributes']['label']);
+ $this->assertEquals(10, $output[10]['child'][100]['attributes']['parentID']);
+ $this->assertEquals(100, $output[10]['child'][100]['attributes']['navID']);
+ }
+
+ public function testFixNavigationMenu_inferIDs_deep() {
+ $input[10] = array(
+ 'attributes' => array(
+ 'label' => 'Custom Menu Entry',
+ 'parentID' => NULL,
+ 'navID' => 10,
+ 'active' => 1,
+ ),
+ 'child' => array(
+ '0' => array(
+ 'attributes' => array(
+ 'label' => 'Custom Child Menu',
+ ),
+ 'child' => array(
+ '100' => array(
+ 'attributes' => array(
+ 'label' => 'Custom Child Menu 2',
+ 'navID' => 100,
+ ),
+ 'child' => NULL,
+ ),
+ ),
+ ),
+ ),
+ );
+
+ $output = $input;
+ CRM_Core_BAO_Navigation::fixNavigationMenu($output);
+
+ $this->assertEquals('Custom Menu Entry', $output[10]['attributes']['label']);
+ $this->assertEquals(NULL, $output[10]['attributes']['parentID']);
+ $this->assertEquals(10, $output[10]['attributes']['navID']);
+
+ $this->assertEquals('Custom Child Menu', $output[10]['child'][101]['attributes']['label']);
+ $this->assertEquals(10, $output[10]['child'][101]['attributes']['parentID']);
+ $this->assertEquals(101, $output[10]['child'][101]['attributes']['navID']);
+
+ $this->assertEquals('Custom Child Menu 2', $output[10]['child'][101]['child'][100]['attributes']['label']);
+ $this->assertEquals(101, $output[10]['child'][101]['child'][100]['attributes']['parentID']);
+ $this->assertEquals(100, $output[10]['child'][101]['child'][100]['attributes']['navID']);
+ }
+
}