diff --git a/includes/features.menu.inc b/includes/features.menu.inc index c883e6a..01d46f1 100644 --- a/includes/features.menu.inc +++ b/includes/features.menu.inc @@ -151,30 +151,43 @@ function menu_links_features_export_options() { } /** - * Callback for generating the menu link exportable identifier. + * Callback for generating the menu link reverse engineerable identifier. */ -function menu_links_features_identifier($link, $old = FALSE) { - // Add some uniqueness to these identifiers, allowing multiple links with the same path, but different titles. - $clean_title = features_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; - } +function menu_links_features_ridentifier($link) { + // TODO: Menu depth should be included in this information. + // Always preserve the unique ID generated the first time. + $uniqueid = NULL; + if (isset($link['options']['identifier'])) { + list($uniqueid) = explode(':', $link['options']['identifier'], 2); + // Check if the $uniqueid corresponds to a 23 character length PHP uniqid + // otherwise this is an old identifier that needs to be converted. + if (strlen($uniqueid) != 23) { + $uniqueid = NULL; } } + if (empty($uniqueid)) { + $uniqueid = uniqid('', TRUE); + } + // Generate an ID that contains a unique persistable ID + // plus information that can allow menu link matching on systems + // that have not had their unique keys generated yet. + $clean_title = features_clean_title(isset($link['title']) ? $link['title'] : $link['link_title']); + $language = isset($link['language']) ? $link['language'] : LANGUAGE_NONE; + return implode(':', array($uniqueid, $link['menu_name'], $clean_title, $link['link_path'], $language)); + // list($uniqueid, $menu_name, $clean_title, $link_path, $language) = explode(':', 5); +} - return isset($link['menu_name'], $link['link_path']) ? "{$link['menu_name']}_{$clean_title}:{$link['link_path']}" : FALSE; +/** + * Callback for generating the menu link exportable identifier. + */ +function menu_links_features_identifier($link, $old = FALSE) { + $identifier = menu_links_features_ridentifier($link); + // Asign a unique persistable ID. + if (!isset($link['options']['identifier']) || $identifier != $link['options']['identifier']) { + $link['options']['identifier'] = $identifier; + menu_link_save($link); + } + return $identifier; } /** @@ -220,43 +233,27 @@ function menu_links_features_export_render($module, $data, $export = NULL) { $translatables = array(); foreach ($data as $identifier) { - if ($link = features_menu_link_load($identifier)) { $new_identifier = menu_links_features_identifier($link, empty($export)); // Replace plid with a parent path. if (!empty($link['plid']) && $parent = menu_link_load($link['plid'])) { - // If the new identifier is different than the old, maintain - // 'parent_path' for backwards compatibility. - if ($new_identifier != menu_links_features_identifier($link)) { - $link['parent_path'] = $parent['link_path']; - } - else { - $clean_title = features_clean_title($parent['title']); - $link['parent_identifier'] = "{$parent['menu_name']}_{$clean_title}:{$parent['link_path']}"; - } + $link['parent_identifier'] = menu_links_features_identifier($parent); } - - if (isset($export)) { - // Don't show new identifier unless we are actually exporting. - $link['options']['identifier'] = $new_identifier; - // identifiers are renewed, => that means we need to update them in the db - $temp = $link; - menu_link_save($temp); - } - - unset($link['plid']); - unset($link['mlid']); + + unset($link['plid']); + unset($link['mlid']); $code[] = " // Exported menu link: {$new_identifier}"; $code[] = " \$menu_links['{$new_identifier}'] = ". features_var_export($link, ' ') .";"; $translatables[] = $link['link_title']; + + } + if (!empty($translatables)) { + $code[] = features_translatables_export($translatables, ' '); } } - if (!empty($translatables)) { - $code[] = features_translatables_export($translatables, ' '); - } - + $code[] = ''; $code[] = ' return $menu_links;'; $code = implode("\n", $code); @@ -275,20 +272,19 @@ function menu_links_features_revert($module) { */ function menu_links_features_rebuild($module) { if ($menu_links = features_get_default('menu_links', $module)) { - menu_links_features_rebuild_ordered($menu_links); + $unordered = features_get_default('menu_links'); + menu_links_features_rebuild_ordered($menu_links, $unordered); } } /** * Generate a depth tree of all menu links. */ -function menu_links_features_rebuild_ordered($menu_links, $reset = FALSE) { +function menu_links_features_rebuild_ordered($menu_links, $unordered, $reset = FALSE) { static $ordered; static $all_links; if (!isset($ordered) || $reset) { $ordered = array(); - $unordered = features_get_default('menu_links'); - // Order all links by depth. if ($unordered) { do { @@ -309,7 +305,7 @@ function menu_links_features_rebuild_ordered($menu_links, $reset = FALSE) { $all_links[$identifier] = $link; unset($unordered[$key]); } - // Exit out when the above does no changes this loop. + // Exit out when the above does no changes this loop. } while (count($unordered) < $current); } // Add all remaining unordered items to the ordered list. @@ -319,11 +315,9 @@ function menu_links_features_rebuild_ordered($menu_links, $reset = FALSE) { } asort($ordered); } - // 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. @@ -334,10 +328,6 @@ function menu_links_features_rebuild_ordered($menu_links, $reset = FALSE) { if (!empty($link['parent_identifier']) && $parent = features_menu_link_load($link['parent_identifier'])) { $link['plid'] = $parent['mlid']; } - // This if for backwards compatibility. - elseif (!empty($link['parent_path']) && $parent = features_menu_link_load("{$link['menu_name']}:{$link['parent_path']}")) { - $link['plid'] = $parent['mlid']; - } else { $link['plid'] = 0; } @@ -346,73 +336,54 @@ function menu_links_features_rebuild_ordered($menu_links, $reset = FALSE) { } } +function features_menu_link_process_old_identifier($identifier, &$uniqueid, &$menu_name, &$clean_title, &$link_path, &$language) { + // TODO: Logic to detect old identifier version. + // return the compatibility type. +} + /** * 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) { - $menu_name = ''; - $link_path = ''; - // This gets variables for menu_name_cleantitle:link_path format. - if (strstr($identifier, "_")) { - $link_path = substr($identifier, strpos($identifier, ":") + 1); - list($menu_name) = explode('_', $identifier, 2); - $clean_title = substr($identifier, strpos($identifier, "_") + 1, strpos($identifier, ":") - strpos($identifier, "_") - 1); - } - // This gets variables for traditional identifier format. - else { - $clean_title = ''; - list($menu_name, $link_path) = explode(':', $identifier, 2); + list($uniqueid, $menu_name, $clean_title, $link_path, $language) = explode(':', $identifier, 5); + $compatiblity_mode = 0; + if (strlen($uniqueid) != 23) { + // This is an old identifier, we need to get as much info as possible. + $compatiblity_mode = features_menu_link_process_old_identifier($identifier, $uniqueid, $menu_name, $clean_title, $link_path, $language); } + $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', 'customized')) - ->condition('menu_name', $menu_name) - ->condition('link_path', $link_path) - ->addTag('features_menu_link') - ->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($clean_title) && strcmp(features_clean_title($link->link_title), $clean_title) == 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($clean_title)) { - $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($clean_title)) { - $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); - // Links with a stored identifier must only be matched on that identifier, - // to prevent cross over assumptions. - if (isset($link->options['identifier'])) { - if (strcmp($link->options['identifier'], $identifier) == 0) { + ->fields('menu_links', array('menu_name', 'mlid', 'plid', 'link_path', 'router_path', 'link_title', 'options', 'module', 'hidden', 'external', 'has_children', 'expanded', 'weight', 'customized', 'language')) + ->condition('menu_name', $menu_name) + ->addTag('features_menu_link') + ->execute() + ->fetchAllAssoc('mlid'); + + // TODO: Implement logic for compatiblity modes, and update local + // identifiers if necessary. + switch($compatiblity_mode) { + case 0: + // Look for the link with the identifier. + foreach($links as $link) { + $link->options = unserialize($link->options); + // Title or previous identifier matches. + if ($link->options['identifier'] == $identifier) { return (array)$link; } } - elseif ((strcmp(features_clean_title($link->link_title), $clean_title) == 0)) { - return (array)$link; - } - } + break; + // Compatiblity for identifiers xxxx + case 1: + break; + // Compatiblity for identifiers xxxx + case 2: + break; + // Compatiblity for identifiers xxxx + case 3: + break; } + // We didn't find anything.... return FALSE; }