diff --git a/core/lib/Drupal/Core/Menu/MenuLinkBase.php b/core/lib/Drupal/Core/Menu/MenuLinkBase.php index 9796b84..d376830 100644 --- a/core/lib/Drupal/Core/Menu/MenuLinkBase.php +++ b/core/lib/Drupal/Core/Menu/MenuLinkBase.php @@ -7,17 +7,19 @@ namespace Drupal\Core\Menu; +use Drupal\Component\Plugin\Exception\PluginException; use Drupal\Core\Plugin\PluginBase; use Drupal\Core\Url; -use Drupal\Component\Plugin\Exception\PluginException; /** - * Base class used for MenuLink plugins. + * Defines a base menu link class. */ abstract class MenuLinkBase extends PluginBase implements MenuLinkInterface { /** - * Defines the list of definition values where an override is allowed. + * The list of definition values where an override is allowed. + * + * The keys are definition names. The values are ignored. * * @var array */ @@ -99,7 +101,7 @@ public function isResetable() { * {@inheritdoc} */ public function isTranslatable() { - return FALSE; + return (bool) $this->getTranslateRoute(); } /** diff --git a/core/lib/Drupal/Core/Menu/MenuLinkDefault.php b/core/lib/Drupal/Core/Menu/MenuLinkDefault.php index 5cd52d2..24cf8d2 100644 --- a/core/lib/Drupal/Core/Menu/MenuLinkDefault.php +++ b/core/lib/Drupal/Core/Menu/MenuLinkDefault.php @@ -11,7 +11,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface; /** - * Default object used for MenuLink plugins. + * Provides a default implementation for menu link plugins. */ class MenuLinkDefault extends MenuLinkBase implements ContainerFactoryPluginInterface { @@ -68,7 +68,7 @@ public static function create(ContainerInterface $container, array $configuratio */ public function isResetable() { // The link can be reset if it has an override. - return $this->staticOverride->loadOverride($this->getPluginId()); + return (bool) $this->staticOverride->loadOverride($this->getPluginId()); } /** diff --git a/core/lib/Drupal/Core/Menu/MenuLinkInterface.php b/core/lib/Drupal/Core/Menu/MenuLinkInterface.php index 64f99a2..a0f500c 100644 --- a/core/lib/Drupal/Core/Menu/MenuLinkInterface.php +++ b/core/lib/Drupal/Core/Menu/MenuLinkInterface.php @@ -11,7 +11,7 @@ use Drupal\Component\Plugin\DerivativeInspectionInterface; /** - * Default object used for LocalTaskPlugins. + * Interface for classes providing a type of menu link. */ interface MenuLinkInterface extends PluginInspectionInterface, DerivativeInspectionInterface { @@ -33,21 +33,33 @@ public function getTitle(); /** * Returns the description of the menu link. + * + * @return string + * The description of the menu link. */ public function getDescription(); /** * Returns the menu name of the menu link. + * + * @return string + * The menu name of the menu link. */ public function getMenuName(); /** * Returns the provider (module name) of the menu link. + * + * @return string + * The provider of the menu link. */ public function getProvider(); /** * Returns the plugin ID of the menu link's parent, or an empty string. + * + * @return string + * The parent plugin ID. */ public function getParent(); @@ -125,10 +137,10 @@ public function getMetaData(); * Returns whether the rendered link can be cached. * * The plugin class may make some or all of the data used in the Url object - * and build array dynamic. For example, it could include the current - * user name in the title, the current time in the description, or a - * destination query string. In addition the route parameters may - * be dynamic so an access check should be performed for each user. + * and build array dynamic. For example, it could include the current user + * name in the title, the current time in the description, or a destination + * query string. In addition the route parameters may be dynamic so an access + * check should be performed for each user. * * @return bool * TRUE if the link can be cached, FALSE otherwise. @@ -136,17 +148,14 @@ public function getMetaData(); public function isCacheable(); /** - * Updates and saves values for a menu link. - * - * The override is written depending on the implementation. - * Static links, for example, have a dedicated override storage service. + * Updates the definition values for a menu link. * * Depending on the implementation details of the class, not all definition - * values may be changed. For example, changes to the title of a static - * link will be discarded. + * values may be changed. For example, changes to the title of a static link + * will be discarded. * * In general, this method should not be called directly, but will be called - * automatically from MenuLinkTreeInterface::updateLink() + * automatically from MenuLinkManagerInterface::updateLink(). * * @param array $new_definition_values * The new values for the link definition. This will usually be just a @@ -161,13 +170,13 @@ public function isCacheable(); public function updateLink(array $new_definition_values, $persist); /** - * Delete a menu link. + * Deletes a menu link. * * In general, this method should not be called directly, but will be called - * automatically from MenuLinkTreeInterface::deleteLink() + * automatically from MenuLinkManagerInterface::deleteLink(). * - * This method will only delete the link from any additional storage, but - * not from the menu.link_tree service. + * This method will only delete the link from any additional storage, but not + * from the plugin.manager.menu.link service. * * @throws \Drupal\Component\Plugin\Exception\PluginException * If the link is not deletable. @@ -179,8 +188,8 @@ public function deleteLink(); * * To instantiate the form class, use an instance of the * \Drupal\Core\DependencyInjection\ClassResolverInterface, such as from the - * class_resolver service. Then call the setMenuLinkInstance() method - * on the form instance with the menu link plugin instance. + * class_resolver service. Then call the setMenuLinkInstance() method on the + * form instance with the menu link plugin instance. * * @return string * A class that implements \Drupal\Core\Menu\Form\MenuLinkFormInterface. @@ -188,30 +197,32 @@ public function deleteLink(); public function getFormClass(); /** - * Returns parameters for a delete link, or an empty value. + * Returns parameters for a delete link. * - * @return array - * Array with keys route_name and route_parameters + * @return array|null + * An array with keys route_name and route_parameters, or NULL if there is + * no route. */ public function getDeleteRoute(); /** - * Returns parameters for a custom edit link, or an empty value. + * Returns parameters for a custom edit link. * - * Plugins should return a value here if they have a special edit form, - * or if they need to define additional local tasks, local actions, etc. - * that are visible from the edit form. + * Plugins should return a value here if they have a special edit form, or if + * they need to define additional local tasks, local actions, etc. that are + * visible from the edit form. * - * @return array - * Array with keys route_name and route_parameters + * @return array|null + * An array with keys route_name and route_parameters, or NULL. */ public function getEditRoute(); /** - * Returns parameters for a translate link, or an empty value. + * Returns parameters for a translate link. * * @return array - * Array with keys route_name and route_parameters + * An array with keys route_name and route_parameters, or NULL if there is + * no route. */ public function getTranslateRoute(); diff --git a/core/lib/Drupal/Core/Menu/MenuLinkManager.php b/core/lib/Drupal/Core/Menu/MenuLinkManager.php index 9529f98..be5b6e1 100644 --- a/core/lib/Drupal/Core/Menu/MenuLinkManager.php +++ b/core/lib/Drupal/Core/Menu/MenuLinkManager.php @@ -199,10 +199,18 @@ public function hasDefinition($plugin_id) { } /** - * {@inheritdoc} + * Returns a pre-configured meu link plugin instance. + * + * @param string $plugin_id + * The ID of the plugin being instantiated. + * @param array $configuration + * An array of configuration relevant to the plugin instance. * * @return \Drupal\Core\Menu\MenuLinkInterface * A menu link instance. + * + * @throws \Drupal\Component\Plugin\Exception\PluginException + * If the instance cannot be created, such as if the ID is invalid. */ public function createInstance($plugin_id, array $configuration = array()) { return $this->factory->createInstance($plugin_id, $configuration); @@ -218,29 +226,25 @@ public function getInstance(array $options) { } /** - * Deletes all links for a menu. - * - * @todo This should really only be called as part of the flow of deleting a - * menu entity, so maybe we should load it and make sure it's not locked? - * - * @param string $menu_name - * The name of the menu whose links will be deleted. + * {@inheritdoc} */ public function deleteLinksInMenu($menu_name) { foreach ($this->treeStorage->loadByProperties(array('menu_name' => $menu_name)) as $plugin_id => $definition) { $instance = $this->createInstance($plugin_id); - if ($instance->isResetable()) { + if ($instance->isDeletable()) { + $this->deleteInstance($instance, TRUE); + } + elseif ($instance->isResetable()) { $new_instance = $this->resetInstance($instance); $affected_menus[$new_instance->getMenuName()] = $new_instance->getMenuName(); } - elseif ($instance->isDeletable()) { - $this->deleteInstance($instance, TRUE); - } } } /** * Helper function to delete a specific instance. + * + * @throws */ protected function deleteInstance(MenuLinkInterface $instance, $persist) { $id = $instance->getPluginId(); @@ -317,10 +321,11 @@ public function loadLinksByRoute($route_name, array $route_parameters = array(), * {@inheritdoc} */ public function createLink($id, array $definition) { - // Add defaults and other stuff, so there is no requirement to specify - // everything. + if ($this->treeStorage->load($id) || $id === '') { + throw new PluginException(sprintf('The ID %s already exists as a plugin definition or is not valid', $id)); + } + // Add defaults, so there is no requirement to specify everything. $this->processDefinition($definition, $id); - // Store the new link in the tree. $this->treeStorage->save($definition); return $this->createInstance($id); diff --git a/core/lib/Drupal/Core/Menu/MenuLinkManagerInterface.php b/core/lib/Drupal/Core/Menu/MenuLinkManagerInterface.php index 94e565d..c213fda 100644 --- a/core/lib/Drupal/Core/Menu/MenuLinkManagerInterface.php +++ b/core/lib/Drupal/Core/Menu/MenuLinkManagerInterface.php @@ -2,7 +2,7 @@ /** * @file - * Contains \Drupal\Core\Menu\MenuLinkTreeInterface. + * Contains \Drupal\Core\Menu\MenuLinkManagerInterface. */ namespace Drupal\Core\Menu; @@ -10,17 +10,23 @@ use Drupal\Component\Plugin\PluginManagerInterface; /** - * Defines an interface for creating menu links and retrieving menu link trees. + * Defines an interface for storing menu link definitions and creating menu links. */ interface MenuLinkManagerInterface extends PluginManagerInterface { /** - * Trigger discovery, save, and cleanup of static links. + * Triggers discovery, save, and cleanup of static links. */ public function rebuild(); /** - * Deletes or resets all links for a menu. + * Deletes all links having a certain menu name. + * + * If a link is not deletable but is resetable, the link will be reset to have + * its original menu name, under the assumption that the original menu is not + * the one we are deleting it from. Note that when resetting, if the original + * menu name is the same as the menu name passed to this method, the link will + * not be moved or deleted. * * @param string $menu_name * The name of the menu whose links will be deleted or reset. @@ -34,17 +40,17 @@ public function deleteLinksInMenu($menu_name); * The menu link plugin ID. * @param bool $persist * If TRUE, this method will attempt to persist the deletion from any - * external storage by invoking MenuLinkInterface::deleteLink() on - * the plugin that is being deleted. + * external storage by invoking MenuLinkInterface::deleteLink() on the + * plugin that is being deleted. * * @throws \Drupal\Component\Plugin\Exception\PluginException - * If the $id is not valid, existing, plugin ID or if the link cannot be - * deleted. + * Thrown if the $id is not a valid, existing, plugin ID or if the link + * cannot be deleted. */ public function deleteLink($id, $persist = TRUE); /** - * Load multiple plugin instances based on route. + * Loads multiple plugin instances based on route. * * @param string $route_name * The route name. @@ -54,15 +60,15 @@ public function deleteLink($id, $persist = TRUE); * (optional) Restricts the found links to just those in the named menu. * * @return \Drupal\Core\Menu\MenuLinkInterface[] - * An array of instances keyed by ID. + * An array of instances keyed by plugin ID. */ public function loadLinksByRoute($route_name, array $route_parameters = array(), $menu_name = NULL); /** * Adds a new link to the tree storage. * - * Use this function in case you know there is no entry in the tree. This is - * the case if you don't use plugin definition to fill in the tree. + * Use this function when you know there is no entry in the tree. This is + * typically used for plugins not found through discovery to fill in the tree. * * @param string $id * The menu link plugin ID. @@ -71,6 +77,9 @@ public function loadLinksByRoute($route_name, array $route_parameters = array(), * * @return \Drupal\Core\Menu\MenuLinkInterface * The updated menu link instance. + * + * @throws \Drupal\Component\Plugin\Exception\PluginException + * Thrown when the $id is not a valid or is not an existing plugin ID. */ public function createLink($id, array $definition); @@ -91,7 +100,7 @@ public function createLink($id, array $definition); * The updated menu link instance. * * @throws \Drupal\Component\Plugin\Exception\PluginException - * If the $id is not valid, existing, plugin ID. + * Thrown if the $id is not a valid, existing, plugin ID. */ public function updateLink($id, array $new_definition_values, $persist = TRUE); @@ -105,8 +114,8 @@ public function updateLink($id, array $new_definition_values, $persist = TRUE); * The menu link instance after being reset. * * @throws \Drupal\Component\Plugin\Exception\PluginException - * If the $id is not valid, existing, plugin ID or if the link cannot be - * reset. + * Thrown if the $id is not a valid, existing, plugin ID or if the link + * cannot be reset. */ public function resetLink($id); @@ -114,16 +123,20 @@ public function resetLink($id); * Counts the total number of menu links. * * @param string $menu_name - * (optional) The menu name to count by, defaults to NULL. + * (optional) The menu name to count by, defaults to all menus. + * + * @return int + * The number of menu links in the named menu, or in all menus if the + * menu name is NULL. */ public function countMenuLinks($menu_name = NULL); /** * Loads all parent link IDs of a given menu link. * - * This method is very similar to getActiveTrailIds() but allows the link - * to be specified rather than being discovered based on the menu name - * and request. This method is mostly useful for testing. + * This method is very similar to getActiveTrailIds() but allows the link to + * be specified rather than being discovered based on the menu name and + * request. This method is mostly useful for testing. * * @param string $id * The menu link plugin ID. @@ -150,7 +163,7 @@ public function getParentIds($id); public function getChildIds($id); /** - * Determine if any links use a given menu name. + * Determines if any links use a given menu name. * * @param string $menu_name * The menu name. diff --git a/core/lib/Drupal/Core/Menu/MenuTreeParameters.php b/core/lib/Drupal/Core/Menu/MenuTreeParameters.php index eaa641b..d6b6eaa 100644 --- a/core/lib/Drupal/Core/Menu/MenuTreeParameters.php +++ b/core/lib/Drupal/Core/Menu/MenuTreeParameters.php @@ -17,8 +17,9 @@ * a parent in the list will be included. * - which menu links are omitted, i.e. minimum and maximum depth * - * @todo Add getter methods and make all properties protected. - * @todo Define an interface instead of using the concrete class to type hint. + * @todo Add getter methods and make all properties protected and define an + * interface instead of using the concrete class to type hint. + * https://www.drupal.org/node/2302041 */ class MenuTreeParameters { @@ -165,8 +166,9 @@ public function setActiveTrail(array $active_trail) { * is a scalar. For more complex options, it is an array. The meaning of * each element in the array is dependent on the $operator. * @param string|NULL $operator - * The comparison operator, such as =, <, or >=. It also accepts more - * complex options such as IN, LIKE, or BETWEEN. + * (Optional) The comparison operator, such as =, <, or >=. It also accepts + * more complex options such as IN, LIKE, or BETWEEN. If NULL, defaults to + * the = operator. * * @return $this */ @@ -204,9 +206,10 @@ public function topLevelOnly() { * Excludes the root menu link from the tree. * * Note that this is only necessary when you specified a custom root, because - * the "real" root (@code '' @encode) is mapped to a non-existing menu link. - * Hence when loading a menu link tree without specifying a custom root, you - * will never get a root; the tree will start at the children. + * the "real" root is the empty string @code '' @endcode, so does not + * correspond to an actual menu link. Hence when loading a menu link tree + * without specifying a custom root the tree will start at the children even + * if this method has not been called. * * @return $this */ diff --git a/core/lib/Drupal/Core/Menu/MenuTreeStorage.php b/core/lib/Drupal/Core/Menu/MenuTreeStorage.php index be9e418..43b65c0 100644 --- a/core/lib/Drupal/Core/Menu/MenuTreeStorage.php +++ b/core/lib/Drupal/Core/Menu/MenuTreeStorage.php @@ -7,14 +7,14 @@ namespace Drupal\Core\Menu; -use Drupal\Core\Database\Connection; -use Drupal\Component\Utility\UrlHelper; -use Drupal\Core\Database\Query\SelectInterface; use Drupal\Component\Plugin\Exception\PluginException; -use Drupal\Core\Database\SchemaObjectExistsException; -use Drupal\Core\Database\Database; +use Drupal\Component\Utility\UrlHelper; use Drupal\Core\Cache\Cache; use Drupal\Core\Cache\CacheBackendInterface; +use Drupal\Core\Database\Connection; +use Drupal\Core\Database\Database; +use Drupal\Core\Database\Query\SelectInterface; +use Drupal\Core\Database\SchemaObjectExistsException; /** * Provides a tree storage using the database. @@ -69,7 +69,8 @@ class MenuTreeStorage implements MenuTreeStorageInterface { /** * List of plugin definition fields. * - * @todo Inject this from the plugin manager? + * @todo Decide how to keep these field definitions in sync. + * https://www.drupal.org/node/2302085 * * @var array */ @@ -186,7 +187,8 @@ public function rebuild(array $definitions) { // Invalidate any cache tagged with any menu name. Cache::invalidateTags(array('menu' => $affected_menus)); $this->resetDefinitions(); - // @todo This is probably unneeded. + // Every item in the cache bin should have one of the menu cache tags but it + // is not guaranteed, so invalidate everything in the bin. $this->menuCacheBackend->invalidateAll(); } @@ -254,25 +256,26 @@ public function save(array $link) { } /** - * Helper function for rebuild that saves a link without clearing caches. + * Saves a link without clearing caches. * * @param array $link * A definition for a \Drupal\Core\Menu\MenuLinkInterface plugin. * * @return array - * The names of the menus affected by the save operation (1 or 2). + * The menu names affected by the save operation (1 or 2 names). * * @throws \Exception - * If the storage back-end does not exist and could not be created. + * Thrown if the storage back-end does not exist and could not be created. * @throws \Drupal\Component\Plugin\Exception\PluginException - * If the definition is invalid - for example, if the specified parent + * Thrown if the definition is invalid - for example, if the specified parent * would cause the links children to be moved to greater than the maximum * depth. */ protected function doSave(array $link) { $original = $this->loadFull($link['id']); - // @todo Should we just return here if the link values match the original. - // values completely?. + // @todo Should we just return here if the link values match the original + // values completely? + // https://www.drupal.org/node/2302137 $affected_menus = array(); $transaction = $this->connection->startTransaction(); @@ -376,6 +379,7 @@ protected function preSave(array &$link, array $original) { // will be 0 even if there are children if those are hidden. // has_children is really just the rendering hint. So, we either need // to define another column (has_any_children), or do the extra query. + // https://www.drupal.org/node/2302149 if ($original) { $limit = $this->maxDepth() - $this->doFindChildrenRelativeDepth($original) - 1; } @@ -571,7 +575,7 @@ protected function findParent($link, $original) { } /** - * Set the has_children flag for the link's parent if it has visible children. + * Sets has_children for the link's parent if it has visible children. * * @param array $link * The link to get a parent ID from. @@ -597,7 +601,7 @@ protected function updateParentalStatus(array $link) { } /** - * Prepare a link by unserializing values and saving the definition. + * Prepares a link by unserializing values and saving the definition. * * @param array $link * The data loaded in the query. @@ -622,6 +626,7 @@ protected function prepareLink(array $link, $intersect = FALSE) { */ public function loadByProperties(array $properties) { // @todo Only allow loading by plugin definition properties. + https://www.drupal.org/node/2302165 $query = $this->connection->select($this->table, $this->options); $query->fields($this->table, $this->definitionFields()); foreach ($properties as $name => $value) { @@ -641,7 +646,8 @@ public function loadByRoute($route_name, array $route_parameters = array(), $men asort($route_parameters); // Since this will be urlencoded, it's safe to store and match against a // text field. - // @todo Does this make more sense than using the system path? + // @todo Standardize an efficient way to load by route name and parameters + // in place of system path. https://www.drupal.org/node/2302139 $param_key = $route_parameters ? UrlHelper::buildQuery($route_parameters) : ''; $query = $this->connection->select($this->table, $this->options); $query->fields($this->table, $this->definitionFields()); @@ -729,6 +735,7 @@ public function getRootPathIds($id) { $subquery = $this->connection->select($this->table, $this->options); // @todo Consider making this dynamic based on static::MAX_DEPTH or from the // schema if that is generated using static::MAX_DEPTH. + // https://www.drupal.org/node/2302043 $subquery->fields($this->table, array('p1', 'p2', 'p3', 'p4', 'p5', 'p6', 'p7', 'p8', 'p9')); $subquery->condition('id', $id); $result = current($subquery->execute()->fetchAll(\PDO::FETCH_ASSOC)); @@ -738,8 +745,8 @@ public function getRootPathIds($id) { $query->fields($this->table, array('id')); $query->orderBy('depth', 'DESC'); $query->condition('mlid', $ids, 'IN'); - // @todo Cache this result in memory if we find it's being used more than - // once per page load. + // @todo Cache this result in memory if we find it is being used more + // than once per page load. https://www.drupal.org/node/2302185 return $this->safeExecuteSelect($query)->fetchAllKeyed(0, 0); } return array(); @@ -750,7 +757,7 @@ public function getRootPathIds($id) { */ public function getExpanded($menu_name, array $parents) { // @todo Go back to tracking in state or some other way which menus have - // expanded links? + // expanded links? https://www.drupal.org/node/2302187 do { $query = $this->connection->select($this->table, $this->options); $query->fields($this->table, array('id')); @@ -768,6 +775,13 @@ public function getExpanded($menu_name, array $parents) { /** * Saves menu links recursively. + * + * @param string $id + * The definition ID. + * @param array $children + * An array of IDs of child links collected by parent ID. + * @param array $links + * An array of all definitions keyed by ID. */ protected function saveRecursive($id, &$children, &$links) { @@ -794,8 +808,7 @@ public function loadTreeData($menu_name, MenuTreeParameters $parameters) { // cache items. sort($parameters->expandedParents); sort($parameters->conditions); - // @todo May be able to skip hashing after https://drupal.org/node/2224847 - $tree_cid = "tree-data:$menu_name:" . hash('sha256', serialize($parameters)); + $tree_cid = "tree-data:$menu_name:" . serialize($parameters); $cache = $this->menuCacheBackend->get($tree_cid); if ($cache && isset($cache->data)) { $data = $cache->data; @@ -821,10 +834,10 @@ public function loadTreeData($menu_name, MenuTreeParameters $parameters) { * * @param string $menu_name * A menu name. - * @param MenuTreeParameters $parameters + * @param \Drupal\Core\Menu\MenuTreeParameters $parameters * The parameters to determine which menu links to be loaded into a tree. - * ::loadLinks() will set the absolute minimum depth, which is used - * ::doBuildTreeData(). + * This method will set the absolute minimum depth, which is used + * MenuTreeStorage::doBuildTreeData(). * * @return array * A flat array of menu links that are part of the menu. Each array element @@ -934,12 +947,12 @@ protected function collectRoutesAndDefinitions(array $tree, array &$definitions) } /** - * Recursive helper function to collect all the route names and definitions. + * Collects all the route names and definitions. * * @param array $tree - * The menu link tree. + * A menu link tree from MenuTreeStorage::doBuildTreeData() * @param array &$definitions - * The collected definitions. + * The collected definitions which are populated by reference. * * @return array * The collected route names. @@ -1054,9 +1067,9 @@ protected function doBuildTreeData(array $links, array $parents = array(), $dept * @param array $links * A flat array of menu links that are part of the menu. Each array element * is an associative array of information about the menu link, containing - * the fields from the {menu_tree} table. This array must be ordered + * the fields from the $this->table. This array must be ordered * depth-first. - * See ::loadTreeData() for a sample query. + * * @param array $parents * An array of the menu link ID values that are in the path from the current * page to the root of the menu tree. @@ -1065,6 +1078,8 @@ protected function doBuildTreeData(array $links, array $parents = array(), $dept * * @return array * The fully built tree. + * + * @see MenuTreeStorage::loadTreeData() for a sample query. */ protected function treeDataRecursive(array &$links, array $parents, $depth) { $tree = array(); @@ -1126,7 +1141,10 @@ protected function ensureTableExists() { } /** - * Helper function to determine serialized fields. + * Determines serialized fields. + * + * @return array + * A list of fields that are serialized in the database. */ protected function serializedFields() { // For now, build the list from the schema since it's in active development. @@ -1142,7 +1160,10 @@ protected function serializedFields() { } /** - * Helper function to determine fields that are part of the plugin definition. + * Determines fields that are part of the plugin definition. + * + * @return array + * The list of the subset of fields that are part of the plugin definition. */ protected function definitionFields() { return $this->definitionFields; @@ -1150,6 +1171,9 @@ protected function definitionFields() { /** * Defines the schema for the tree table. + * + * @return array + * The schema API definition for the SQL storage table. */ protected static function schemaDefinition() { $schema = array( @@ -1381,6 +1405,7 @@ protected static function schemaDefinition() { 'p9', ), // @todo Test this index for effectiveness. + // https://www.drupal.org/node/2302197 'menu_parent_expand_child' => array( 'menu_name', 'expanded', 'has_children', diff --git a/core/lib/Drupal/Core/Menu/MenuTreeStorageInterface.php b/core/lib/Drupal/Core/Menu/MenuTreeStorageInterface.php index 0de1fe6..1326d8b 100644 --- a/core/lib/Drupal/Core/Menu/MenuTreeStorageInterface.php +++ b/core/lib/Drupal/Core/Menu/MenuTreeStorageInterface.php @@ -32,7 +32,6 @@ public function resetDefinitions(); * @param array $definitions * The new menu link definitions. * - * @todo give this a better name. */ public function rebuild(array $definitions); @@ -43,7 +42,7 @@ public function rebuild(array $definitions); * The menu link plugin ID. * * @return array|FALSE - * Menu Link definition + * The plugin definition, or FALSE if no definition was found for the ID. */ public function load($id); @@ -54,7 +53,7 @@ public function load($id); * An array of plugin IDs. * * @return array - * An array of menu Link definitions. + * An array of plugin definition arrays. */ public function loadMultiple(array $ids); @@ -91,7 +90,7 @@ public function loadByRoute($route_name, array $route_parameters = array(), $men * A definition for a \Drupal\Core\Menu\MenuLinkInterface plugin. * * @return array - * The names of the menus affected by the save operation (1 or 2). + * The menu names affected by the save operation (1 or 2 names). * * @throws \Exception * If the storage back-end does not exist and could not be created. @@ -171,7 +170,8 @@ public function getAllChildIds($id); * @param string $id * The menu link plugin ID. * @param int $max_relative_depth - * The maximum depth of child menu links relative to the passed in. + * (optional) The maximum depth of child menu links relative to the passed + * in. Defaults to NULL, in which case the full subtree will be returned. * * @return array * An array with 2 elements: @@ -242,10 +242,11 @@ public function getMenuNames(); * Counts the total number of menu links in one menu or all menus. * * @param string $menu_name - * (optional) The menu name to count by, defaults to NULL. + * (optional) The menu name to count by, defaults to all menus. * * @return int - * The number of menu links. + * The number of menu links in the named menu, or in all menus if the + * menu name is NULL. */ public function countMenuLinks($menu_name = NULL); diff --git a/core/lib/Drupal/Core/Menu/StaticMenuLinkOverridesInterface.php b/core/lib/Drupal/Core/Menu/StaticMenuLinkOverridesInterface.php index 5f0549b..b9c825a 100644 --- a/core/lib/Drupal/Core/Menu/StaticMenuLinkOverridesInterface.php +++ b/core/lib/Drupal/Core/Menu/StaticMenuLinkOverridesInterface.php @@ -30,6 +30,7 @@ public function reload(); * - menu_name * - expanded * - hidden + * or NULL if there is no override for the given ID. */ public function loadOverride($id); diff --git a/core/modules/menu_link_content/menu_link_content.info.yml b/core/modules/menu_link_content/menu_link_content.info.yml index a82c890..5ea5cc7 100644 --- a/core/modules/menu_link_content/menu_link_content.info.yml +++ b/core/modules/menu_link_content/menu_link_content.info.yml @@ -1,6 +1,6 @@ -name: 'Menu Link Content' +name: 'Custom Menu Links' type: module -description: 'Allows administrators to create custom links' +description: 'Allows administrators to create custom menu links.' package: Core version: VERSION core: 8.x diff --git a/core/modules/menu_link_content/menu_link_content.module b/core/modules/menu_link_content/menu_link_content.module index 6648280..25dfb26 100644 --- a/core/modules/menu_link_content/menu_link_content.module +++ b/core/modules/menu_link_content/menu_link_content.module @@ -2,7 +2,7 @@ /** * @file - * Enables users to create menu link content. + * Allows administrators to create custom menu links. */ use Drupal\system\MenuInterface; diff --git a/core/modules/menu_link_content/src/Entity/MenuLinkContent.php b/core/modules/menu_link_content/src/Entity/MenuLinkContent.php index 9ac769f..8582179 100644 --- a/core/modules/menu_link_content/src/Entity/MenuLinkContent.php +++ b/core/modules/menu_link_content/src/Entity/MenuLinkContent.php @@ -188,7 +188,7 @@ public function getWeight() { * * @see \Drupal\Core\Menu\MenuLinkTree::$defaults */ - protected function getMenuDefinition() { + protected function getPluginDefinition() { $definition = array(); $definition['class'] = 'Drupal\menu_link_content\Plugin\Menu\MenuLinkContent'; $definition['menu_name'] = $this->getMenuName(); @@ -228,11 +228,11 @@ public function postSave(EntityStorageInterface $storage, $update = TRUE) { // When the entity is saved via a plugin instance, we should not call // the menu tree manager to update the definition a second time. if (!$this->insidePlugin) { - $menu_link_manager->updateLink($this->getPluginId(), $this->getMenuDefinition(), FALSE); + $menu_link_manager->updateLink($this->getPluginId(), $this->getPluginDefinition(), FALSE); } } else { - $menu_link_manager->createLink($this->getPluginId(), $this->getMenuDefinition()); + $menu_link_manager->createLink($this->getPluginId(), $this->getPluginDefinition()); } } @@ -315,7 +315,7 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { ->setDescription(t('The menu name. All links with the same menu name (such as "tools") are part of the same menu.')) ->setSetting('default_value', 'tools'); - // @todo use a link field in the end? see https://drupal.org/node/2235457 + // @todo Use a link field https://www.drupal.org/node/2302205. $fields['route_name'] = FieldDefinition::create('string') ->setLabel(t('Route name')) ->setDescription(t('The machine name of a defined Symfony Route this menu item represents.')); diff --git a/core/modules/menu_link_content/src/Entity/MenuLinkContentInterface.php b/core/modules/menu_link_content/src/Entity/MenuLinkContentInterface.php index 35a24a7..41391cd 100644 --- a/core/modules/menu_link_content/src/Entity/MenuLinkContentInterface.php +++ b/core/modules/menu_link_content/src/Entity/MenuLinkContentInterface.php @@ -15,7 +15,7 @@ interface MenuLinkContentInterface extends ContentEntityInterface { /** - * Flag this instance as being wrapped in a menu link plugin instance. + * Flags this instance as being wrapped in a menu link plugin instance. */ public function setInsidePlugin(); @@ -28,15 +28,15 @@ public function setInsidePlugin(); public function getTitle(); /** - * Gets the route name of the custom menu link. + * Gets the route name of the menu link. * * @return string|NULL - * Returns the route name, unless it is an internal link. + * Returns the route name, or NULL if it is an external link. */ public function getRouteName(); /** - * Gets the route parameters of the custom menu link. + * Gets the route parameters of the menu link content entity. * * @return array * The route parameters, or an empty array. @@ -63,7 +63,7 @@ public function setRouteParameters(array $route_parameters); public function getUrl(); /** - * Gets the url object pointing to the URL of the custom menu link. + * Gets the url object pointing to the URL of the menu link content entity. * * @return \Drupal\Core\Url * A Url object instance. @@ -79,7 +79,7 @@ public function getUrlObject(); public function getMenuName(); /** - * Gets the options for the custom menu link. + * Gets the options for the menu link content entity. * * @return array * The options that may be passed to the URL generator. @@ -87,7 +87,7 @@ public function getMenuName(); public function getOptions(); /** - * Sets the query options of the custom menu link. + * Sets the query options of the menu link content entity. * * @param array $options * The new option. @@ -97,10 +97,10 @@ public function getOptions(); public function setOptions(array $options); /** - * Gets the description of the custom menu link for the UI. + * Gets the description of the menu link for the UI. * * @return string - * The descption for use on admin pages or as a title attribute. + * The description to use on admin pages or as a title attribute. */ public function getDescription(); @@ -137,7 +137,7 @@ public function isExpanded(); public function getParentId(); /** - * Returns the weight of the custom menu link. + * Returns the weight of the menu link content entity. * * @return int * A weight for use when ordering links. diff --git a/core/modules/menu_link_content/src/MenuLinkContentAccessController.php b/core/modules/menu_link_content/src/MenuLinkContentAccessController.php index d895478..718e151 100644 --- a/core/modules/menu_link_content/src/MenuLinkContentAccessController.php +++ b/core/modules/menu_link_content/src/MenuLinkContentAccessController.php @@ -44,7 +44,7 @@ protected function checkAccess(EntityInterface $entity, $operation, $langcode, A * Returns the access manager. * * @return \Drupal\Core\Access\AccessManager - * The route provider. + * The access manager. */ protected function accessManager() { if (!$this->accessManager) { diff --git a/core/modules/menu_link_content/src/Plugin/Menu/MenuLinkContent.php b/core/modules/menu_link_content/src/Plugin/Menu/MenuLinkContent.php index 9c77e53..5781044 100644 --- a/core/modules/menu_link_content/src/Plugin/Menu/MenuLinkContent.php +++ b/core/modules/menu_link_content/src/Plugin/Menu/MenuLinkContent.php @@ -7,18 +7,25 @@ namespace Drupal\menu_link_content\Plugin\Menu; -use Drupal\Core\Plugin\ContainerFactoryPluginInterface; +use Drupal\Component\Plugin\Exception\PluginException; use Drupal\Core\Entity\EntityManagerInterface; use Drupal\Core\Language\LanguageManagerInterface; use Drupal\Core\Menu\MenuLinkBase; -use Drupal\Component\Plugin\Exception\PluginException; +use Drupal\Core\Plugin\ContainerFactoryPluginInterface; use Symfony\Component\DependencyInjection\ContainerInterface; /** - * Provides the menu link plugin for content menu link.s + * Provides the menu link plugin for content menu links. */ class MenuLinkContent extends MenuLinkBase implements ContainerFactoryPluginInterface { + /** + * Entities IDs to load. + * + * It is an array of entity IDs keyed by entity IDs. + * + * @var array + */ protected static $entityIdsToLoad = array(); /** @@ -78,6 +85,8 @@ public function __construct(array $configuration, $plugin_id, $plugin_definition if (!empty($this->pluginDefinition['metadata']['entity_id'])) { $entity_id = $this->pluginDefinition['metadata']['entity_id']; + // Builds a list of entity IDs to take advantage of the more efficient + // EntityStorageInterface::loadMultiple() in getEntity() at render time. static::$entityIdsToLoad[$entity_id] = $entity_id; } @@ -113,6 +122,8 @@ protected function getEntity() { $storage = $this->entityManager->getStorage('menu_link_content'); if (!empty($this->pluginDefinition['metadata']['entity_id'])) { $entity_id = $this->pluginDefinition['metadata']['entity_id']; + // Make sure the current ID is in the list, which may include multiple + // IDs added earlier in each plugin's constructor. static::$entityIdsToLoad[$entity_id] = $entity_id; $entities = $storage->loadMultiple(array_values(static::$entityIdsToLoad)); $entity = isset($entities[$entity_id]) ? $entities[$entity_id] : NULL; @@ -129,7 +140,9 @@ protected function getEntity() { } // Clone the entity object to avoid tampering with the static cache. $this->entity = clone $entity; - $this->entity = $this->entityManager->getTranslationFromContext($this->entity); + $the_entity = $this->entityManager->getTranslationFromContext($this->entity); + /** @var \Drupal\menu_link_content\Entity\MenuLinkContentInterface $the_entity */ + $this->entity = $the_entity; $this->entity->setInsidePlugin(); } return $this->entity; @@ -139,9 +152,9 @@ protected function getEntity() { * {@inheritdoc} */ public function getTitle() { - // We only need to get the title from the actual entity if it may be - // a translation based on the current language context. This can only - // happen if the site configured to be multilingual. + // We only need to get the title from the actual entity if it may be a + // translation based on the current language context. This can only happen + // if the site is configured to be multilingual. if ($this->langaugeManager->isMultilingual()) { return $this->getEntity()->getTitle(); } @@ -152,6 +165,9 @@ public function getTitle() { * {@inheritdoc} */ public function getDescription() { + // We only need to get the description from the actual entity if it may be a + // translation based on the current language context. This can only happen + // if the site is configured to be multilingual. if ($this->langaugeManager->isMultilingual()) { return $this->getEntity()->getDescription(); } @@ -182,12 +198,10 @@ public function getEditRoute() { * {@inheritdoc} */ public function getTranslateRoute() { - $entity_type = $this->getEntity()->getEntityType()->id(); + $entity_type = 'menu_link_content'; return array( 'route_name' => 'content_translation.translation_overview_' . $entity_type, - 'route_parameters' => array( - $entity_type => $this->getEntity()->id(), - ), + 'route_parameters' => array( $entity_type => $this->getEntity()->id()), ); } @@ -227,7 +241,6 @@ public function isTranslatable() { * {@inheritdoc} */ public function deleteLink() { - // @todo: Flag this call if possible so we don't call the menu tree manager. $this->getEntity()->delete(); }