Commit f260688f authored by Hoi Sing Edison Wong's avatar Hoi Sing Edison Wong Committed by Joseph Olstad
Browse files

Issue #2353585 by mattsqd, imre.horjan, hswong3i, joseph.olstad: UUID export...

Issue #2353585 by mattsqd, imre.horjan, hswong3i, joseph.olstad: UUID export and import of menu items linking to nodes, terms and users
parent 65b07cae
Loading
Loading
Loading
Loading
+206 −37
Original line number Diff line number Diff line
@@ -17,7 +17,7 @@ function menu_features_api() {
      'feature_source' => TRUE,
      'default_file' => FEATURES_DEFAULTS_INCLUDED,
    ),
    // DEPRECATED
    // DEPRECATED.
    'menu' => array(
      'name' => t('Menu items'),
      'default_hook' => 'menu_default_items',
@@ -29,6 +29,7 @@ function menu_features_api() {

/**
 * Implements hook_features_export().
 *
 * DEPRECATED: This implementation simply migrates deprecated `menu` items
 * to the `menu_links` type.
 */
@@ -61,7 +62,7 @@ function menu_custom_features_export($data, &$export, $module_name = '') {
  $export['dependencies']['features'] = 'features';
  $export['dependencies']['menu'] = 'menu';

  // Collect a menu to module map
  // Collect a menu to module map.
  $pipe = array();
  $map = features_get_default_map('menu_custom', 'menu_name');
  foreach ($data as $menu_name) {
@@ -77,7 +78,7 @@ function menu_custom_features_export($data, &$export, $module_name = '') {
}

/**
 * Implements hook_features_export_render()
 * Implements hook_features_export_render().
 */
function menu_custom_features_export_render($module, $data) {
  $code = array();
@@ -132,7 +133,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)
  // current user may not have access to (i.e. user/login).
  $menu_admin = TRUE;
  $use_menus = array_intersect_key(menu_get_menus(), array_flip(array_filter(variable_get('features_admin_menu_links_menus', array_keys(menu_get_menus())))));
  $menu_links = menu_parent_options($use_menus, array('mlid' => 0));
@@ -141,6 +142,12 @@ function menu_links_features_export_options() {
    list($menu_name, $mlid) = explode(':', $key, 2);
    if ($mlid != 0) {
      $link = menu_link_load($mlid);

      // UUID URL handling.
      if (module_exists('uuid')) {
        _features_set_menu_link_uuid_path($link);
      }

      $identifier = menu_links_features_identifier($link, TRUE);
      $options[$identifier] = "{$menu_name}: {$name}";
    }
@@ -158,16 +165,16 @@ function menu_links_features_identifier($link, $old = FALSE) {

  // The old identifier is requested.
  if ($old) {
    // if identifier already exists
    // If identifier already exists.
    if (isset($link['options']['identifier'])) {
      return $link['options']['identifier'];
    }
    // providing backward compatibility and allowing/enabling multiple links with same paths
    // 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
      // 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.
        // This is where we return the upgrade posibility for links.
        return $identifier;
      }
    }
@@ -185,11 +192,16 @@ function menu_links_features_export($data, &$export, $module_name = '') {
  $export['dependencies']['features'] = 'features';
  $export['dependencies']['menu'] = 'menu';

  // Collect a link to module map
  // Collect a link to module map.
  $pipe = array();
  $map = features_get_default_map('menu_links', 'menu_links_features_identifier');
  foreach ($data as $key => $identifier) {
    if ($link = features_menu_link_load($identifier)) {
      // UUID URL handling.
      // Without this, features info file will lose UUID for menu links.
      if (module_exists('uuid')) {
        _features_set_menu_link_uuid_path($link);
      }
      // 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) {
@@ -201,7 +213,14 @@ function menu_links_features_export($data, &$export, $module_name = '') {
      // 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.
      if (!in_array($link['menu_name'], array('features', 'primary-links', 'secondary-links', 'navigation', 'admin', 'devel'))) {
      if (!in_array($link['menu_name'], array(
        'features',
        'primary-links',
        'secondary-links',
        'navigation',
        'admin',
        'devel',
      ))) {
        $pipe['menu_custom'][] = $link['menu_name'];
      }
    }
@@ -210,7 +229,68 @@ function menu_links_features_export($data, &$export, $module_name = '') {
}

/**
 * Implements hook_features_export_render()
 * Helper function to set UUID data for menu items.
 */
function _features_set_menu_link_uuid_path(&$link) {
  // UUID URL handling.
  if (module_exists('uuid') &&
    in_array(
      $link['router_path'],
      array('node/%', 'taxonomy/term/%', 'user/%', 'uuid'))
  ) {
    $entity_type = 'node';
    switch ($link['router_path']) {
      case 'taxonomy/term/%':
        $entity_type = 'taxonomy_term';
        break;

      case 'user/%':
        $entity_type = 'user';
        break;

      case 'uuid':
        // Restore the internal path instead of the UUID path.
        $uri = explode('/', $link['link_path']);
        if (count($uri) == 3 && $uri[0] == 'uuid') {
          $entity_data = uuid_uri_array_to_data($uri);
          $entities = entity_uuid_load($entity_data['entity_type'], array($entity_data['uuid']));
          if (!empty($entities)) {
            $entity_type = $entity_data['entity_type'];
            $entity = reset($entities);
            $internal_uri = entity_uri($entity_data['entity_type'], $entity);
            $link['link_path'] = $internal_uri['path'];
          }
        }
        // The router path is set to 'uuid', but the link path is not a UUID
        // path.
        else {
          switch ($uri[0]) {
            case 'taxonomy':
              $entity_type = 'taxonomy_term';
              break;

            case 'user':
              $entity_type = 'user';
              break;
          }
        }
        break;
    }
    $path_position = substr_count($link['link_path'], '/');
    $entity = menu_get_object($entity_type, $path_position, $link['link_path']);
    if ($entity && isset($entity->uuid)) {
      $link['uuid'] = $entity->uuid;
      $link['link_path'] = 'uuid/' . $entity_type . '/' . $entity->uuid;
      $link['router_path'] = 'uuid';
    }
    if ($entity && isset($entity->vuuid)) {
      $link['vuuid'] = $entity->vuuid;
    }
  }
}

/**
 * Implements hook_features_export_render().
 */
function menu_links_features_export_render($module, $data, $export = NULL) {
  $code = array();
@@ -221,10 +301,20 @@ function menu_links_features_export_render($module, $data, $export = NULL) {
  foreach ($data as $identifier) {

    if ($link = features_menu_link_load($identifier)) {

      // UUID URL handling.
      if (module_exists('uuid')) {
        _features_set_menu_link_uuid_path($link);
      }

      $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'])) {
        // UUID URL handling.
        if (module_exists('uuid')) {
          _features_set_menu_link_uuid_path($parent);
        }
        // If the new identifier is different than the old, maintain
        // 'parent_path' for backwards compatibility.
        if ($new_identifier != menu_links_features_identifier($link)) {
@@ -237,11 +327,25 @@ function menu_links_features_export_render($module, $data, $export = NULL) {
      }

      if (!isset($link['options']['identifier'])) {
        // Create the identifier only if it doesn't exists.
        // Create the identifier only if it doesn't exist.
        $link['options']['identifier'] = $new_identifier;
        if (!empty($export)) {
          // Identifiers are renewed. We need to update them in the DB.
          $temp = $link;
          // Start uuid handling.
          if (module_exists('uuid')) {
            // Restore the internal path instead of the UUID path.
            $uri = explode('/', $temp['link_path']);
            if ($uri[0] == 'uuid' && count($uri) == 3) {
              $entity_data = uuid_uri_array_to_data($uri);
              $entities = entity_uuid_load($entity_data['entity_type'], array($entity_data['uuid']));
              if (!empty($entities)) {
                $entity = reset($entities);
                $internal_uri = entity_uri($entity_data['entity_type'], $entity);
                $temp['link_path'] = $internal_uri['path'];
              }
            }
          } // End of uuid handling.
          menu_link_save($temp);
        }
      }
@@ -328,6 +432,23 @@ function menu_links_features_rebuild_ordered($menu_links, $reset = FALSE) {

    $existing = features_menu_link_load($identifier);
    if (!$existing || in_array($link, $menu_links)) {
      // Restore the internal path instead of the UUID path.
      $internal_path = '';
      $uri = explode('/', $link['link_path']);
      if (module_exists('uuid') && $uri[0] == 'uuid' && count($uri) == 3) {
        $entity_data = uuid_uri_array_to_data($uri);
        $entities = entity_uuid_load($entity_data['entity_type'], array($entity_data['uuid']));
        if (!empty($entities)) {
          $entity = reset($entities);
          $internal_uri = entity_uri($entity_data['entity_type'], $entity);
          $internal_path = $internal_uri['path'];
        }
      }
      $link_paths = array($link['link_path']);
      if (!empty($internal_path)) {
        $link['link_path'] = $internal_path;
      }

      // Retrieve the mlid if this is an existing item.
      if ($existing) {
        $link['mlid'] = $existing['mlid'];
@@ -350,7 +471,8 @@ function menu_links_features_rebuild_ordered($menu_links, $reset = FALSE) {

/**
 * Load a menu link by its menu_name_cleantitle:link_path identifier.
 * Also matches links with unique menu_name:link_path
 *
 * Also matches links with unique menu_name:link_path.
 */
function features_menu_link_load($identifier) {
  $menu_name = '';
@@ -366,10 +488,43 @@ function features_menu_link_load($identifier) {
    $clean_title = '';
    list($menu_name, $link_path) = explode(':', $identifier, 2);
  }

  // Menu item can link either to internal URL or UUID URL.
  $internal_path = '';
  $uri = explode('/', $link_path);
  if (module_exists('uuid') && $uri[0] == 'uuid' && count($uri) == 3) {
    $entity_data = uuid_uri_array_to_data($uri);
    $entities = entity_uuid_load($entity_data['entity_type'], array($entity_data['uuid']));
    if (!empty($entities)) {
      $entity = reset($entities);
      $internal_uri = entity_uri($entity_data['entity_type'], $entity);
      $internal_path = $internal_uri['path'];
    }
  }
  $link_paths = array($link_path);
  if (!empty($internal_path)) {
    $link_paths = array($internal_path);
  }

  $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'))
    ->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)
    ->condition('link_path', $link_paths, 'IN')
    ->addTag('features_menu_link')
    ->execute()
    ->fetchAllAssoc('mlid');
@@ -380,7 +535,6 @@ function features_menu_link_load($identifier) {
    // 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;
    }
  }
@@ -389,14 +543,29 @@ function features_menu_link_load($identifier) {
  // -- 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
    // Get the first item.
    $link = reset($links);
    return (array) $link;
  }
  // If link_path was changed on an existing link, we need to find it by
  // searching for link_title.
  elseif (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'))
      ->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');
@@ -419,7 +588,7 @@ function features_menu_link_load($identifier) {
}

/**
 * Returns a lowercase clean string with only letters, numbers and dashes
 * Returns a lowercase clean string with only letters, numbers and dashes.
 */
function features_clean_title($str) {
  return strtolower(preg_replace_callback('/(\s)|([^a-zA-Z\-0-9])/i', '_features_clean_title', $str));