From f9623ac265cfc6db398220f5c5150f8981e595c9 Mon Sep 17 00:00:00 2001 From: Tim Brandin Date: Wed, 23 May 2012 16:54:12 +0200 Subject: [PATCH] #issue solved! --- features.api.php | 2 +- includes/features.menu.inc | 130 ++++++++++++++++++++++++++++++++++++++------ 2 files changed, 113 insertions(+), 19 deletions(-) diff --git a/features.api.php b/features.api.php index 572b5a7..9fe858b 100644 --- a/features.api.php +++ b/features.api.php @@ -118,7 +118,7 @@ function hook_features_export($data, &$export, $module_name) { } /** - * Component hook. The hook should be implemented using the name ot the + * Component hook. The hook should be implemented using the name of the * component, not the module, eg. [component]_features_export() rather than * [module]_features_export(). * diff --git a/includes/features.menu.inc b/includes/features.menu.inc index 3060aa0..0a11bf2 100644 --- a/includes/features.menu.inc +++ b/includes/features.menu.inc @@ -132,6 +132,7 @@ function menu_custom_features_rebuild($module) { */ function menu_links_features_export_options() { global $menu_admin; + // Need to set this to TRUE in order to get menu links that the // current user may not have access to (i.e. user/login) $menu_admin = TRUE; @@ -141,7 +142,7 @@ function menu_links_features_export_options() { list($menu_name, $mlid) = explode(':', $key, 2); if ($mlid != 0) { $link = menu_link_load($mlid); - $identifier = menu_links_features_identifier($link); + $identifier = menu_links_features_identifier($link, true); $options[$identifier] = "{$menu_name}: {$name}"; } } @@ -152,14 +153,36 @@ function menu_links_features_export_options() { /** * Callback for generating the menu link exportable identifier. */ -function menu_links_features_identifier($link) { - return isset($link['menu_name'], $link['link_path']) ? "{$link['menu_name']}:{$link['link_path']}" : FALSE; +function menu_links_features_identifier($link, $old = false) { + + // add some uniqueness to these identifiers, allowing multiple links with the same path, but different titles. + $cleantitle = clean_title(isset($link['title']) ? $link['title'] : $link['link_title']); + + // The old identifier is requested. + if ($old) { + // if identifier already exists + if (isset($link['options']['identifier'])) { + return $link['options']['identifier']; + } + // providing backward compatibility and allowing/enabling multiple links with same paths + else { + $identifier = isset($link['menu_name'], $link['link_path']) ? "{$link['menu_name']}:{$link['link_path']}" : FALSE; + // Checking if there are multiples of this identifier + if (features_menu_link_load($identifier) !== FALSE) { + // this is where we return the upgrade posibility for links. + return $identifier; + } + } + } + + return isset($link['menu_name'], $link['link_path']) ? "{$link['menu_name']}_{$cleantitle}:{$link['link_path']}" : FALSE; } /** * Implements hook_features_export(). */ function menu_links_features_export($data, &$export, $module_name = '') { + // Default hooks are provided by the feature module so we need to add // it as a dependency. $export['dependencies']['features'] = 'features'; @@ -168,15 +191,21 @@ function menu_links_features_export($data, &$export, $module_name = '') { // Collect a link to module map $pipe = array(); $map = features_get_default_map('menu_links', 'menu_links_features_identifier'); - foreach ($data as $identifier) { + + foreach ($data as $key => $identifier) { + if ($link = features_menu_link_load($identifier)) { // If this link is provided by a different module, add it as a dependency. + + $new_identifier = menu_links_features_identifier($link, empty($export)); + if (isset($map[$identifier]) && $map[$identifier] != $module_name) { $export['dependencies'][$map[$identifier]] = $map[$identifier]; } else { - $export['features']['menu_links'][$identifier] = $identifier; + $export['features']['menu_links'][$new_identifier] = $new_identifier; } + // For now, exclude a variety of common menus from automatic export. // They may still be explicitly included in a Feature if the builder // chooses to do so. @@ -191,23 +220,36 @@ function menu_links_features_export($data, &$export, $module_name = '') { /** * Implements hook_features_export_render() */ -function menu_links_features_export_render($module, $data) { +function menu_links_features_export_render($module, $data, $export = NULL) { $code = array(); $code[] = ' $menu_links = array();'; $code[] = ''; - + $translatables = array(); foreach ($data as $identifier) { + if ($link = features_menu_link_load($identifier)) { + + $new_identifier = menu_links_features_identifier($link, empty($export)); + + $link['options']['identifier'] = $new_identifier; + // Replace plid with a parent path. if (!empty($link['plid']) && $parent = menu_link_load($link['plid'])) { - $link['parent_path'] = $parent['link_path']; + $cleantitle = clean_title($parent['title']); + $link['parent_identifier'] = "{$parent['menu_name']}_{$cleantitle}:{$parent['link_path']}"; } + + if (isset($export)) { + // identifiers are renewed, => that means we need to update them in the db + menu_link_save($temp = $link); + } + unset($link['plid']); unset($link['mlid']); - $code[] = " // Exported menu link: {$identifier}"; - $code[] = " \$menu_links['{$identifier}'] = ". features_var_export($link, ' ') .";"; + $code[] = " // Exported menu link: {$new_identifier}"; + $code[] = " \$menu_links['{$new_identifier}'] = ". features_var_export($link, ' ') .";"; $translatables[] = $link['link_title']; } } @@ -218,6 +260,7 @@ function menu_links_features_export_render($module, $data) { $code[] = ''; $code[] = ' return $menu_links;'; $code = implode("\n", $code); + return array('menu_default_menu_links' => $code); } @@ -232,6 +275,7 @@ function menu_links_features_revert($module) { * Implements hook_features_export_rebuild(). */ function menu_links_features_rebuild($module) { + if ($menu_links = features_get_default('menu_links', $module)) { menu_links_features_rebuild_ordered($menu_links); } @@ -243,6 +287,7 @@ function menu_links_features_rebuild($module) { function menu_links_features_rebuild_ordered($menu_links, $reset = FALSE) { static $ordered; static $all_links; + if (!isset($ordered) || $reset) { $ordered = array(); $unordered = features_get_default('menu_links'); @@ -253,7 +298,7 @@ function menu_links_features_rebuild_ordered($menu_links, $reset = FALSE) { $current = count($unordered); foreach ($unordered as $key => $link) { $identifier = menu_links_features_identifier($link); - $parent = isset($link['parent_path']) ? "{$link['menu_name']}:{$link['parent_path']}" : ''; + $parent = isset($link['parent_identifier']) ? $link['parent_identifier'] : ''; if (empty($parent)) { $ordered[$identifier] = 0; $all_links[$identifier] = $link; @@ -273,6 +318,7 @@ function menu_links_features_rebuild_ordered($menu_links, $reset = FALSE) { // Ensure any default menu items that do not exist are created. foreach (array_keys($ordered) as $identifier) { $link = $all_links[$identifier]; + $existing = features_menu_link_load($identifier); if (!$existing || in_array($link, $menu_links)) { // Retrieve the mlid if this is an existing item. @@ -280,7 +326,7 @@ function menu_links_features_rebuild_ordered($menu_links, $reset = FALSE) { $link['mlid'] = $existing['mlid']; } // Retrieve the plid for a parent link. - if (!empty($link['parent_path']) && $parent = features_menu_link_load("{$link['menu_name']}:{$link['parent_path']}")) { + if (!empty($link['parent_identifier']) && $parent = features_menu_link_load($link['parent_identifier'])) { $link['plid'] = $parent['mlid']; } else { @@ -292,19 +338,67 @@ function menu_links_features_rebuild_ordered($menu_links, $reset = FALSE) { } /** - * Load a menu link by its menu_name:link_path identifier. + * Load a menu link by its menu_name_cleantitle:link_path identifier. + * Also matches links with unique menu_name:link_path */ function features_menu_link_load($identifier) { list($menu_name, $link_path) = explode(':', $identifier, 2); - $link = db_select('menu_links') + list($menu_name, $cleantitle) = array_merge(explode('_', $menu_name, 2), array('', '')); + + $links = db_select('menu_links') ->fields('menu_links', array('menu_name', 'mlid', 'plid', 'link_path', 'router_path', 'link_title', 'options', 'module', 'hidden', 'external', 'has_children', 'expanded', 'weight')) ->condition('menu_name', $menu_name) ->condition('link_path', $link_path) ->execute() - ->fetchAssoc(); - if ($link) { - $link['options'] = unserialize($link['options']); - return $link; + ->fetchAllAssoc('mlid'); + + foreach($links as $link) { + $link->options = unserialize($link->options); + + // title or previous identifier matches + if ((isset($link->options['identifier']) && strcmp($link->options['identifier'], $identifier) == 0) + || (isset($cleantitle) && strcmp(clean_title($link->link_title), $cleantitle) == 0)) { + + return (array)$link; + } } + + // only one link with the requested menu_name and link_path does exists, + // -- providing an upgrade possibility for links saved in a feature before the new identifier-pattern was added. + if (count($links)==1 && empty($cleantitle)) { + $link = reset($links); // get the first item + return (array)$link; + } + // if link_path was changed on an existing link, we need to find it by searching for link_title. + else if (isset($cleantitle)) { + $links = db_select('menu_links') + ->fields('menu_links', array('menu_name', 'mlid', 'plid', 'link_path', 'router_path', 'link_title', 'options', 'module', 'hidden', 'external', 'has_children', 'expanded', 'weight')) + ->condition('menu_name', $menu_name) + ->execute() + ->fetchAllAssoc('mlid'); + + foreach($links as $link) { + $link->options = unserialize($link->options); + + // title or previous identifier matches + if ((isset($link->options['identifier']) && strcmp($link->options['identifier'], $identifier) == 0) + || (isset($cleantitle) && strcmp(clean_title($link->link_title), $cleantitle) == 0)) { + + return (array)$link; + } + } + + } + return FALSE; } + +/** + * Returns a lowercase clean string with only letters, numbers and dashes + */ +function clean_title($str) { + return strtolower(preg_replace_callback('/(\s)|([^a-zA-Z\-0-9])/i', create_function( + '$matches', + 'return $matches[1]?"-":"";' + ), $str)); +} -- 1.7.8.3