diff --git a/core/includes/menu.inc b/core/includes/menu.inc index eba234b..f21c0c8 100644 --- a/core/includes/menu.inc +++ b/core/includes/menu.inc @@ -642,8 +642,13 @@ function _menu_item_localize(&$item, $map, $link_translate = FALSE) { // @todo In order to remove this code we need to implement a database update // including unserializing all existing link options and running this code // on them, as well as adding validation to menu_link_save(). - if (isset($item['options']->attributes['class']) && is_string($item['options']->attributes['class'])) { - $item->localized_options->attributes['class'] = explode(' ', $item['options']->attributes['class']); + if (isset($item['options']['attributes']['class']) && is_string($item['options']['attributes']['class'])) { + if ($link_translate) { + $item->localized_options->attributes['class'] = explode(' ', $item->options->attributes['class']); + } + else { + $item['localized_options']['attributes']['class'] = explode(' ', $item['options']['attributes']['class']); + } } // If we are translating the title of a menu link, and its title is the same // as the corresponding router item, then we can use the title information @@ -671,7 +676,11 @@ function _menu_item_localize(&$item, $map, $link_translate = FALSE) { } // Avoid calling check_plain again on l() function. if ($title_callback == 'check_plain') { - $item['localized_options']['html'] = TRUE; + if ($link_translate) { + $item->localized_options->html = TRUE; + } else { + $item['localized_options']['html'] = TRUE; + } } } } @@ -705,6 +714,11 @@ function _menu_item_localize(&$item, $map, $link_translate = FALSE) { } } } + // If the title and description are the same, use the translated description + // as a localized title. + if ($link_translate && isset($original_description) && isset($item['options']['attributes']['title']) && $item->options->attributes['title'] == $original_description) { + $item->localized_options->attributes['title'] = $item['description']; + } } /** @@ -863,20 +877,22 @@ function menu_tail_load($arg, &$map, $index) { * $item['access'] becomes TRUE if the item is accessible, FALSE otherwise. * $item['href'] is generated from link_path, possibly by to_arg functions. * $item['title'] is generated from link_title, and may be localized. + * $item['options'] is unserialized; it is also changed within the call here * to $item['localized_options'] by _menu_item_localize(). */ function _menu_link_translate(&$item, $translate = FALSE) { - if ($item['external']) { - $item['access'] = 1; + if ($item->isExternal()) { + $item->setAccess(1); $map = array(); - $item['href'] = $item['link_path']; - $item['title'] = $item['link_title']; + $item['href'] = $item->getLinkPath(); + $item['title'] = $item->getLinkTitle(); + $item->localized_options->setValue($item->options->getValue()); } else { // Complete the path of the menu link with elements from the current path, // if it contains dynamic placeholders (%). - $map = explode('/', $item['link_path']); - if (strpos($item['link_path'], '%') !== FALSE) { + $map = explode('/', $item->getLinkPath()); + if (strpos($item->getLinkPath(), '%') !== FALSE) { // Invoke registered to_arg callbacks. if (!empty($item['to_arg_functions'])) { _menu_link_map_translate($map, $item['to_arg_functions']); @@ -892,7 +908,7 @@ function _menu_link_translate(&$item, $translate = FALSE) { elseif ($translate && ($current_router_item = menu_get_item())) { // If $translate is TRUE, then this link is in the active trail. // Only translate paths within the current path. - if (strpos($current_router_item['path'], $item['link_path']) === 0) { + if (strpos($current_router_item['path'], $item->getLinkPath()) === 0) { $count = count($map); $map = array_slice($current_router_item['original_map'], 0, $count); $item['original_map'] = $map; @@ -900,7 +916,7 @@ function _menu_link_translate(&$item, $translate = FALSE) { $item['map'] = array_slice($current_router_item['map'], 0, $count); } // Reset access to check it (for the first time). - unset($item['access']); + $item->setAccess(NULL); } } } @@ -908,17 +924,17 @@ function _menu_link_translate(&$item, $translate = FALSE) { // Skip links containing untranslated arguments. if (strpos($item['href'], '%') !== FALSE) { - $item['access'] = FALSE; + $item->setAccess(FALSE); return FALSE; } // menu_tree_check_access() may set this ahead of time for links to nodes. - if (!isset($item['access'])) { + if ($item->getAccess() === NULL) { if ($route = $item->getRoute()) { - $item['access'] = menu_item_route_access($route, $item['href'], $map); + $item->setAccess(menu_item_route_access($route, $item['href'], $map)); } elseif (!empty($item['load_functions']) && !_menu_load_objects($item, $map)) { // An error occurred loading an object. - $item['access'] = FALSE; + $item->setAccess(FALSE); return FALSE; } // Apply the access check defined in hook_menu() if there is not route @@ -928,7 +944,7 @@ function _menu_link_translate(&$item, $translate = FALSE) { } } // For performance, don't localize a link the user can't access. - if ($item['access']) { + if ($item->getAccess()) { _menu_item_localize($item, $map, TRUE); } } @@ -936,7 +952,7 @@ function _menu_link_translate(&$item, $translate = FALSE) { // Allow other customizations - e.g. adding a page-specific query string to the // options array. For performance reasons we only invoke this hook if the link // has the 'alter' flag set in the options array. - if (!empty($item['options']->alter)) { + if (!empty($item->options->alter)) { drupal_alter('translated_menu_link', $item, $map); } @@ -1088,7 +1104,7 @@ function menu_tree_output($tree) { // Pull out just the menu links we are going to render so that we // get an accurate count for the first/last classes. foreach ($tree as $data) { - if ($data['link']['access'] && !$data['link']['hidden']) { + if ($data['link']->getAccess() && !$data['link']->isHidden()) { $items[] = $data; } } @@ -1106,47 +1122,48 @@ function menu_tree_output($tree) { // Set a class for the
  • -tag. Since $data['below'] may contain local // tasks, only set 'expanded' class if the link also has children within // the current menu. - if ($data['link']['has_children'] && $data['below']) { + if ($data['link']->hasChildren() && $data['below']) { $class[] = 'expanded'; } - elseif ($data['link']['has_children']) { + elseif ($data['link']->hasChildren()) { $class[] = 'collapsed'; } else { $class[] = 'leaf'; } // Set a class if the link is in the active trail. - $localized_options = $data['link']['options']; - if ($data['link']['in_active_trail']) { + $localized_attributes = $data['link']->localized_options->attributes; + if ($data['link']->in_active_trail->value) { $class[] = 'active-trail'; - $localized_options['attributes']['class'][] = 'active-trail'; + $localized_attributes['class'][] = 'active-trail'; } // Normally, l() compares the href of every link with the current path and // sets the active class accordingly. But local tasks do not appear in menu // trees, so if the current path is a local task, and this link is its // tab root, then we have to set the class manually. if ($data['link']['href'] == $router_item['tab_root_href'] && $data['link']['href'] != current_path()) { - $localized_options['attributes']['class'][] = 'active'; + $localized_attributes['class'][] = 'active'; } - $data['link']['options'] = $localized_options; + $data['link']->localized_options->attributes = $localized_attributes; // Allow menu-specific theme overrides. - $element['#theme'] = 'menu_link__' . strtr($data['link']['menu_name'], '-', '_'); + $element['#theme'] = 'menu_link__' . strtr($data['link']->getMenuName(), '-', '_'); $element['#attributes']['class'] = $class; $element['#title'] = $data['link']['title']; $element['#href'] = $data['link']['href']; - $element['#options'] = !empty($data['link']['options']) ? $data['link']['options'] : array(); + $localized_options = $data['link']->localized_options->getValue(); + $element['#localized_options'] = !empty($localized_options) ? $localized_options : array(); $element['#below'] = $data['below'] ? menu_tree_output($data['below']) : $data['below']; $element['#original_link'] = $data['link']; // Index using the link's unique mlid. - $build[$data['link']['mlid']] = $element; + $build[$data['link']->id()] = $element; } if ($build) { // Make sure drupal_render() does not re-order the links. $build['#sorted'] = TRUE; // Add the theme wrapper for outer markup. // Allow menu-specific theme overrides. - $build['#theme_wrappers'][] = 'menu_tree__' . strtr($data['link']['menu_name'], '-', '_'); + $build['#theme_wrappers'][] = 'menu_tree__' . strtr($data['link']->getMenuName(), '-', '_'); } return $build; @@ -1354,12 +1371,13 @@ function menu_tree_page_data($menu_name, $max_depth = NULL, $only_active_trail = // active trail, if it resides in the requested menu. Otherwise, // we'd needlessly re-run _menu_build_tree() queries for every menu // on every page. - if ($active_link['menu_name'] == $menu_name) { + if ($active_link->getMenuName() == $menu_name) { // Use all the coordinates, except the last one because there // can be no child beyond the last column. for ($i = 1; $i < MENU_MAX_DEPTH; $i++) { - if ($active_link['p' . $i]) { - $active_trail[$active_link['p' . $i]] = $active_link['p' . $i]; + $p_i = 'p' . $i; + if ($active_link->{$p_i}->value) { + $active_trail[$active_link->{$p_i}->value] = $active_link->{$p_i}->value; } } // If we are asked to build links for the active trail only, skip @@ -1525,11 +1543,11 @@ function _menu_build_tree($menu_name, array $parameters = array()) { */ function menu_tree_collect_node_links(&$tree, &$node_links) { foreach ($tree as $key => $v) { - if ($tree[$key]['link']['router_path'] == 'node/%') { - $nid = substr($tree[$key]['link']['link_path'], 5); + if ($tree[$key]['link']->getRouterPath() == 'node/%') { + $nid = substr($tree[$key]['link']->getLinkPath(), 5); if (is_numeric($nid)) { - $node_links[$nid][$tree[$key]['link']['mlid']] = &$tree[$key]['link']; - $tree[$key]['link']['access'] = FALSE; + $node_links[$nid][$tree[$key]['link']->id()] = &$tree[$key]['link']; + $tree[$key]['link']->set('access', FALSE); } } if ($tree[$key]['below']) { @@ -1576,14 +1594,14 @@ function _menu_tree_check_access(&$tree) { foreach ($tree as $key => $v) { $item = &$tree[$key]['link']; _menu_link_translate($item); - if ($item['access'] || ($item['in_active_trail'] && strpos($item['href'], '%') !== FALSE)) { + if ($item->getAccess() || ($item->in_active_trail->value && strpos($item['href'], '%') !== FALSE)) { if ($tree[$key]['below']) { _menu_tree_check_access($tree[$key]['below']); } // The weights are made a uniform 5 digits by adding 50000 as an offset. // After _menu_link_translate(), $item['title'] has the localized link title. // Adding the mlid to the end of the index insures that it is unique. - $new_tree[(50000 + $item['weight']) . ' ' . $item['title'] . ' ' . $item['mlid']] = $tree[$key]; + $new_tree[(50000 + $item->getWeight()) . ' ' . $item['title'] . ' ' . $item->id()] = $tree[$key]; } } // Sort siblings in the tree based on the weights and localized titles. @@ -1634,9 +1652,9 @@ function _menu_tree_data(&$links, $parents, $depth) { while ($item = array_pop($links)) { // We need to determine if we're on the path to root so we can later build // the correct active trail and breadcrumb. - $item['in_active_trail'] = in_array($item['mlid'], $parents); + $item->in_active_trail->value = in_array($item->id(), $parents); // Add the current link to the tree. - $tree[$item['mlid']] = array( + $tree[$item->id()] = array( 'link' => $item, 'below' => array(), ); @@ -1644,14 +1662,14 @@ function _menu_tree_data(&$links, $parents, $depth) { // to other recursive function calls if we return or build a sub-tree. $next = end($links); // Check whether the next link is the first in a new sub-tree. - if ($next && $next['depth'] > $depth) { + if ($next && $next->getDepth() > $depth) { // Recursively call _menu_tree_data to build the sub-tree. - $tree[$item['mlid']]['below'] = _menu_tree_data($links, $parents, $next['depth']); + $tree[$item->id()]['below'] = _menu_tree_data($links, $parents, $next->getDepth()); // Fetch next link after filling the sub-tree. $next = end($links); } // Determine if we should exit the loop and return. - if (!$next || $next['depth'] < $depth) { + if (!$next || $next->getDepth() < $depth) { break; } } @@ -1695,7 +1713,7 @@ function theme_menu_link(array $variables) { if ($element['#below']) { $sub_menu = drupal_render($element['#below']); } - $output = l($element['#title'], $element['#href'], $element['#options']); + $output = l($element['#title'], $element['#href'], $element['#localized_options']); return '' . $output . $sub_menu . "
  • \n"; } @@ -1714,7 +1732,7 @@ function theme_menu_link(array $variables) { function theme_menu_local_task($variables) { $link = $variables['element']['#link']; $link += array( - 'options' => array(), + 'localized_options' => array(), ); $link_text = $link['title']; @@ -1724,14 +1742,14 @@ function theme_menu_local_task($variables) { // If the link does not contain HTML already, check_plain() it now. // After we set 'html'=TRUE the link will not be sanitized by l(). - if (empty($link['options']['html'])) { + if (empty($link['localized_options']['html'])) { $link['title'] = check_plain($link['title']); } - $link['options']['html'] = TRUE; + $link['localized_options']['html'] = TRUE; $link_text = t('!local-task-title!active', array('!local-task-title' => $link['title'], '!active' => $active)); } - return '' . l($link_text, $link['href'], $link['options']) . ''; + return '' . l($link_text, $link['href'], $link['localized_options']) . ''; } /** @@ -1749,13 +1767,13 @@ function theme_menu_local_action($variables) { $link = $variables['element']['#link']; $link += array( 'href' => '', - 'options' => array(), + 'localized_options' => array(), ); - $link['options']['attributes']['class'][] = 'button'; - $link['options']['attributes']['class'][] = 'button-action'; + $link['localized_options']['attributes']['class'][] = 'button'; + $link['localized_options']['attributes']['class'][] = 'button-action'; $output = '
  • '; - $output .= l($link['title'], $link['href'], $link['options']); + $output .= l($link['title'], $link['href'], $link['localized_options']); $output .= "
  • "; return $output; @@ -1917,12 +1935,12 @@ function menu_navigation_links($menu_name, $level = 0) { $router_item = menu_get_item(); $links = array(); foreach ($tree as $item) { - if (!$item['link']['hidden']) { + if (!$item['link']->isHidden()) { $class = ''; - $l = $item['link']['options']->getValue(); + $l = $item['link']->localized_options->getValue(); $l['href'] = $item['link']['href']; $l['title'] = $item['link']['title']; - if ($item['link']['in_active_trail']) { + if ($item['link']->in_active_trail->value) { $class = ' active-trail'; $l['attributes']['class'][] = 'active-trail'; } @@ -1934,7 +1952,7 @@ function menu_navigation_links($menu_name, $level = 0) { $l['attributes']['class'][] = 'active'; } // Keyed with the unique mlid to generate classes in theme_links(). - $links['menu-' . $item['link']['mlid'] . $class] = $l; + $links['menu-' . $item['link']->id() . $class] = $l; } } return $links; @@ -2048,7 +2066,7 @@ function menu_local_tasks($level = 0) { // would not be marked as active, since l() only compares the href // with current_path(). if ($link['href'] != current_path()) { - $link['options']['attributes']['class'][] = 'active'; + $link['localized_options']['attributes']['class'][] = 'active'; } $tabs_current[$link['href']] = array( '#theme' => 'menu_local_task', @@ -2125,7 +2143,7 @@ function menu_local_tasks($level = 0) { // links to its parent, l() will not mark it as active, as it only // compares the link's href to current_path(). if ($link['href'] != current_path()) { - $link['options']['attributes']['class'][] = 'active'; + $link['localized_options']['attributes']['class'][] = 'active'; } $tabs_current[$link['href']] = array( '#theme' => 'menu_local_task', @@ -2471,7 +2489,7 @@ function menu_set_active_trail($new_trail = NULL) { 'title' => t('Home'), 'href' => '', 'link_path' => '', - 'options' => array(), + 'localized_options' => array(), 'type' => 0, ); @@ -2485,7 +2503,7 @@ function menu_set_active_trail($new_trail = NULL) { // Pass TRUE for $only_active_trail to make menu_tree_page_data() build // a stripped down menu tree containing the active trail only, in case // the given menu has not been built in this request yet. - $tree = menu_tree_page_data($preferred_link['menu_name'], NULL, TRUE); + $tree = menu_tree_page_data($preferred_link->getMenuName(), NULL, TRUE); list($key, $curr) = each($tree); } // There is no link for the current path. @@ -2496,7 +2514,7 @@ function menu_set_active_trail($new_trail = NULL) { while ($curr) { $link = $curr['link']; - if ($link['in_active_trail']) { + if ($link->in_active_trail->value) { // Add the link to the trail, unless it links to its parent. if (!($link['type'] & MENU_LINKS_TO_PARENT)) { // The menu tree for the active trail may contain additional links @@ -2510,7 +2528,7 @@ function menu_set_active_trail($new_trail = NULL) { if (strpos($link['href'], '%') !== FALSE) { _menu_link_translate($link, TRUE); } - if ($link['access']) { + if ($link->getAccess()) { $trail[] = $link; } } @@ -2588,10 +2606,10 @@ function menu_link_get_preferred($path = NULL, $selected_menu = NULL) { // Sort candidates by link path and menu name. $candidates = array(); foreach ($menu_links as $candidate) { - $candidates[$candidate['link_path']][$candidate['menu_name']] = $candidate; + $candidates[$candidate->getLinkPath()][$candidate->getMenuName()] = $candidate; // Add any menus not already in the menu name search list. - if (!in_array($candidate['menu_name'], $menu_names)) { - $menu_names[] = $candidate['menu_name']; + if (!in_array($candidate->getMenuName(), $menu_names)) { + $menu_names[] = $candidate->getMenuName(); } } @@ -2604,7 +2622,7 @@ function menu_link_get_preferred($path = NULL, $selected_menu = NULL) { $candidate_item = $candidates[$link_path][$menu_name]; $map = explode('/', $path); _menu_translate($candidate_item, $map); - if ($candidate_item['access']) { + if ($candidate_item->getAccess()) { $preferred_links[$path][$menu_name] = $candidate_item; if (empty($preferred_links[$path][MENU_PREFERRED_LINK])) { // Store the most specific link. @@ -2687,7 +2705,7 @@ function menu_get_active_breadcrumb() { } foreach ($active_trail as $parent) { - $l_options = $parent['options']; + $l_options = $parent['localized_options']; $breadcrumb[] = l($parent['title'], $parent['href'], (is_array($l_options) && !empty($l_options)) ? $l_options : array('')); } } @@ -2837,19 +2855,10 @@ function menu_router_build($save = FALSE) { * The translated path pattern from the route. */ function _menu_router_translate_route($route_name) { - $route = \Drupal::service('router.route_provider') - ->getRouteByName($route_name); - - $path = $route->getPattern(); - $defaults = $route->getDefaults(); - - // Remove placeholders with default values from the outline, so that they - // will still match. - $remove = array_map(function($a) { - return '/{' . $a . '}'; - }, array_keys($defaults)); - $stripped_path = str_replace($remove, '', $path); - $outline = preg_replace('#\{(\w+)\}#', '%$1', $stripped_path); + $outline = \Drupal::service('router.route_provider') + ->getRouteByName($route_name) + ->compile() + ->getPatternOutline(); return trim($outline, '/'); } @@ -3126,14 +3135,15 @@ function _menu_router_build($callbacks, $save = FALSE) { // Look for wildcards in the form allowed to be used in PHP functions, // because we are using these to construct the load function names. if (preg_match('/^%(|' . DRUPAL_PHP_FUNCTION_PATTERN . ')$/', $part, $matches)) { - $match = TRUE; if (empty($matches[1])) { + $match = TRUE; $load_functions[$k] = NULL; } else { if (function_exists($matches[1] . '_to_arg')) { $to_arg_functions[$k] = $matches[1] . '_to_arg'; $load_functions[$k] = NULL; + $match = TRUE; } if (function_exists($matches[1] . '_load')) { $function = $matches[1] . '_load'; @@ -3141,6 +3151,7 @@ function _menu_router_build($callbacks, $save = FALSE) { // function when this menu path is checked, if 'load arguments' // exists. $load_functions[$k] = isset($item['load arguments']) ? array($function => $item['load arguments']) : $function; + $match = TRUE; } } } diff --git a/core/lib/Drupal/Core/Entity/EntityNG.php b/core/lib/Drupal/Core/Entity/EntityNG.php index 66f9ea7..5e94d71 100644 --- a/core/lib/Drupal/Core/Entity/EntityNG.php +++ b/core/lib/Drupal/Core/Entity/EntityNG.php @@ -616,7 +616,7 @@ public function updateOriginalValues() { } /** - * Implements the magic method for setting object properties. + * Implements the magic method for getting object properties. * * @todo: A lot of code still uses non-fields (e.g. $entity->content in render * controllers) by reference. Clean that up. diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/MapItem.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/MapItem.php index dd835bd..4a9c8a0 100644 --- a/core/lib/Drupal/Core/Entity/Plugin/DataType/MapItem.php +++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/MapItem.php @@ -32,20 +32,22 @@ public function getPropertyDefinitions() { foreach ($this->properties as $name => $property) { $definitions[$name] = $property->getDefinition(); } + return $definitions; } /** - * Overrides \Drupal\Core\TypedData\TypedData::setValue(). + * Overrides \Drupal\Core\Entity\Field\FieldItemBase::setValue(). * * @param array|null $values * An array of property values. */ public function setValue($values, $notify = TRUE) { + $this->properties = array(); if (!isset($values)) { - $this->properties = array(); return; } + if (!is_array($values)) { if ($values instanceof MapItem) { $values = $values->getValue(); @@ -54,35 +56,41 @@ public function setValue($values, $notify = TRUE) { $values = unserialize($values); } } - $this->properties = array(); + foreach($values as $name => $value) { - $this->{$name} = $value; + $this->properties[$name] = $this->valueToProperty($value, $name); } } public function __get($name) { if (!isset($this->properties[$name])) { - $this->{$name} = array(); + $this->properties[$name] = $this->valueToProperty(array(), $name); } + return $this->properties[$name]->getValue(); } public function __set($name, $value) { if (isset($value)) { if (isset($this->properties[$name])) { - $this->set($name, $value); + $this->properties[$name]->setValue($value); } else { - $def = array('type' => 'any'); - if ($value instanceof TypedData) { - $def = $value->getDefinition(); - $value = $value->getValue(); - } - $this->properties[$name] = \Drupal::typedData()->create($def, $value, $name); + $this->properties[$name] = $this->valueToProperty($value, $name); } } else { unset($this->properties[$name]); } } -} + + protected function valueToProperty($value, $name) { + $def = array('type' => 'any'); + if ($value instanceof TypedData) { + $def = $value->getDefinition(); + $value = $value->getValue(); + } + + return \Drupal::typedData()->create($def, $value, $name, $this); + } +} \ No newline at end of file diff --git a/core/modules/contextual/contextual.module b/core/modules/contextual/contextual.module index ebaff55..529fa5c 100644 --- a/core/modules/contextual/contextual.module +++ b/core/modules/contextual/contextual.module @@ -269,9 +269,9 @@ function contextual_pre_render_links($element) { 'href' => $item['href'], ); // @todo theme_links() should *really* use the same parameters as l(). - $item['options'] += array('query' => array()); - $item['options']['query'] += drupal_get_destination(); - $links[$class] += $item['options']; + $item['localized_options'] += array('query' => array()); + $item['localized_options']['query'] += drupal_get_destination(); + $links[$class] += $item['localized_options']; } $element['#links'] = $links; diff --git a/core/modules/menu/lib/Drupal/menu/Form/MenuLinkDeleteForm.php b/core/modules/menu/lib/Drupal/menu/Form/MenuLinkDeleteForm.php index 87c03f0..43db3a2 100644 --- a/core/modules/menu/lib/Drupal/menu/Form/MenuLinkDeleteForm.php +++ b/core/modules/menu/lib/Drupal/menu/Form/MenuLinkDeleteForm.php @@ -38,10 +38,10 @@ public function getCancelRoute() { */ public function submit(array $form, array &$form_state) { menu_link_delete($this->entity->id()); - $t_args = array('%title' => $this->entity->link_title); + $t_args = array('%title' => $this->entity->getLinkTitle()); drupal_set_message(t('The menu link %title has been deleted.', $t_args)); watchdog('menu', 'Deleted menu link %title.', $t_args, WATCHDOG_NOTICE); - $form_state['redirect'] = 'admin/structure/menu/manage/' . $this->entity->menu_name->value; + $form_state['redirect'] = 'admin/structure/menu/manage/' . $this->entity->getMenuName(); } } diff --git a/core/modules/menu/lib/Drupal/menu/Form/MenuLinkResetForm.php b/core/modules/menu/lib/Drupal/menu/Form/MenuLinkResetForm.php index c6615e8..6f41606 100644 --- a/core/modules/menu/lib/Drupal/menu/Form/MenuLinkResetForm.php +++ b/core/modules/menu/lib/Drupal/menu/Form/MenuLinkResetForm.php @@ -53,7 +53,7 @@ public function getConfirmText() { public function submit(array $form, array &$form_state) { $new_menu_link = $this->entity->reset(); drupal_set_message(t('The menu link was reset to its default settings.')); - $form_state['redirect'] = 'admin/structure/menu/manage/' . $new_menu_link->menu_name->value; + $form_state['redirect'] = 'admin/structure/menu/manage/' . $new_menu_link->getMenuName(); } } diff --git a/core/modules/menu/lib/Drupal/menu/MenuFormController.php b/core/modules/menu/lib/Drupal/menu/MenuFormController.php index b8e47f7..68bc6a4 100644 --- a/core/modules/menu/lib/Drupal/menu/MenuFormController.php +++ b/core/modules/menu/lib/Drupal/menu/MenuFormController.php @@ -297,7 +297,7 @@ protected function buildOverviewTreeForm($tree, $delta) { $mlid = 'mlid:' . $item['mlid']; $form[$mlid]['#item'] = $item; $form[$mlid]['#attributes'] = $item['hidden'] ? array('class' => array('menu-disabled')) : array('class' => array('menu-enabled')); - $form[$mlid]['title']['#markup'] = l($item['title'], $item['href'], $item['options']); + $form[$mlid]['title']['#markup'] = l($item['title'], $item['href'], $item['localized_options']); if ($item['hidden']) { $form[$mlid]['title']['#markup'] .= ' (' . t('disabled') . ')'; } diff --git a/core/modules/menu/lib/Drupal/menu/Tests/MenuTest.php b/core/modules/menu/lib/Drupal/menu/Tests/MenuTest.php index 03e4c6d..e0ac0d7 100644 --- a/core/modules/menu/lib/Drupal/menu/Tests/MenuTest.php +++ b/core/modules/menu/lib/Drupal/menu/Tests/MenuTest.php @@ -88,7 +88,7 @@ function testMenu() { // helper. $this->assertIdentical($return_value, $item->save(), 'Return value of menu_link_save() is identical to the return value of $menu_link->save().'); $saved_item = entity_load('menu_link', $item['mlid']); - $this->assertEqual($description, $saved_item['options']['attributes']['title'], 'Saving an existing link updates the description (title attribute)'); + $this->assertEqual($description, $saved_item->options->attributes['title'], 'Saving an existing link updates the description (title attribute)'); $this->resetMenuLink($item, $old_title); } diff --git a/core/modules/menu/menu.install b/core/modules/menu/menu.install index 4e0d032..5376346 100644 --- a/core/modules/menu/menu.install +++ b/core/modules/menu/menu.install @@ -5,8 +5,6 @@ * Install, update and uninstall functions for the menu module. */ -use Drupal\Component\Uuid\Uuid; - /** * Implements hook_install(). */ @@ -18,9 +16,9 @@ function menu_install() { $system_link = reset($system_link); $base_link = entity_create('menu_link', array( - 'menu_name' => $system_link->menu_name, + 'menu_name' => $system_link->getMenuName(), 'router_path' => 'admin/structure/menu/manage/%', - 'module' => 'menu', + 'module' => 'menu' )); $menus = entity_load_multiple('menu'); @@ -31,8 +29,8 @@ function menu_install() { $link->link_path = 'admin/structure/menu/manage/' . $menu->id(); $query = Drupal::entityQuery('menu_link') - ->condition('link_path', $link->link_path) - ->condition('plid', $link->plid); + ->condition('link_path', $link->getLinkPath()) + ->condition('plid', $link->getParentLinkId()); $result = $query->execute(); if (empty($result)) { diff --git a/core/modules/menu/menu.module b/core/modules/menu/menu.module index 662308c..5dd2d0c 100644 --- a/core/modules/menu/menu.module +++ b/core/modules/menu/menu.module @@ -351,7 +351,7 @@ function menu_block_view_system_menu_block_alter(array &$build, BlockPluginInter list(, $menu_name) = explode(':', $block->getPluginId()); if (isset($menus[$menu_name]) && isset($build['content'])) { foreach (element_children($build['content']) as $key) { - $build['content']['#contextual_links']['menu'] = array('admin/structure/menu/manage', array($build['content'][$key]['#original_link']['menu_name'])); + $build['content']['#contextual_links']['menu'] = array('admin/structure/menu/manage', array($build['content'][$key]['#original_link']->getMenuName())); } } } diff --git a/core/modules/menu_link/lib/Drupal/menu_link/Entity/MenuLink.php b/core/modules/menu_link/lib/Drupal/menu_link/Entity/MenuLink.php index 0b44153..5145d85 100644 --- a/core/modules/menu_link/lib/Drupal/menu_link/Entity/MenuLink.php +++ b/core/modules/menu_link/lib/Drupal/menu_link/Entity/MenuLink.php @@ -13,6 +13,7 @@ use Drupal\Core\Entity\EntityNG; use Drupal\Core\Entity\EntityStorageControllerInterface; use Drupal\Core\TypedData\TypedDataInterface; +use Drupal\Component\Uuid\Uuid; use Drupal\menu_link\MenuLinkInterface; use Drupal\menu_link\MenuLinkStorageControllerInterface; use Symfony\Component\Routing\Route; @@ -84,7 +85,7 @@ class MenuLink extends EntityNG implements \ArrayAccess, MenuLinkInterface { 'number_parts', 'context', 'tab_parent', 'tab_root', 'title', 'title_callback', 'title_arguments', 'theme_callback', 'theme_arguments', 'type', 'description', 'description_callback', 'description_arguments', - 'position', 'include_file', 'route_name', + 'position', 'include_file', ); /** @@ -106,6 +107,7 @@ public function bundle() { */ public function createDuplicate() { $duplicate = parent::createDuplicate(); + $duplicate->get('plid')->offsetGet(0)->set('value', NULL); return $duplicate; } @@ -170,6 +172,7 @@ public static function buildFromRouterItem(array $item) { 'link_title' => $item['title'], 'link_path' => $item['path'], 'options' => empty($item['description']) ? array() : array('attributes' => array('title' => $item['description'])), + 'route_name' => $item['route_name'], ); return \Drupal::entityManager() ->getStorageController('menu_link')->create($item); @@ -192,11 +195,11 @@ public function offsetGet($offset) { if (in_array($offset, $this->oldRoutingProperties)) { return $this->oldRouterItem[$offset]; } - elseif ($offset == 'options' || $offset == 'localized_options') { - return $this->options->getValue(); + elseif (in_array($offset, array('options', 'localized_options', 'route_parameters'))) { + return $this->get($offset)->getValue(); } elseif ($this->getPropertyDefinition($offset)) { - return $this->$offset->value; + return $this->get($offset)->value; } else { return $this->$offset; @@ -210,11 +213,11 @@ public function offsetSet($offset, $value) { if (in_array($offset, $this->oldRoutingProperties)) { $this->oldRouterItem[$offset] = $value; } - elseif ($offset == 'options' || $offset == 'localized_options') { + elseif (in_array($offset, array('options', 'localized_options', 'route_parameters'))) { if (is_array($value)) { foreach ($value as $delta => $value_item) { if (!is_numeric($delta)) { - $this->options = array($value); + $this->{$offset} = array($value); return; } } @@ -235,10 +238,12 @@ public function offsetUnset($offset) { if (in_array($offset, $this->oldRoutingProperties)) { unset($this->oldRouterItem[$offset]); } + elseif ($this->getPropertyDefinition($offset)) { + $this->get($offset)->setValue(NULL); + } else { - $this->{$offset}->value = NULL; + $this->get($offset)->setValue(NULL); } -// unset($this->{$offset}); } /** @@ -361,8 +366,9 @@ public function preSave(EntityStorageControllerInterface $storage_controller) { $this->setRouterPath(_menu_find_router_path($this->getLinkPath())); } } + // Find the route_name. - if ($this->getRouteName()) { + if ($this->getRouteName() === NULL) { if ($result = static::findRouteNameParameters($this->getLinkPath())) { $this->setRouteName($result[0]); $this->route_parameters = $result[1]; @@ -480,6 +486,21 @@ public function findParent(MenuLinkStorageControllerInterface $storage_controlle } /** + * overrides \Drupal\Core\Entity\EntityNG::set() + */ + public function set($property_name, $value, $notify = TRUE) { + // work-around entity_form_submit_build_entity() -> entity.set() trying to + // set a non-existing fields into MenuLink. + $definition = $this->getPropertyDefinition($property_name); + if (!$definition) { + $this->$property_name = $value; + } + else { + parent::set($property_name, $value, $notify); + } + } + + /** * {@inheritdoc} */ public function getMenuName() { @@ -695,6 +716,29 @@ public function setRouteName($route_name) { return $this; } + public function getAccess() { + return $this->get('access')->value; + } + + public function setAccess($access) { + $this->set('access', $access); + return $this; + } + /** + * {@inheritdoc} + */ + public function getRouteParams() { + return $this->get('route_parameters')->value; + } + + /** + * {@inheritdoc} + */ + public function setRouteParams($route_parameters) { + $this->set('route_parameters', $route_parameters); + return $this; + } + /** * {@inheritdoc} */ diff --git a/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkFormController.php b/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkFormController.php index 7dbbbdb..49c9e9d 100644 --- a/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkFormController.php +++ b/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkFormController.php @@ -256,7 +256,9 @@ public function buildEntity(array $form, array &$form_state) { // The value of "hidden" is the opposite of the value supplied by the // "enabled" checkbox. $entity->hidden->value = (int) !$form_state['values']['enabled']; - list($entity->menu_name->value, $entity->plid->target_id) = explode(':', $form_state['values']['parent']); + $substrs = explode(':', $form_state['values']['parent']); + $entity->setMenuName($substrs[0]); + $entity->plid = intval($substrs[1]); $attributes = $entity->options->attributes; $attributes['title'] = $form_state['values']['description']; $entity->options->attributes = $attributes; @@ -269,7 +271,7 @@ public function buildEntity(array $form, array &$form_state) { public function save(array $form, array &$form_state) { if ($this->entity->save()) { drupal_set_message(t('The menu link has been saved.')); - $form_state['redirect'] = 'admin/structure/menu/manage/' . $this->entity->menu_name->value; + $form_state['redirect'] = 'admin/structure/menu/manage/' . $this->entity->getMenuName(); } else { drupal_set_message(t('There was an error saving the menu link.'), 'error'); diff --git a/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkInterface.php b/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkInterface.php index acb4549..3b307ba 100644 --- a/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkInterface.php +++ b/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkInterface.php @@ -372,4 +372,23 @@ public function getRouteName(); */ public function setRouteName($route_name); + /** + * Returns the route parameters associated with this menu link, if any. + * + * @return array + * The route parameters of this menu link. + */ + public function getRouteParams(); + + /** + * Sets the route parameters associated with this menu link. + * + * @param array $route_parameters + * The route parameters associated with this menu link. + * + * @return \Drupal\menu_link\MenuLinkInterface + * The called menu link entity. + */ + public function setRouteParams($route_parameters); + } diff --git a/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkStorageController.php b/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkStorageController.php index c221df5..6991e1d 100644 --- a/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkStorageController.php +++ b/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkStorageController.php @@ -61,7 +61,7 @@ public function __construct($entity_type, array $entity_info, Connection $databa $this->routeProvider = $route_provider; if (empty(static::$routerItemFields)) { - static::$routerItemFields = array_diff(drupal_schema_fields_sql('menu_router'), array('weight')); + static::$routerItemFields = array_diff(drupal_schema_fields_sql('menu_router'), array('weight', 'route_name')); } } @@ -74,6 +74,7 @@ public function create(array $values) { if (!isset($values['bundle']) && isset($values['menu_name'])) { $values['bundle'] = $values['menu_name']; } + return parent::create($values); } @@ -109,7 +110,7 @@ protected function attachLoad(&$queried_entities, $load_revision = FALSE) { foreach ($queried_entities as &$record) { $record->options = unserialize($record->options); - $record->route_parameters = unserialize($record->route_parameters); + $record->route_parameters = isset($record->route_parameters) ? unserialize($record->route_parameters) : array(); // Use the weight property from the menu link. $record->router_item['weight'] = $record->weight; @@ -154,6 +155,18 @@ protected function mapFromStorageRecords(array $records, $load_revision = FALSE) } /** + * Overrides DatabaseStorageControllerNG::mapToStorageRecord(). + */ + protected function mapToStorageRecord(EntityInterface $entity) { + $record = parent::mapToStorageRecord($entity); + foreach (array('options', 'route_parameters') as $property) { + $record->$property = $entity->$property->getValue(); + } + + return $record; + } + + /** * Overrides DatabaseStorageController::save(). */ public function save(EntityInterface $entity) { @@ -164,9 +177,6 @@ public function save(EntityInterface $entity) { $transaction = $this->database->startTransaction(); try { - // Ensure we are dealing with the actual entity. - $entity = $entity->getNGEntity(); - // Sync the changes made in the fields array to the internal values array. $entity->updateOriginalValues(); diff --git a/core/modules/shortcut/shortcut.module b/core/modules/shortcut/shortcut.module index 287b024..804b76b 100644 --- a/core/modules/shortcut/shortcut.module +++ b/core/modules/shortcut/shortcut.module @@ -470,8 +470,8 @@ function shortcut_preprocess_page(&$variables) { // Check if $link is already a shortcut and set $link_mode accordingly. foreach ($shortcut_set->links as $shortcut) { - if ($link == $shortcut['link_path']) { - $mlid = $shortcut['mlid']; + if ($link == $shortcut->getLinkPath()) { + $mlid = $shortcut->id(); break; } } diff --git a/core/modules/system/lib/Drupal/system/Controller/SystemController.php b/core/modules/system/lib/Drupal/system/Controller/SystemController.php index b27acf1..b5eef16 100644 --- a/core/modules/system/lib/Drupal/system/Controller/SystemController.php +++ b/core/modules/system/lib/Drupal/system/Controller/SystemController.php @@ -86,13 +86,13 @@ public function overview() { $menu_links = $menu_link_storage->loadMultiple($result); foreach ($menu_links as $item) { _menu_link_translate($item); - if (!$item['access']) { + if (!$item->getAccess()) { continue; } // The link description, either derived from 'description' in hook_menu() // or customized via menu module is used as title attribute. - if (!empty($item['localized_options']['attributes']['title'])) { - $item['description'] = $item['localized_options']['attributes']['title']; + if (!empty($item->localized_options->attributes['title'])) { + $item['description'] = $item->localized_options->attributes['title']; unset($item->localized_options->attributes['title']); } $block = array( @@ -111,7 +111,7 @@ public function overview() { // Prepare for sorting as in function _menu_tree_check_access(). // The weight is offset so it is always positive, with a uniform 5-digits. - $blocks[(50000 + $item['weight']) . ' ' . $item['title'] . ' ' . $item['mlid']] = $block; + $blocks[(50000 + $item->getWeight()) . ' ' . $item['title'] . ' ' . $item->id()] = $block; } } } diff --git a/core/modules/system/lib/Drupal/system/SystemManager.php b/core/modules/system/lib/Drupal/system/SystemManager.php index 5c12997..57d893f 100644 --- a/core/modules/system/lib/Drupal/system/SystemManager.php +++ b/core/modules/system/lib/Drupal/system/SystemManager.php @@ -209,16 +209,16 @@ public function getAdminBlock($item) { $menu_links = $this->menuLinkStorage->loadByProperties(array('plid' => $item['mlid'], 'menu_name' => $item['menu_name'], 'hidden' => 0)); foreach ($menu_links as $link) { _menu_link_translate($link); - if ($link['access']) { + if ($link->getAccess()) { // The link description, either derived from 'description' in // hook_menu() or customized via menu module is used as title attribute. - if (!empty($link['localized_options']['attributes']['title'])) { - $link['description'] = $link['localized_options']['attributes']['title']; - unset($link['localized_options']['attributes']['title']); + if (!empty($link->localized_options->attributes['title'])) { + $link['description'] = $link->localized_options->attributes['title']; + unset($link->localized_options->attributes['title']); } // Prepare for sorting as in function _menu_tree_check_access(). // The weight is offset so it is always positive, with a uniform 5-digits. - $key = (50000 + $link['weight']) . ' ' . Unicode::strtolower($link['title']) . ' ' . $link['mlid']; + $key = (50000 + $link->getWeight()) . ' ' . Unicode::strtolower($link['title']) . ' ' . $link->id(); $content[$key] = $link; } } diff --git a/core/modules/system/lib/Drupal/system/Tests/Menu/LinksTest.php b/core/modules/system/lib/Drupal/system/Tests/Menu/LinksTest.php index bcf7c96..b05f9e3 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Menu/LinksTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Menu/LinksTest.php @@ -246,19 +246,19 @@ public function testRouterIntegration() { 'link_path' => 'router_test/test1', )); $menu_link->save(); - $this->assertEqual($menu_link->route_name, 'router_test.1'); - $this->assertEqual($menu_link->route_parameters, array()); + $this->assertEqual($menu_link->getRouteName(), 'router_test.1'); + $this->assertEqual($menu_link->getRouteParams(), array()); $menu_link = entity_create('menu_link', array( 'link_path' => 'router_test/test3/test', )); $menu_link->save(); - $this->assertEqual($menu_link->route_name, 'router_test.3'); - $this->assertEqual($menu_link->route_parameters, array('value' => 'test')); + $this->assertEqual($menu_link->getRouteName(), 'router_test.3'); + $this->assertEqual($menu_link->getRouteParams(), 'test'); $menu_link = entity_load('menu_link', $menu_link->id()); - $this->assertEqual($menu_link->route_name, 'router_test.3'); - $this->assertEqual($menu_link->route_parameters, array('value' => 'test')); + $this->assertEqual($menu_link->getRouteName(), 'router_test.3'); + $this->assertEqual($menu_link->getRouteParams(), 'test'); } } diff --git a/core/modules/toolbar/toolbar.module b/core/modules/toolbar/toolbar.module index 3067945..94a9251 100644 --- a/core/modules/toolbar/toolbar.module +++ b/core/modules/toolbar/toolbar.module @@ -495,9 +495,9 @@ function toolbar_get_menu_tree() { if (!empty($result)) { $admin_link = menu_link_load(reset($result)); $tree = menu_build_tree('admin', array( - 'expanded' => array($admin_link['mlid']), - 'min_depth' => $admin_link['depth'] + 1, - 'max_depth' => $admin_link['depth'] + 1, + 'expanded' => array($admin_link->id()), + 'min_depth' => $admin_link->getDepth() + 1, + 'max_depth' => $admin_link->getDepth() + 1, )); } @@ -521,16 +521,14 @@ function toolbar_menu_navigation_links(&$tree) { } // Make sure we have a path specific ID in place, so we can attach icons // and behaviors to the items. - $l_options = $tree[$key]['link']['localized_options']; - $l_options['attributes'] = array( - 'id' => 'toolbar-link-' . str_replace(array('/', '<', '>'), array('-', '', ''), $item['link']['link_path']), + $l_options = $tree[$key]['link']->localized_options->attributes = array( + 'id' => 'toolbar-link-' . str_replace(array('/', '<', '>'), array('-', '', ''), $item['link']->getLinkPath()), 'class' => array( 'toolbar-icon', - 'toolbar-icon-' . strtolower(str_replace(' ', '-', $item['link']['link_title'])), + 'toolbar-icon-' . strtolower(str_replace(' ', '-', $item['link']->getLinkTitle())), ), 'title' => check_plain($item['link']['description']), ); - $tree[$key]['link']['localized_options'] = $l_options; } } @@ -542,16 +540,17 @@ function toolbar_get_rendered_subtrees() { $tree = toolbar_get_menu_tree(); foreach ($tree as $tree_item) { $item = $tree_item['link']; - if (!$item['hidden'] && $item['access']) { - if ($item['has_children']) { + if (!$item->isHidden() && $item->getAccess()) { + if ($item->hasChildren()) { $query = db_select('menu_links'); $query->addField('menu_links', 'mlid'); $query->condition('has_children', 1); - for ($i=1; $i <= $item['depth']; $i++) { - $query->condition('p' . $i, $item['p' . $i]); + for ($i=1; $i <= $item->getDepth(); $i++) { + $p_i = 'p' . $i; + $query->condition('p' . $i, $item->{$p_i}->value); } $parents = $query->execute()->fetchCol(); - $subtree = menu_build_tree($item['menu_name'], array('expanded' => $parents, 'min_depth' => $item['depth']+1)); + $subtree = menu_build_tree($item->getMenuName(), array('expanded' => $parents, 'min_depth' => $item->getDepth()+1)); toolbar_menu_navigation_links($subtree); $subtree = menu_tree_output($subtree); $subtree = drupal_render($subtree);