diff --git a/core/includes/entity.api.php b/core/includes/entity.api.php index 0517568..dfa43da 100644 --- a/core/includes/entity.api.php +++ b/core/includes/entity.api.php @@ -618,17 +618,20 @@ function hook_entity_operation_alter(array &$operations, \Drupal\Core\Entity\Ent * @param string $operation * The operation to be performed. See * \Drupal\Core\TypedData\AccessibleInterface::access() for possible values. - * @param \Drupal\Core\Entity\Field\Field $field - * The entity field object on which the operation is to be performed. + * @param \Drupal\Core\Entity\Field\FieldDefinitionInterface $field_definition + * The field definition * @param \Drupal\Core\Session\AccountInterface $account * The user account to check. + * @param \Drupal\Core\Entity\Field\FieldInterface $field + * (optional) The entity field object on which the operation is to be + * performed. * * @return bool|NULL * TRUE if access should be allowed, FALSE if access should be denied and NULL * if the implementation has no opinion. */ -function hook_entity_field_access($operation, $field, \Drupal\Core\Session\AccountInterface $account) { - if ($field->getName() == 'field_of_interest' && $operation == 'update') { +function hook_entity_field_access($operation, \Drupal\Core\Entity\Field\FieldDefinitionInterface $field_definition, \Drupal\Core\Session\AccountInterface $account, \Drupal\Core\Entity\Field\FieldInterface $field) { + if ($field_definition->getFieldName() == 'field_of_interest' && $operation == 'update') { return user_access('update field of interest', $account); } } @@ -646,9 +649,12 @@ function hook_entity_field_access($operation, $field, \Drupal\Core\Session\Accou * @param array $context * Context array on the performed operation with the following keys: * - operation: The operation to be performed (string). - * - field: The entity field object (\Drupal\Core\Entity\Field\Field). + * - field_definition: The field definition object + * (\Drupal\Core\Entity\Field\FieldDefinitionInterface) * - account: The user account to check access for * (Drupal\user\Plugin\Core\Entity\User). + * - field: (optional) The entity field object + * (\Drupal\Core\Entity\Field\FieldInterface). */ function hook_entity_field_access_alter(array &$grants, array $context) { $field = $context['field']; diff --git a/core/lib/Drupal/Core/Entity/EntityAccessController.php b/core/lib/Drupal/Core/Entity/EntityAccessController.php index 164b83e..197b232 100644 --- a/core/lib/Drupal/Core/Entity/EntityAccessController.php +++ b/core/lib/Drupal/Core/Entity/EntityAccessController.php @@ -7,6 +7,8 @@ namespace Drupal\Core\Entity; +use Drupal\Core\Entity\Field\FieldDefinitionInterface; +use Drupal\Core\Entity\Field\FieldInterface; use Drupal\Core\Language\Language; use Drupal\Core\Session\AccountInterface; @@ -244,4 +246,45 @@ protected function prepareUser(AccountInterface $account = NULL) { return $account; } + /** + * @todo add to interface. + */ + public function fieldAccess($operation, FieldDefinitionInterface $field_definition, AccountInterface $account = NULL, FieldInterface $field = NULL) { + global $user; + if (!isset($account)) { + $account = $user; + } + + // Get the default access restriction that lives within this field. + $default = $field ? $field->defaultAccess($operation, $account) : TRUE; + + // Invoke hook and collect grants/denies for field access from other + // modules. Our default access flag is masked under the ':default' key. + $grants = array(':default' => $default); + $hook_implementations = \Drupal::moduleHandler()->getImplementations('entity_field_access'); + foreach ($hook_implementations as $module) { + $grants = array_merge($grants, array($module => module_invoke($module, 'entity_field_access', $operation, $field_definition, $account, $field))); + } + + // Also allow modules to alter the returned grants/denies. + $context = array( + 'operation' => $operation, + 'field_definition' => $field_definition, + 'field' => $field, + 'account' => $account, + ); + drupal_alter('entity_field_access', $grants, $context); + + // One grant being FALSE is enough to deny access immediately. + if (in_array(FALSE, $grants, TRUE)) { + return FALSE; + } + // At least one grant has the explicit opinion to allow access. + if (in_array(TRUE, $grants, TRUE)) { + return TRUE; + } + // All grants are NULL and have no opinion - deny access in that case. + return FALSE; + } + } diff --git a/core/lib/Drupal/Core/Entity/Field/Field.php b/core/lib/Drupal/Core/Entity/Field/Field.php index 0ff36d7..48816cf 100644 --- a/core/lib/Drupal/Core/Entity/Field/Field.php +++ b/core/lib/Drupal/Core/Entity/Field/Field.php @@ -171,37 +171,8 @@ public function __unset($property_name) { * Implements \Drupal\Core\TypedData\AccessibleInterface::access(). */ public function access($operation = 'view', AccountInterface $account = NULL) { - global $user; - if (!isset($account)) { - $account = $user; - } - // Get the default access restriction that lives within this field. - $access = $this->defaultAccess($operation, $account); - // Invoke hook and collect grants/denies for field access from other - // modules. Our default access flag is masked under the ':default' key. - $grants = array(':default' => $access); - $hook_implementations = \Drupal::moduleHandler()->getImplementations('entity_field_access'); - foreach ($hook_implementations as $module) { - $grants = array_merge($grants, array($module => module_invoke($module, 'entity_field_access', $operation, $this, $account))); - } - // Also allow modules to alter the returned grants/denies. - $context = array( - 'operation' => $operation, - 'field' => $this, - 'account' => $account, - ); - drupal_alter('entity_field_access', $grants, $context); - - // One grant being FALSE is enough to deny access immediately. - if (in_array(FALSE, $grants, TRUE)) { - return FALSE; - } - // At least one grant has the explicit opinion to allow access. - if (in_array(TRUE, $grants, TRUE)) { - return TRUE; - } - // All grants are NULL and have no opinion - deny access in that case. - return FALSE; + $access_controller = \Drupal::entityManager()->getAccessController($this->getParent()->entityType()); + return $access_controller ->fieldAccess($operation, $this->getFieldDefinition(), $account, $this); } /** diff --git a/core/modules/field/field.api.php b/core/modules/field/field.api.php index 312ebb5..ccf1afe 100644 --- a/core/modules/field/field.api.php +++ b/core/modules/field/field.api.php @@ -1361,32 +1361,5 @@ function hook_field_storage_purge(\Drupal\Core\Entity\EntityInterface $entity, $ */ /** - * Determine whether the user has access to a given field. - * - * This hook is invoked from field_access() to let modules block access to - * operations on fields. If no module returns FALSE, the operation is allowed. - * - * @param $op - * The operation to be performed. Possible values: 'edit', 'view'. - * @param \Drupal\field\FieldInterface $field - * The field on which the operation is to be performed. - * @param $entity_type - * The type of $entity; for example, 'node' or 'user'. - * @param $entity - * (optional) The entity for the operation. - * @param $account - * (optional) The account to check; if not given use currently logged in user. - * - * @return - * TRUE if the operation is allowed, and FALSE if the operation is denied. - */ -function hook_field_access($op, \Drupal\field\FieldInterface $field, $entity_type, $entity, $account) { - if ($field['field_name'] == 'field_of_interest' && $op == 'edit') { - return user_access('edit field of interest', $account); - } - return TRUE; -} - -/** * @} End of "addtogroup hooks". */ diff --git a/core/modules/field/field.module b/core/modules/field/field.module index c2eda35..11abfc4 100644 --- a/core/modules/field/field.module +++ b/core/modules/field/field.module @@ -868,22 +868,15 @@ function field_get_items(EntityInterface $entity, $field_name, $langcode = NULL) * * @return * TRUE if the operation is allowed; FALSE if the operation is denied. + * + * @deprecated as of Drupal 8.0. Use + * Drupal\Core\Entity\EntityAccessControllerInterface::fieldAccess() */ function field_access($op, FieldInterface $field, $entity_type, $entity = NULL, $account = NULL) { - global $user; - - if (!isset($account)) { - $account = $user; - } + $access_controller = \Drupal::entityManager()->getAccessController($entity_type); - foreach (Drupal::moduleHandler()->getImplementations('field_access') as $module) { - $function = $module . '_field_access'; - $access = $function($op, $field, $entity_type, $entity, $account); - if ($access === FALSE) { - return FALSE; - } - } - return TRUE; + $items = $entity ? $entity->get($field->id()) : NULL; + return $access_controller->fieldAccess($op, $field, $account, $items); } /** diff --git a/core/modules/field/tests/modules/field_test/field_test.field.inc b/core/modules/field/tests/modules/field_test/field_test.field.inc index db22e81..1a2734c 100644 --- a/core/modules/field/tests/modules/field_test/field_test.field.inc +++ b/core/modules/field/tests/modules/field_test/field_test.field.inc @@ -6,8 +6,10 @@ */ use Drupal\Core\Entity\EntityInterface; +use Drupal\Core\Entity\Field\FieldDefinitionInterface; +use Drupal\Core\Entity\Field\FieldInterface; +use Drupal\Core\Session\AccountInterface; use Drupal\field\FieldException; -use Drupal\field\FieldInterface; /** * Implements hook_field_info(). @@ -199,16 +201,16 @@ function field_test_default_value(EntityInterface $entity, $field, $instance) { } /** - * Implements hook_field_access(). + * Implements hook_entity_field_access(). */ -function field_test_field_access($op, FieldInterface $field, $entity_type, $entity, $account) { - if ($field['field_name'] == "field_no_{$op}_access") { +function field_test_entity_field_access($operation, FieldDefinitionInterface $field_definition, AccountInterface $account, FieldInterface $field) { + if ($field_definition->getFieldName() == "field_no_{$operation}_access") { return FALSE; } // Only grant view access to test_view_field fields when the user has // 'view test_view_field content' permission. - if ($field['field_name'] == 'test_view_field' && $op == 'view' && !user_access('view test_view_field content')) { + if ($field_definition->getFieldName() == 'test_view_field' && $operation == 'view' && !user_access('view test_view_field content', $account)) { return FALSE; } diff --git a/core/modules/system/tests/modules/entity_test/entity_test.module b/core/modules/system/tests/modules/entity_test/entity_test.module index 05498f7..fc6f289 100644 --- a/core/modules/system/tests/modules/entity_test/entity_test.module +++ b/core/modules/system/tests/modules/entity_test/entity_test.module @@ -6,6 +6,8 @@ */ use Drupal\Core\Entity\EntityInterface; +use Drupal\Core\Entity\Field\FieldDefinitionInterface; +use Drupal\Core\Entity\Field\FieldInterface; use Drupal\entity\Plugin\Core\Entity\EntityFormDisplay; use Drupal\field\Plugin\Core\Entity\Field; use Drupal\field\Plugin\Core\Entity\FieldInstance; @@ -369,13 +371,15 @@ function entity_test_label_callback($entity_type, $entity, $langcode = NULL) { * * @see \Drupal\system\Tests\Entity\FieldAccessTest::testFieldAccess() */ -function entity_test_entity_field_access($operation, $field, $account) { - if ($field->getName() == 'field_test_text') { - if ($field->value == 'no access value') { - return FALSE; - } - elseif ($operation == 'delete' && $field->value == 'no delete access value') { - return FALSE; +function entity_test_entity_field_access($operation, FieldDefinitionInterface $field_definition, AccountInterface $account, FieldInterface $field) { + if ($field_definition->getFieldName() == 'field_test_text') { + if ($field) { + if ($field->value == 'no access value') { + return FALSE; + } + elseif ($operation == 'delete' && $field->value == 'no delete access value') { + return FALSE; + } } } }