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..a269495 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. + * Defines an 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(); @@ -98,7 +110,8 @@ public function isDeletable(); * Returns a URL object containing either the external path or route. * * @param bool $title_attribute - * If TRUE, add the link description (if present) as the title attribute. + * (optional) If TRUE, add the link description as the title attribute if + * the description is not empty. * * @return \Drupal\Core\Url * A a URL object containing either the external path or route. @@ -125,10 +138,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 +149,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::updateDefinition(). * * @param array $new_definition_values * The new values for the link definition. This will usually be just a @@ -161,13 +171,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::removeDefinition(). * - * 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 +189,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 +198,33 @@ 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 (e.g. when the link is not deletable). */ 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 if there is + * no route because there is no custom edit route for this instance. */ 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 (e.g. when the link is not translatable). */ public function getTranslateRoute(); diff --git a/core/lib/Drupal/Core/Menu/MenuLinkManager.php b/core/lib/Drupal/Core/Menu/MenuLinkManager.php index 33521fc..0b27be2 100644 --- a/core/lib/Drupal/Core/Menu/MenuLinkManager.php +++ b/core/lib/Drupal/Core/Menu/MenuLinkManager.php @@ -25,7 +25,12 @@ class MenuLinkManager implements MenuLinkManagerInterface { /** - * {@inheritdoc} + * Provides some default values for the definition of all menu link plugins. + * + * @todo Decide how to keep these field definitions in sync. + * https://www.drupal.org/node/2302085 + * + * @var array */ protected $defaults = array( // (required) The name of the menu for this link. @@ -119,19 +124,27 @@ public function __construct(MenuTreeStorageInterface $tree_storage, StaticMenuLi * By default we add defaults for the type to the definition. If a type has * additional processing logic they can do that by replacing or extending the * method. + * + * @param array $definition + * The definition to be processed and modified by reference. + * @param $plugin_id + * The ID of the plugin this definition is being used for. */ - protected function processDefinition(&$definition, $plugin_id) { + protected function processDefinition(array &$definition, $plugin_id) { $definition = NestedArray::mergeDeep($this->defaults, $definition); $definition['parent'] = (string) $definition['parent']; $definition['id'] = $plugin_id; } /** - * Instantiate if necessary and return a YamlDiscovery instance. + * Instantiates if necessary and returns a YamlDiscovery instance. * * Since the discovery is very rarely used - only when the rebuild() method * is called - it's instantiated only when actually needed instead of in the * constructor. + * + * @return \Drupal\Core\Plugin\Discovery\ContainerDerivativeDiscoveryDecorator + * A plugin discovery instance. */ protected function getDiscovery() { if (empty($this->discovery)) { @@ -199,10 +212,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,30 +239,31 @@ 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. + * Deletes a specific instance. + * + * @param \Drupal\Core\Menu\MenuLinkInterface $instance + * The plugin instance to be deleted. + * @param bool $persist + * If TRUE, calls MenuLinkInterface::deleteLink() on the instance. + * + * @throws \Drupal\Component\Plugin\Exception\PluginException + * If the plugin instance does not support deletion. */ protected function deleteInstance(MenuLinkInterface $instance, $persist) { $id = $instance->getPluginId(); @@ -259,7 +281,7 @@ protected function deleteInstance(MenuLinkInterface $instance, $persist) { /** * {@inheritdoc} */ - public function deleteLink($id, $persist = TRUE) { + public function removeDefinition($id, $persist = TRUE) { $definition = $this->treeStorage->load($id); // It's possible the definition has already been deleted, or doesn't exist. if ($definition) { @@ -317,11 +339,12 @@ 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. + public function addDefinition($id, array $definition) { + 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); @@ -330,7 +353,7 @@ public function createLink($id, array $definition) { /** * {@inheritdoc} */ - public function updateLink($id, array $new_definition_values, $persist = TRUE) { + public function updateDefinition($id, array $new_definition_values, $persist = TRUE) { $instance = $this->createInstance($id); if ($instance) { $new_definition_values['id'] = $id; diff --git a/core/lib/Drupal/Core/Menu/MenuLinkManagerInterface.php b/core/lib/Drupal/Core/Menu/MenuLinkManagerInterface.php index 94e565d..f6757a7 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 creating menu links and storing their definitions. */ 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. @@ -28,54 +34,59 @@ public function rebuild(); public function deleteLinksInMenu($menu_name); /** - * Deletes a single link from the menu tree. + * Removes a single link definition from the menu tree storage. + * + * This is used for plugins not found through discovery to remove definitions. * * @param string $id * 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); + public function removeDefinition($id, $persist = TRUE); /** - * Load multiple plugin instances based on route. + * Loads multiple plugin instances based on route. * * @param string $route_name * The route name. * @param array $route_parameters - * (optional) The route parameters, defaults to an empty array. + * (optional) The route parameters. Defaults to an empty array. * @param string $menu_name * (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. + * Adds a new menu link definition to the menu 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 + * used for plugins not found through discovery to add new definitions. * * @param string $id - * The menu link plugin ID. + * The plugin ID for the new menu link definition that is being added. * @param array $definition - * The values of the link. + * The values of the link definition. * * @return \Drupal\Core\Menu\MenuLinkInterface - * The updated menu link instance. + * A plugin instance created using the newly added definition. + * + * @throws \Drupal\Component\Plugin\Exception\PluginException + * Thrown when the $id is not valid or is an already existing plugin ID. */ - public function createLink($id, array $definition); + public function addDefinition($id, array $definition); /** - * Updates the values for a menu link in the tree storage. + * Updates the values for a menu link definition in the menu tree storage. * * @param string $id * The menu link plugin ID. @@ -83,17 +94,17 @@ public function createLink($id, array $definition); * The new values for the link definition. This will usually be just a * subset of the plugin definition. * @param bool $persist - * TRUE to also have the link instance itself persist the changed values - * to any additional storage by invoking MenuLinkInterface::updateLink() on + * TRUE to also have the link instance itself persist the changed values to + * any additional storage by invoking MenuLinkInterface::updateDefinition() on * the plugin that is being updated. * * @return \Drupal\Core\Menu\MenuLinkInterface - * The updated menu link instance. + * A plugin instance created using the updated definition. * * @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); + public function updateDefinition($id, array $new_definition_values, $persist = TRUE); /** * Resets the values for a menu link based on the values found by discovery. @@ -105,8 +116,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 +125,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 +165,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 d8adb40..277b43c 100644 --- a/core/lib/Drupal/Core/Menu/MenuTreeParameters.php +++ b/core/lib/Drupal/Core/Menu/MenuTreeParameters.php @@ -17,17 +17,18 @@ * 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 { /** * A menu link plugin ID that should be used as the root. * - * By default the "real" root (@code '' @encode) of a menu is used. But, when - * only the descendants (subtree) of a certain menu link are needed, a custom - * root can be specified. + * By default the root ID of empty string '' is used. However, when only the + * descendants (subtree) of a certain menu link are needed, a custom root can + * be specified. * * @var string */ @@ -85,7 +86,8 @@ class MenuTreeParameters { * Sets a root; loads a menu tree with this menu link plugin ID as root. * * @param string $root - * A menu link plugin ID, or @code '' @endcode to use the "real" root. + * A menu link plugin ID, or empty string '' to use the root of the whole + * tree. * * @return $this * @@ -165,8 +167,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 +207,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 normal root ID is the empty string, '', which 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 1c94d54..0382f0e 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(); } @@ -195,20 +197,15 @@ public function rebuild(array $definitions) { * * @param array $ids * An array of menu link IDs. - * @param bool $prevent_reparenting - * (optional) Disables the re-parenting logic from the deletion process. - * Defaults to FALSE. */ - protected function purgeMultiple(array $ids, $prevent_reparenting = FALSE) { - if (!$prevent_reparenting) { - $loaded = $this->loadFullMultiple($ids); - foreach ($loaded as $id => $link) { - if ($link['has_children']) { - $children = $this->loadByProperties(array('parent' => $id)); - foreach ($children as $child) { - $child['parent'] = $link['parent']; - $this->save($child); - } + protected function purgeMultiple(array $ids) { + $loaded = $this->loadFullMultiple($ids); + foreach ($loaded as $id => $link) { + if ($link['has_children']) { + $children = $this->loadByProperties(array('parent' => $id)); + foreach ($children as $child) { + $child['parent'] = $link['parent']; + $this->save($child); } } } @@ -227,7 +224,8 @@ protected function purgeMultiple(array $ids, $prevent_reparenting = FALSE) { * A prepared statement, or NULL if the query is not valid. * * @throws \Exception - * If the table could not be created or the database connection failed. + * Thrown if the table could not be created or the database connection + * failed. */ protected function safeExecuteSelect(SelectInterface $query) { try { @@ -254,25 +252,27 @@ 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. + * A definition, according to $definitionFields, 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(); @@ -309,7 +309,7 @@ protected function doSave(array $link) { } /** - * Using the link definition, but up all the fields needed for database save. + * Fills in all the fields the database save needs, using the link definition. * * @param array $link * The link definition to be updated. @@ -372,10 +372,11 @@ protected function preSave(array &$link, array $original) { // Otherwise, ensure that this link's depth is not beyond the maximum depth // and fill parents based on the parent link. else { - // @todo - we want to also check $original['has_children'] here, but that + // @todo We want to also check $original['has_children'] here, but that // 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; } @@ -514,7 +515,7 @@ protected function moveChildren($fields, $original) { if ($shift > 0) { // The order of expressions must be reversed so the new values don't // overwrite the old ones before they can be used because "Single-table - // UPDATE assignments are generally evaluated from left to right" + // UPDATE assignments are generally evaluated from left to right". // @see http://dev.mysql.com/doc/refman/5.0/en/update.html $expressions = array_reverse($expressions); } @@ -536,11 +537,12 @@ protected function moveChildren($fields, $original) { * Loads the parent definition if it exists. * * @param array $link - * The link definition to check. - * @param array|FALSE $original - * The original link, or FALSE. + * The link definition to find the parent of. + * @param array|false $original + * The original link that might be used to find the parent if the parent + * is not set on the $link, or FALSE if the original could not be loaded. * - * @return array|FALSE + * @return array|false * Returns a definition array, or FALSE if no parent was found. */ protected function findParent($link, $original) { @@ -571,7 +573,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,12 +599,13 @@ 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. * @param bool $intersect * If TRUE, filter out values that are not part of the actual definition. + * * @return array * The prepared link data. */ @@ -621,7 +624,8 @@ protected function prepareLink(array $link, $intersect = FALSE) { * {@inheritdoc} */ public function loadByProperties(array $properties) { - // @todo - only allow loading by plugin definition 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 +645,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()); @@ -727,8 +732,9 @@ protected function loadFullMultiple(array $ids) { */ 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. + // @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 +744,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(); @@ -749,8 +755,8 @@ public function getRootPathIds($id) { * {@inheritdoc} */ public function getExpanded($menu_name, array $parents) { - // @todo - go back to tracking in state or some other way - // which menus have expanded links? + // @todo Go back to tracking in state or some other way which menus have + // expanded links? https://www.drupal.org/node/2302187 do { $query = $this->connection->select($this->table, $this->options); $query->fields($this->table, array('id')); @@ -768,9 +774,15 @@ 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) { - if (!empty($links[$id]['parent']) && empty($links[$links[$id]['parent']])) { // Invalid parent ID, so remove it. $links[$id]['parent'] = ''; @@ -794,8 +806,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 +832,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 in + * MenuTreeStorage::doBuildTreeData(). * * @return array * A flat array of menu links that are part of the menu. Each array element @@ -837,7 +848,7 @@ protected function loadLinks($menu_name, MenuTreeParameters $parameters) { $query->fields($this->table); // Allow a custom root to be specified for loading a menu link tree. If - // ommitted, the default root (i.e. the actual root, '') is used. + // omitted, the default root (i.e. the actual root, '') is used. if ($parameters->root !== '') { $root = $this->loadFull($parameters->root); @@ -924,7 +935,7 @@ protected function loadLinks($menu_name, MenuTreeParameters $parameters) { * @param array $tree * The menu tree you wish to operate on. * @param array $definitions - * An array to accumulate definitions. + * An array to accumulate definitions by reference. * * @return array * Array of route names, with all values being unique. @@ -934,12 +945,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. - * @param array &$definitions - * The collected definitions. + * A menu link tree from MenuTreeStorage::doBuildTreeData() + * @param array $definitions + * The collected definitions which are populated by reference. * * @return array * The collected route names. @@ -1054,9 +1065,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 - * depth-first. - * See ::loadTreeData() for a sample query. + * the fields from the $this->table. This array must be ordered + * depth-first. MenuTreeStorage::loadTreeData() includes 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 +1076,8 @@ protected function doBuildTreeData(array $links, array $parents = array(), $dept * * @return array * The fully built tree. + * + * @see \Drupal\Core\Menu\MenuTreeStorage::loadTreeData() */ protected function treeDataRecursive(array &$links, array $parents, $depth) { $tree = array(); @@ -1126,7 +1139,10 @@ protected function ensureTableExists() { } /** - * Helper function to determine serialized fields. + * Determines serialized fields in the storage. + * + * @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 +1158,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 +1169,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( @@ -1380,7 +1402,8 @@ protected static function schemaDefinition() { 'p8', 'p9', ), - // @todo - test this index for effectiveness. + // @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..0deff75 100644 --- a/core/lib/Drupal/Core/Menu/MenuTreeStorageInterface.php +++ b/core/lib/Drupal/Core/Menu/MenuTreeStorageInterface.php @@ -7,6 +7,9 @@ namespace Drupal\Core\Menu; +/** + * Defines an interface for the menu tree storage. + */ interface MenuTreeStorageInterface { /** @@ -18,7 +21,7 @@ public function maxDepth(); /** - * Helper function for testing. Clears all definitions cached in memory. + * Clears all definitions cached in memory. */ public function resetDefinitions(); @@ -32,7 +35,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 +45,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 +56,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); @@ -65,7 +67,7 @@ public function loadMultiple(array $ids); * The properties to filter by. * * @return array - * An array of menu link definitions. + * An array of menu link definition arrays. */ public function loadByProperties(array $properties); @@ -75,7 +77,7 @@ public function loadByProperties(array $properties); * @param string $route_name * The route name. * @param array $route_parameters - * (optional) The route parameters, defaults to an empty array. + * (optional) The route parameters. Defaults to an empty array. * @param string $menu_name * (optional) Restricts the found links to just those in the named menu. * @@ -91,14 +93,14 @@ 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. + * 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 - * would cause the links children to be moved to greater than the maximum - * depth. + * 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. */ public function save(array $definition); @@ -119,9 +121,9 @@ public function delete($id); * * The tree order is maintained using an optimized algorithm, for example by * storing each parent in an individual field, see - * http://drupal.org/node/141866 for more details. However, any details - * of the storage should not be relied upon since it may be swapped with - * a different implementation. + * http://drupal.org/node/141866 for more details. However, any details of the + * storage should not be relied upon since it may be swapped with a different + * implementation. * * @param string $menu_name * The name of the menu. @@ -138,9 +140,9 @@ public function loadTreeData($menu_name, MenuTreeParameters $parameters); /** * Loads all the visible menu links that are below the given ID. * - * The returned links are not ordered, and visible children will be - * included even if they have a hidden parent or ancestor so would not - * normally appear in a rendered tree. + * The returned links are not ordered, and visible children will be included + * even if they have a hidden parent or ancestor so would not normally appear + * in a rendered tree. * * @param string $id * The parent menu link ID. @@ -171,7 +173,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: @@ -189,13 +192,13 @@ public function loadSubtreeData($id, $max_relative_depth = NULL); * @return array * An associative array of IDs with keys equal to values that represents the * path from the given ID to the root of the tree. If $id is an ID that - * exists, the returned array will at least include it. An empty array - * is returned if the ID does not exist in the storage. + * exists, the returned array will at least include it. An empty array is + * returned if the ID does not exist in the storage. */ public function getRootPathIds($id); /** - * Find expanded links in a menu given a set of possible parents. + * Finds expanded links in a menu given a set of possible parents. * * @param string $menu_name * The menu name. @@ -242,10 +245,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/StaticMenuLinkOverrides.php b/core/lib/Drupal/Core/Menu/StaticMenuLinkOverrides.php index 0c7a94b..991d277 100644 --- a/core/lib/Drupal/Core/Menu/StaticMenuLinkOverrides.php +++ b/core/lib/Drupal/Core/Menu/StaticMenuLinkOverrides.php @@ -10,7 +10,7 @@ use Drupal\Core\Config\ConfigFactoryInterface; /** - * Implementation of the menu link override using a config file. + * Defines an implementation of the menu link override using a config file. */ class StaticMenuLinkOverrides implements StaticMenuLinkOverridesInterface { @@ -46,7 +46,7 @@ public function __construct(ConfigFactoryInterface $config_factory) { } /** - * Helper function to get the config object. + * Gets the configuration object when needed. * * Since this service is injected into all static menu link objects, but * only used when updating one, avoid actually loading the config when it's @@ -146,7 +146,8 @@ public function saveOverride($id, array $definition) { * Encodes the ID by replacing dots with double underscores. * * This is done because config schema uses dots for its internal type - * hierarchy. + * hierarchy. Double underscores are converted to triple underscores to + * avoid accidental conflicts. * * @param string $id * The menu plugin ID. @@ -155,7 +156,7 @@ public function saveOverride($id, array $definition) { * The menu plugin ID with double underscore instead of dots. */ protected static function encodeId($id) { - return str_replace('.', '__', $id); + return strtr($id, array('.' => '__', '__' => '___')); } } diff --git a/core/lib/Drupal/Core/Menu/StaticMenuLinkOverridesInterface.php b/core/lib/Drupal/Core/Menu/StaticMenuLinkOverridesInterface.php index 5f0549b..3d7b4d5 100644 --- a/core/lib/Drupal/Core/Menu/StaticMenuLinkOverridesInterface.php +++ b/core/lib/Drupal/Core/Menu/StaticMenuLinkOverridesInterface.php @@ -13,7 +13,8 @@ interface StaticMenuLinkOverridesInterface { /** - * Force all overrides to be re-loaded from storage. Useful for testing. + * Forces all overrides to be reloaded from config storage to compare the + * override value with the value submitted during test form submission. */ public function reload(); @@ -30,6 +31,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..ae84e07 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->updateDefinition($this->getPluginId(), $this->getPluginDefinition(), FALSE); } } else { - $menu_link_manager->createLink($this->getPluginId(), $this->getMenuDefinition()); + $menu_link_manager->addDefinition($this->getPluginId(), $this->getPluginDefinition()); } } @@ -247,7 +247,7 @@ public static function preDelete(EntityStorageInterface $storage, array $entitie foreach ($entities as $menu_link) { /** @var \Drupal\menu_link_content\Entity\MenuLinkContent $menu_link */ - $menu_link_manager->deleteLink($menu_link->getPluginId(), FALSE); + $menu_link_manager->removeDefinition($menu_link->getPluginId(), FALSE); } } @@ -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..d64bab9 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. @@ -44,10 +44,15 @@ public function getRouteName(); public function getRouteParameters(); /** - * Sets the route paramters of the custom menu link. + * Sets the route parameters of the custom menu link. * * @param array $route_parameters - * The route parameters + * The route parameters, usually derived from the path entered by the + * administrator. For example, for a link to a node with route 'node.view' + * the route needs the node ID as a parameter: + * @code + * array('node' => 2) + * @endcode * * @return $this */ @@ -63,7 +68,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 +84,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 +92,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 +102,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 +142,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(); }