commit e27f39f52fddd8b101e1d4778b671c4357608928 Author: Bart Feenstra Date: Fri Nov 1 22:14:35 2013 +0100 fubar diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigEntityListController.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityListController.php index b363cc4..2cfb551 100644 --- a/core/lib/Drupal/Core/Config/Entity/ConfigEntityListController.php +++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityListController.php @@ -27,40 +27,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..5422c68 --- /dev/null +++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityOperationsController.php @@ -0,0 +1,52 @@ +uri(); + $operations = parent::getDefaultOperations($entity); + if (isset($operations['update'])) { + // For configuration entities edit path is the MENU_DEFAULT_LOCAL_TASK and + // therefore should be accessed by the short route. + $operations['update']['href'] = $uri['path']; + } + + $info = $entity->entityInfo(); + if (isset($info['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/Entity/Annotation/EntityType.php b/core/lib/Drupal/Core/Entity/Annotation/EntityType.php index 40c1447..1758622 100644 --- a/core/lib/Drupal/Core/Entity/Annotation/EntityType.php +++ b/core/lib/Drupal/Core/Entity/Annotation/EntityType.php @@ -64,6 +64,10 @@ class EntityType extends Plugin { * - translation: The name of the controller class that should be used to * handle the translation process. The class must implement * \Drupal\content_translation\ContentTranslationControllerInterface. + * - operations: The name of the controller class that provides entity + * operations, for which access checks must be run through the "access" + * controller. The class must implement + * \Drupal\Core\Entity\EntityOperationsControllerInterface. * * @todo Interfaces from outside \Drupal\Core or \Drupal\Component should not * be used here. diff --git a/core/lib/Drupal/Core/Entity/EntityListController.php b/core/lib/Drupal/Core/Entity/EntityListController.php index 7312e3f..b70e293 100644 --- a/core/lib/Drupal/Core/Entity/EntityListController.php +++ b/core/lib/Drupal/Core/Entity/EntityListController.php @@ -8,6 +8,7 @@ namespace Drupal\Core\Entity; use Drupal\Core\Extension\ModuleHandlerInterface; +use Drupal\Core\Session\AccountInterface; use Drupal\Core\StringTranslation\TranslationInterface; use Symfony\Component\DependencyInjection\ContainerInterface; use Drupal\Component\Utility\String; @@ -18,6 +19,13 @@ class EntityListController implements EntityListControllerInterface, EntityControllerInterface { /** + * The current user. + * + * @var \Drupal\Core\Session\AccountInterface + */ + protected $currentUser; + + /** * The entity storage controller class. * * @var \Drupal\Core\Entity\EntityStorageControllerInterface @@ -25,6 +33,13 @@ class EntityListController implements EntityListControllerInterface, EntityContr protected $storage; /** + * The entity operations controller. + * + * @var \Drupal\Core\Entity\EntityOperationsControllerInterface + */ + protected $operations; + + /** * The module handler to invoke hooks on. * * @var \Drupal\Core\Extension\ModuleHandlerInterface @@ -62,7 +77,9 @@ public static function createInstance(ContainerInterface $container, $entity_typ $entity_type, $entity_info, $container->get('entity.manager')->getStorageController($entity_type), - $container->get('module_handler') + $container->get('entity.manager')->getOperationsController($entity_type), + $container->get('module_handler'), + $container->get('current_user') ); } @@ -75,14 +92,20 @@ public static function createInstance(ContainerInterface $container, $entity_typ * An array of entity info for the entity type. * @param \Drupal\Core\Entity\EntityStorageControllerInterface $storage * The entity storage controller class. + * @param \Drupal\Core\Entity\EntityOperationsControllerInterface $operations + * The entity operations controller. * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler * The module handler to invoke hooks on. + * @param \Drupal\Core\Session\AccountInterface $current_user + * The current user. */ - 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, AccountInterface $current_user) { $this->entityType = $entity_type; $this->storage = $storage; + $this->operations = $operations; $this->entityInfo = $entity_info; $this->moduleHandler = $module_handler; + $this->currentUser = $current_user; } /** @@ -113,33 +136,6 @@ 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; - } - - /** * Builds the header row for the entity listing. * * @return array @@ -164,31 +160,12 @@ public function buildHeader() { * @see \Drupal\Core\Entity\EntityListController::render() */ public function buildRow(EntityInterface $entity) { - $row['operations']['data'] = $this->buildOperations($entity); - return $row; - } - - /** - * Builds a renderable list of operation links for the entity. - * - * @param \Drupal\Core\Entity\EntityInterface $entity - * The entity on which the linked operations will be performed. - * - * @return array - * A renderable array of operation links. - * - * @see \Drupal\Core\Entity\EntityListController::render() - */ - public function buildOperations(EntityInterface $entity) { - // Retrieve and sort operations. - $operations = $this->getOperations($entity); - $this->moduleHandler->alter('entity_operation', $operations, $entity); - uasort($operations, 'drupal_sort_weight'); - $build = array( + $row['operations']['data'] = array( '#type' => 'operations', - '#links' => $operations, + '#links' => $this->operations->getOperations($entity, $this->currentUser), ); - return $build; + + return $row; } /** diff --git a/core/lib/Drupal/Core/Entity/EntityListControllerInterface.php b/core/lib/Drupal/Core/Entity/EntityListControllerInterface.php index b7581d8..a56d959 100644 --- a/core/lib/Drupal/Core/Entity/EntityListControllerInterface.php +++ b/core/lib/Drupal/Core/Entity/EntityListControllerInterface.php @@ -32,22 +32,6 @@ public function getStorageController(); public function load(); /** - * Provides an array of information to build a list of operation links. - * - * @param \Drupal\Core\Entity\EntityInterface $entity - * The entity the operations are for. - * - * @return array - * An associative array of operation link data for this list, keyed by - * operation name, containing the following key-value pairs: - * - title: The localized title of the operation. - * - href: The path for the operation. - * - options: An array of URL options for the path. - * - weight: The weight of this operation. - */ - public function getOperations(EntityInterface $entity); - - /** * Renders the list page markup to be output. * * @return string diff --git a/core/lib/Drupal/Core/Entity/EntityManager.php b/core/lib/Drupal/Core/Entity/EntityManager.php index cb722b7..8e7873e 100644 --- a/core/lib/Drupal/Core/Entity/EntityManager.php +++ b/core/lib/Drupal/Core/Entity/EntityManager.php @@ -300,6 +300,18 @@ protected function getController($entity_type, $controller_type) { } /** + * Gets an entity type's operations controller. + * + * @param string $entity_type + * The entity type for this operations controller. + * + * @return \Drupal\Core\Entity\EntityOperationsControllerInterface. + */ + public function getOperationsController($entity_type) { + return $this->getController($entity_type, 'operations'); + } + + /** * {@inheritdoc} */ public function getForm(EntityInterface $entity, $operation = 'default', array $form_state = array()) { diff --git a/core/lib/Drupal/Core/Entity/EntityOperationsController.php b/core/lib/Drupal/Core/Entity/EntityOperationsController.php new file mode 100644 index 0000000..9142762 --- /dev/null +++ b/core/lib/Drupal/Core/Entity/EntityOperationsController.php @@ -0,0 +1,111 @@ +moduleHandler = $module_handler; + $this->translationManager = $translation_manager; + $this->accessController = $access_controller; + } + + /** + * {@inheritdoc} + */ + public static function createInstance(ContainerInterface $container, $entity_type, array $entity_info) { + return new static($container->get('module_handler'), $container->get('string_translation'), $container->get('entity.manager')->getAccessController($entity_type)); + } + + /** + * {@inheritdoc} + */ + public function getOperations(EntityInterface $entity, AccountInterface $account) { + // Operations are retrieved from specific to non-specific contexts (the + // controller, the entity-type-specific hook, and the generic hook). + $operations = $this->getDefaultOperations($entity); + $hooks = array($entity->entityType() . '_operations' , 'entity_operations'); + foreach ($hooks as $hook) { + $operations = array_merge($this->moduleHandler->invokeAll($hook, array($entity)), $operations); + } + $this->moduleHandler->alter(array('entity_operations', $entity->entityType() . '_operations'), $entity, $operations); + + // Check access to the operations. + foreach ($operations as $operation => $operation_link) { + if (!$entity->access($operation, $account)) { + unset($operations[$operation]); + } + } +// @todo Sort operations by weight and human-readable label. + return $operations; + } + + /** + * Gets the entity's default operations. + * + * @param \Drupal\Core\Entity\EntityInterface $entity + * + * @return array + * The structure is identical to that of the return value of + * self::getOperations(). + */ + protected function getDefaultOperations(EntityInterface $entity) { + $uri = $entity->uri(); + $operations = array(); + $operations['update'] = array( + 'title' => $this->translationManager->translate('Edit'), + 'href' => $uri['path'] . '/edit', + 'options' => $uri['options'], + 'weight' => 10, + ); + $operations['delete'] = array( + 'title' => $this->translationManager->translate('Delete'), + 'href' => $uri['path'] . '/delete', + 'options' => $uri['options'], + 'weight' => 100, + ); + + return $operations; + } +} diff --git a/core/lib/Drupal/Core/Entity/EntityOperationsControllerInterface.php b/core/lib/Drupal/Core/Entity/EntityOperationsControllerInterface.php new file mode 100644 index 0000000..28ac78f --- /dev/null +++ b/core/lib/Drupal/Core/Entity/EntityOperationsControllerInterface.php @@ -0,0 +1,32 @@ +uri(); - $operations['edit']['href'] = $uri['path']; - $operations['edit']['query']['destination'] = 'admin/structure/block/custom-blocks'; - } - return $operations; - } - } diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockOperationsController.php b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockOperationsController.php new file mode 100644 index 0000000..982607a --- /dev/null +++ b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockOperationsController.php @@ -0,0 +1,33 @@ +uri(); + $operations['edit']['href'] = $uri['path']; + $operations['edit']['query']['destination'] = 'admin/structure/block/custom-blocks'; + } + + return $operations; + } + +} diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/Entity/CustomBlock.php b/core/modules/block/custom_block/lib/Drupal/custom_block/Entity/CustomBlock.php index 9446451..61b23b4 100644 --- a/core/modules/block/custom_block/lib/Drupal/custom_block/Entity/CustomBlock.php +++ b/core/modules/block/custom_block/lib/Drupal/custom_block/Entity/CustomBlock.php @@ -22,6 +22,7 @@ * bundle_label = @Translation("Custom Block type"), * module = "custom_block", * controllers = { + * "operations" = "Drupal\custom_block\CustomBlockOperationsController", * "storage" = "Drupal\custom_block\CustomBlockStorageController", * "access" = "Drupal\custom_block\CustomBlockAccessController", * "list" = "Drupal\custom_block\CustomBlockListController", diff --git a/core/modules/block/lib/Drupal/block/Entity/Block.php b/core/modules/block/lib/Drupal/block/Entity/Block.php index f11031e..4c4816d 100644 --- a/core/modules/block/lib/Drupal/block/Entity/Block.php +++ b/core/modules/block/lib/Drupal/block/Entity/Block.php @@ -22,6 +22,7 @@ * label = @Translation("Block"), * module = "block", * controllers = { + * "operations" = "Drupal\Core\Config\Entity\ConfigEntityOperationsController", * "storage" = "Drupal\Core\Config\Entity\ConfigStorageController", * "access" = "Drupal\block\BlockAccessController", * "view_builder" = "Drupal\block\BlockViewBuilder", diff --git a/core/modules/contact/lib/Drupal/contact/Entity/Category.php b/core/modules/contact/lib/Drupal/contact/Entity/Category.php index 2e6dd3b..5f5319a 100644 --- a/core/modules/contact/lib/Drupal/contact/Entity/Category.php +++ b/core/modules/contact/lib/Drupal/contact/Entity/Category.php @@ -21,6 +21,7 @@ * label = @Translation("Contact category"), * module = "contact", * controllers = { + * "operations" = "Drupal\Core\Config\Entity\ConfigEntityOperationsController", * "storage" = "Drupal\contact\CategoryStorageController", * "access" = "Drupal\contact\CategoryAccessController", * "list" = "Drupal\contact\CategoryListController", diff --git a/core/modules/field_ui/field_ui.module b/core/modules/field_ui/field_ui.module index dc0d38f..e580192 100644 --- a/core/modules/field_ui/field_ui.module +++ b/core/modules/field_ui/field_ui.module @@ -179,6 +179,71 @@ function field_ui_permission() { } /** + * Implements hook_entity_operations(). + */ +function field_ui_entity_operations(EntityInterface $entity) { + $info = $entity->entityInfo(); + $operations = array(); + + 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, + ); + } + + // Add manage fields and display links if this entity type is the bundle + // of another. + if (!empty($info['bundle_of'])) { + $uri = $entity->uri(); + $operations['manage-fields'] = array( + 'title' => t('Manage fields'), + 'href' => $uri['path'] . '/fields', + 'options' => $uri['options'], + 'weight' => 15, + ); + $operations['manage-form-display'] = array( + 'title' => t('Manage form display'), + 'href' => $uri['path'] . '/form-display', + 'options' => $uri['options'], + 'weight' => 20, + ); + $operations['manage-display'] = array( + 'title' => t('Manage display'), + 'href' => $uri['path'] . '/display', + 'options' => $uri['options'], + 'weight' => 25, + ); + } + + return $operations; +} + +/** + * Implements hook_entity_access(). + */ +function field_ui_entity_access(\Drupal\Core\Entity\EntityInterface $entity, $operation, \Drupal\Core\Session\AccountInterface $account, $langcode) { + if ($operation == 'manage-fields') { + return $account->hasPermission('administer ' . $entity->entityType() . ' fields'); + } + if ($operation == 'manage-form-display') { + return $account->hasPermission('administer ' . $entity->entityType() . ' form display'); + } + if ($operation == 'manage-display') { + return $account->hasPermission('administer ' . $entity->entityType() . ' display'); + } +} + +/** * Menu loader callback: Loads a field instance based on field and bundle name. * * @param $field_name @@ -291,43 +356,6 @@ function field_ui_form_node_type_form_alter(&$form, $form_state) { } /** - * Implements hook_entity_operation_alter(). - */ -function field_ui_entity_operation_alter(array &$operations, EntityInterface $entity) { - $info = $entity->entityInfo(); - // Add manage fields and display links if this entity type is the bundle - // of another. - if (!empty($info['bundle_of'])) { - $bundle_of = $info['bundle_of']; - $uri = $entity->uri(); - if (user_access('administer '. $bundle_of . ' fields')) { - $operations['manage-fields'] = array( - 'title' => t('Manage fields'), - 'href' => $uri['path'] . '/fields', - 'options' => $uri['options'], - 'weight' => 15, - ); - } - if (user_access('administer '. $bundle_of . ' form display')) { - $operations['manage-form-display'] = array( - 'title' => t('Manage form display'), - 'href' => $uri['path'] . '/form-display', - 'options' => $uri['options'], - 'weight' => 20, - ); - } - if (user_access('administer '. $bundle_of . ' display')) { - $operations['manage-display'] = array( - 'title' => t('Manage display'), - 'href' => $uri['path'] . '/display', - 'options' => $uri['options'], - 'weight' => 25, - ); - } - } -} - -/** * Form submission handler for the 'Save and manage fields' button. * * @see field_ui_form_node_type_form_alter() diff --git a/core/modules/system/entity.api.php b/core/modules/system/entity.api.php index 05f9e57..375f65a 100644 --- a/core/modules/system/entity.api.php +++ b/core/modules/system/entity.api.php @@ -684,15 +684,54 @@ function hook_entity_field_info_alter(&$info, $entity_type) { } /** - * Alter entity operations. + * Declares operations for an entity. + * + * @see \Drupal\Core\Entity\EntityOperationsController * - * @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. + * + * @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\EntityOperationsController + * + * @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_operation_alter(array &$operations, \Drupal\Core\Entity\EntityInterface $entity) { +function hook_ENTITY_TYPE_operations(\Drupal\Core\Entity\EntityInterface $entity) { + return array(); +} + +/** + * Alters entity operations. + * + * @see \Drupal\Core\Entity\EntityOperationsController + * + * @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_operations_alter(\Drupal\Core\Entity\EntityInterface $entity, array &$operations) { $uri = $entity->uri(); $operations['translate'] = array( 'title' => t('Translate'), @@ -702,6 +741,20 @@ function hook_entity_operation_alter(array &$operations, \Drupal\Core\Entity\Ent } /** + * Alters entity operations for an entity of a specific type. + * + * @see \Drupal\Core\Entity\EntityOperationsController + * + * @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