diff --git a/core/includes/entity.api.php b/core/includes/entity.api.php index 8e60f00..1e7bad0 100644 --- a/core/includes/entity.api.php +++ b/core/includes/entity.api.php @@ -604,15 +604,54 @@ function hook_entity_field_info_alter(&$info, $entity_type) { } /** - * Alter entity operations. + * Declares operations for an entity. * + * @see \Drupal\Core\Entity\EntityDefaultOperationsController + * + * @param \Drupal\Core\Entity\EntityInterface $entity + * + * @return array + * The structure is identical to that of the return value of + * \Drupal\Core\Entity\EntityOperationsControllerInterface::getOperations(). + */ +function hook_entity_operations(\Drupal\Core\Entity\EntityInterface $entity) { + $uri = $entity->uri(); + $operations['translate'] = array( + 'title' => t('Translate'), + 'href' => $uri['path'] . '/translate', + 'weight' => 50, + ); + + return $operations; +} + +/** + * Declares operations for an entity of a specific type. + * + * @see \Drupal\Core\Entity\EntityDefaultOperationsController + * + * @param \Drupal\Core\Entity\EntityInterface $entity + * + * @return array + * The structure is identical to that of the return value of + * \Drupal\Core\Entity\EntityOperationsControllerInterface::getOperations(). + */ +function hook_ENTITY_TYPE_operations(\Drupal\Core\Entity\EntityInterface $entity) { + return array(); +} + +/** + * Alters entity operations. + * + * @see \Drupal\Core\Entity\EntityDefaultOperationsController + * + * @param \Drupal\Core\Entity\EntityInterface $entity + * The entity on which the linked operations will be performed. * @param array $operations * Operations array as returned by * \Drupal\Core\Entity\EntityStorageControllerInterface::getOperations(). - * @param \Drupal\Core\Entity\EntityInterface $entity - * The entity on which the linked operations will be performed. */ -function hook_entity_operation_alter(array &$operations, \Drupal\Core\Entity\EntityInterface $entity) { +function hook_entity_operations_alter(\Drupal\Core\Entity\EntityInterface $entity, array &$operations) { $uri = $entity->uri(); $operations['translate'] = array( 'title' => t('Translate'), @@ -622,6 +661,20 @@ function hook_entity_operation_alter(array &$operations, \Drupal\Core\Entity\Ent } /** + * Alters entity operations for a specific entity type. + * + * @see \Drupal\Core\Entity\EntityDefaultOperationsController + * + * @param \Drupal\Core\Entity\EntityInterface $entity + * The entity on which the linked operations will be performed. + * @param array $operations + * Operations array as returned by + * \Drupal\Core\Entity\EntityStorageControllerInterface::getOperations(). + */ +function hook_ENTITY_TYPE_operations_alter(\Drupal\Core\Entity\EntityInterface $entity, array &$operations) { +} + +/** * Control access to fields. * * This hook is invoked from \Drupal\Core\Entity\Field\Field::access() to diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigEntityListController.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityListController.php index 0eb187a..54d62a8 100644 --- a/core/lib/Drupal/Core/Config/Entity/ConfigEntityListController.php +++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityListController.php @@ -24,40 +24,4 @@ public function load() { return $entities; } - /** - * {@inheritdoc} - */ - public function getOperations(EntityInterface $entity) { - $operations = parent::getOperations($entity); - $uri = $entity->uri(); - - // Ensure the edit operation exists since it is access controlled. - if (isset($operations['edit'])) { - // For configuration entities edit path is the MENU_DEFAULT_LOCAL_TASK and - // therefore should be accessed by the short route. - $operations['edit']['href'] = $uri['path']; - } - - if (isset($this->entityInfo['entity_keys']['status'])) { - if (!$entity->status()) { - $operations['enable'] = array( - 'title' => t('Enable'), - 'href' => $uri['path'] . '/enable', - 'options' => $uri['options'], - 'weight' => -10, - ); - } - else { - $operations['disable'] = array( - 'title' => t('Disable'), - 'href' => $uri['path'] . '/disable', - 'options' => $uri['options'], - 'weight' => 40, - ); - } - } - - return $operations; - } - } diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigEntityOperationsController.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityOperationsController.php new file mode 100644 index 0000000..00431f4 --- /dev/null +++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityOperationsController.php @@ -0,0 +1,47 @@ +uri(); + if ($entity instanceof ConfigEntityInterface) { + if (!$entity->status()) { + $operations['enable'] = array( + 'title' => t('Enable'), + 'href' => $uri['path'] . '/enable', + 'options' => $uri['options'], + 'weight' => -10, + ); + } + else { + $operations['disable'] = array( + 'title' => t('Disable'), + 'href' => $uri['path'] . '/disable', + 'options' => $uri['options'], + 'weight' => 20, + ); + } + } + + return $operations; + } + +} diff --git a/core/lib/Drupal/Core/Entity/EntityDefaultOperationsController.php b/core/lib/Drupal/Core/Entity/EntityDefaultOperationsController.php new file mode 100644 index 0000000..82559c8 --- /dev/null +++ b/core/lib/Drupal/Core/Entity/EntityDefaultOperationsController.php @@ -0,0 +1,85 @@ +moduleHandler = $module_handler; + } + + /** + * {@inheritdoc} + */ + public static function createInstance(ContainerInterface $container, $entity_type, array $entity_info) { + return new static($container->get('module_handler')); + } + + /** + * {@inheritdoc} + */ + public function getOwnOperations(EntityInterface $entity) { + $uri = $entity->uri(); + $operations = array(); + $operations['edit'] = array( + 'title' => t('Edit'), + 'href' => $uri['path'] . '/edit', + 'options' => $uri['options'], + 'weight' => 10, + ); + $operations['delete'] = array( + 'title' => t('Delete'), + 'href' => $uri['path'] . '/delete', + 'options' => $uri['options'], + 'weight' => 100, + ); + return $operations; + } + + /** + * {@inheritdoc} + */ + public function getOperations(EntityInterface $entity) { + // Collect all operations. + $operations = $this->getOwnOperations($entity); + $hooks = array($entity->entityType() . '_operations' , 'entity_operations'); + foreach ($hooks as $hook) { + $operations = array_merge($operations, $this->moduleHandler->invokeAll($hook, $entity)); + } + + // Check whether the operations are accessible. + foreach ($operations as $key => $operation) { + if (!$entity->access($key)) { + unset($operations[$key]); + } + } + + $this->moduleHandler->alter(array('entity_operations', $entity->entityType() . '_operations'), $entity, $operations); + + return $operations; + } +} diff --git a/core/lib/Drupal/Core/Entity/EntityListController.php b/core/lib/Drupal/Core/Entity/EntityListController.php index 3b1b580..b6e3da4 100644 --- a/core/lib/Drupal/Core/Entity/EntityListController.php +++ b/core/lib/Drupal/Core/Entity/EntityListController.php @@ -32,6 +32,13 @@ class EntityListController implements EntityListControllerInterface, EntityContr protected $moduleHandler; /** + * The entity operations controller class. + * + * @var \Drupal\Core\Entity\EntityOperationsControllerInterface + */ + protected $operations; + + /** * The entity type name. * * @var string @@ -62,6 +69,7 @@ public static function createInstance(ContainerInterface $container, $entity_typ $entity_type, $entity_info, $container->get('entity.manager')->getStorageController($entity_type), + $container->get('entity.manager')->getOperationsController($entity_type), $container->get('module_handler') ); } @@ -77,10 +85,14 @@ public static function createInstance(ContainerInterface $container, $entity_typ * The entity storage controller class. * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler * The module handler to invoke hooks on. + * @param \Drupal\Core\Entity\EntityOperationsControllerInterface $operations + * The entity operations controller class. + */ - public function __construct($entity_type, array $entity_info, EntityStorageControllerInterface $storage, ModuleHandlerInterface $module_handler) { + public function __construct($entity_type, array $entity_info, EntityStorageControllerInterface $storage, EntityOperationsControllerInterface $operations, ModuleHandlerInterface $module_handler) { $this->entityType = $entity_type; $this->storage = $storage; + $this->operations = $operations; $this->entityInfo = $entity_info; $this->moduleHandler = $module_handler; } @@ -116,27 +128,7 @@ protected function getLabel(EntityInterface $entity) { * {@inheritdoc} */ public function getOperations(EntityInterface $entity) { - $uri = $entity->uri(); - - $operations = array(); - if ($entity->access('update')) { - $operations['edit'] = array( - 'title' => t('Edit'), - 'href' => $uri['path'] . '/edit', - 'options' => $uri['options'], - 'weight' => 10, - ); - } - if ($entity->access('delete')) { - $operations['delete'] = array( - 'title' => t('Delete'), - 'href' => $uri['path'] . '/delete', - 'options' => $uri['options'], - 'weight' => 100, - ); - } - - return $operations; + return $this->operations->getOperations($entity); } /** diff --git a/core/lib/Drupal/Core/Entity/EntityManager.php b/core/lib/Drupal/Core/Entity/EntityManager.php index 3060909..6861606 100644 --- a/core/lib/Drupal/Core/Entity/EntityManager.php +++ b/core/lib/Drupal/Core/Entity/EntityManager.php @@ -319,6 +319,18 @@ public function getAccessController($entity_type) { } /** + * Gets an entity type's operations controller. + * + * @return \Drupal\Core\Entity\EntityOperationsControllerInterface. + */ + public function getOperationsController($entity_type) { + return $this->getController($entity_type, 'operations'); + } + + /** + + + /** * Creates a new controller instance. * * @param string $entity_type diff --git a/core/lib/Drupal/Core/Entity/EntityOperationsControllerInterface.php b/core/lib/Drupal/Core/Entity/EntityOperationsControllerInterface.php new file mode 100644 index 0000000..9c95c29 --- /dev/null +++ b/core/lib/Drupal/Core/Entity/EntityOperationsControllerInterface.php @@ -0,0 +1,37 @@ +getDefinition($entity->entityType()); + if ($info['fieldable']) { + $uri = $entity->uri(); + $operations['manage-fields'] = array( + 'title' => t('Manage fields'), + 'href' => $uri['path'] . '/fields', + 'options' => $uri['options'], + 'weight' => 15, + ); + $operations['manage-display'] = array( + 'title' => t('Manage display'), + 'href' => $uri['path'] . '/display', + 'options' => $uri['options'], + 'weight' => 20, + ); + } + + return $operations; +} + +/** * Generates an entity field definition for a configurable field. * * @param \Drupal\field\FieldInterface $field diff --git a/core/modules/menu/lib/Drupal/menu/MenuListController.php b/core/modules/menu/lib/Drupal/menu/MenuListController.php index 4c5a408..6b3da33 100644 --- a/core/modules/menu/lib/Drupal/menu/MenuListController.php +++ b/core/modules/menu/lib/Drupal/menu/MenuListController.php @@ -39,28 +39,6 @@ public function buildRow(EntityInterface $entity) { } /** - * {@inheritdoc} - */ - public function getOperations(EntityInterface $entity) { - $operations = parent::getOperations($entity); - $uri = $entity->uri(); - - if (isset($operations['edit'])) { - $operations['edit']['title'] = t('Edit menu'); - $operations['add'] = array( - 'title' => t('Add link'), - 'href' => $uri['path'] . '/add', - 'options' => $uri['options'], - 'weight' => 20, - ); - } - if (isset($operations['delete'])) { - $operations['delete']['title'] = t('Delete menu'); - } - return $operations; - } - - /** * Overrides \Drupal\Core\Entity\EntityListController::render(); */ public function render() { diff --git a/core/modules/picture/lib/Drupal/picture/Entity/PictureMapping.php b/core/modules/picture/lib/Drupal/picture/Entity/PictureMapping.php index fb266fa..af4953d 100644 --- a/core/modules/picture/lib/Drupal/picture/Entity/PictureMapping.php +++ b/core/modules/picture/lib/Drupal/picture/Entity/PictureMapping.php @@ -28,7 +28,8 @@ * "add" = "Drupal\picture\PictureMappingFormController", * "delete" = "Drupal\picture\Form\PictureMappingDeleteForm", * "duplicate" = "Drupal\picture\PictureMappingFormController" - * } + * }, + * "operations" = "Drupal\picture\PictureMappingOperationsController" * }, * list_path = "admin/config/media/picturemapping", * config_prefix = "picture.mappings", diff --git a/core/modules/picture/lib/Drupal/picture/PictureMappingListController.php b/core/modules/picture/lib/Drupal/picture/PictureMappingListController.php index ffe4c0c..5594053 100644 --- a/core/modules/picture/lib/Drupal/picture/PictureMappingListController.php +++ b/core/modules/picture/lib/Drupal/picture/PictureMappingListController.php @@ -33,19 +33,4 @@ public function buildRow(EntityInterface $entity) { return $row + parent::buildRow($entity); } - /** - * {@inheritdoc} - */ - public function getOperations(EntityInterface $entity) { - $operations = parent::getOperations($entity); - $uri = $entity->uri(); - $operations['duplicate'] = array( - 'title' => t('Duplicate'), - 'href' => $uri['path'] . '/duplicate', - 'options' => $uri['options'], - 'weight' => 15, - ); - return $operations; - } - } diff --git a/core/modules/shortcut/lib/Drupal/shortcut/Entity/ShortcutSet.php b/core/modules/shortcut/lib/Drupal/shortcut/Entity/ShortcutSet.php index 392c3d8..ccac5ce 100644 --- a/core/modules/shortcut/lib/Drupal/shortcut/Entity/ShortcutSet.php +++ b/core/modules/shortcut/lib/Drupal/shortcut/Entity/ShortcutSet.php @@ -29,7 +29,8 @@ * "edit" = "Drupal\shortcut\ShortcutSetFormController", * "customize" = "Drupal\shortcut\Form\SetCustomize", * "delete" = "Drupal\shortcut\Form\ShortcutSetDeleteForm" - * } + * }, + * "operations" = "Drupal\shortcut\ShortcutSetOperationsController" * }, * config_prefix = "shortcut.set", * entity_keys = { diff --git a/core/modules/shortcut/lib/Drupal/shortcut/ShortcutSetListController.php b/core/modules/shortcut/lib/Drupal/shortcut/ShortcutSetListController.php index 6215a87..ca66977 100644 --- a/core/modules/shortcut/lib/Drupal/shortcut/ShortcutSetListController.php +++ b/core/modules/shortcut/lib/Drupal/shortcut/ShortcutSetListController.php @@ -24,25 +24,6 @@ public function buildHeader() { } /** - * {@inheritdoc} - */ - public function getOperations(EntityInterface $entity) { - $operations = parent::getOperations($entity); - $uri = $entity->uri(); - - if (isset($operations['edit'])) { - $operations['edit']['title'] = t('Edit menu'); - $operations['edit']['href'] = $uri['path'] . '/edit'; - } - - $operations['list'] = array( - 'title' => t('List links'), - 'href' => $uri['path'], - ); - return $operations; - } - - /** * Overrides \Drupal\Core\Entity\EntityListController::buildRow(). */ public function buildRow(EntityInterface $entity) { diff --git a/core/modules/system/lib/Drupal/system/Entity/Menu.php b/core/modules/system/lib/Drupal/system/Entity/Menu.php index 7b2be7b..cd2d742 100644 --- a/core/modules/system/lib/Drupal/system/Entity/Menu.php +++ b/core/modules/system/lib/Drupal/system/Entity/Menu.php @@ -21,7 +21,8 @@ * module = "system", * controllers = { * "storage" = "Drupal\Core\Config\Entity\ConfigStorageController", - * "access" = "Drupal\system\MenuAccessController" + * "access" = "Drupal\system\MenuAccessController", + * "operations" = "Drupal\menu\MenuOperationsController" * }, * config_prefix = "menu.menu", * entity_keys = { diff --git a/core/modules/user/lib/Drupal/user/Entity/Role.php b/core/modules/user/lib/Drupal/user/Entity/Role.php index 8529e87..6d6e593 100644 --- a/core/modules/user/lib/Drupal/user/Entity/Role.php +++ b/core/modules/user/lib/Drupal/user/Entity/Role.php @@ -27,7 +27,8 @@ * "form" = { * "default" = "Drupal\user\RoleFormController", * "delete" = "Drupal\user\Form\UserRoleDelete" - * } + * }, + * "operations" = "Drupal\user\RoleOperationsController" * }, * config_prefix = "user.role", * entity_keys = { diff --git a/core/modules/user/lib/Drupal/user/RoleListController.php b/core/modules/user/lib/Drupal/user/RoleListController.php index 3e95aae..216ac6a 100644 --- a/core/modules/user/lib/Drupal/user/RoleListController.php +++ b/core/modules/user/lib/Drupal/user/RoleListController.php @@ -41,24 +41,6 @@ public function buildRow(EntityInterface $entity) { /** * {@inheritdoc} */ - public function getOperations(EntityInterface $entity) { - $operations = parent::getOperations($entity); - - $operations['permissions'] = array( - 'title' => t('Edit permissions'), - 'href' => 'admin/people/permissions/' . $entity->id(), - 'weight' => 20, - ); - // Built-in roles could not be deleted or disabled. - if (in_array($entity->id(), array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID))) { - unset($operations['delete']); - } - return $operations; - } - - /** - * {@inheritdoc} - */ public function submitForm(array &$form, array &$form_state) { parent::submitForm($form, $form_state); diff --git a/core/modules/views_ui/lib/Drupal/views_ui/ViewListController.php b/core/modules/views_ui/lib/Drupal/views_ui/ViewListController.php index 33ac4de..a583664 100644 --- a/core/modules/views_ui/lib/Drupal/views_ui/ViewListController.php +++ b/core/modules/views_ui/lib/Drupal/views_ui/ViewListController.php @@ -135,31 +135,6 @@ public function buildHeader() { /** * {@inheritdoc} */ - public function getOperations(EntityInterface $entity) { - $operations = parent::getOperations($entity); - $uri = $entity->uri(); - - $operations['clone'] = array( - 'title' => t('Clone'), - 'href' => $uri['path'] . '/clone', - 'options' => $uri['options'], - 'weight' => 15, - ); - - // Add AJAX functionality to enable/disable operations. - foreach (array('enable', 'disable') as $op) { - if (isset($operations[$op])) { - $operations[$op]['ajax'] = TRUE; - $operations[$op]['query']['token'] = drupal_get_token($op); - } - } - - return $operations; - } - - /** - * {@inheritdoc} - */ public function buildOperations(EntityInterface $entity) { $build = parent::buildOperations($entity); diff --git a/core/modules/views_ui/views_ui.module b/core/modules/views_ui/views_ui.module index 7c41565..4efbcc0 100644 --- a/core/modules/views_ui/views_ui.module +++ b/core/modules/views_ui/views_ui.module @@ -105,6 +105,7 @@ function views_ui_entity_info(&$entity_info) { 'delete' => 'Drupal\views_ui\ViewDeleteFormController', 'break_lock' => 'Drupal\views_ui\Form\BreakLockForm', ), + 'operations' => 'Drupal\views_ui\ViewOperationsController', ); }