diff --git a/core/includes/entity.api.php b/core/includes/entity.api.php index da9c1b8..c4077b8 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\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 7cf493c..87317f0 100644 --- a/core/lib/Drupal/Core/Entity/Field/Field.php +++ b/core/lib/Drupal/Core/Entity/Field/Field.php @@ -168,52 +168,15 @@ public function __unset($property_name) { } /** - * Implements \Drupal\Core\TypedData\AccessibleInterface::access(). + * {@inheritdoc} */ 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); } /** - * Contains the default access logic of this field. - * - * See \Drupal\Core\TypedData\AccessibleInterface::access() for the parameter - * doucmentation. This method can be overriden by field sub classes to provide - * a different default access logic. That allows them to inherit the complete - * access() method which contains the access hook invocation logic. - * - * @return bool - * TRUE if access to this field is allowed per default, FALSE otherwise. + * {@inheritdoc} */ public function defaultAccess($operation = 'view', AccountInterface $account = NULL) { // Grant access per default. diff --git a/core/lib/Drupal/Core/Entity/Field/FieldInterface.php b/core/lib/Drupal/Core/Entity/Field/FieldInterface.php index 0d85da3..e7b8483 100644 --- a/core/lib/Drupal/Core/Entity/Field/FieldInterface.php +++ b/core/lib/Drupal/Core/Entity/Field/FieldInterface.php @@ -36,6 +36,18 @@ public function getFieldDefinition(); /** + * Contains the default access logic of this field. + * + * See \Drupal\Core\TypedData\AccessibleInterface::access() for the parameter + * doucmentation. This method can be overriden by field sub classes to provide + * a different default access logic. + * + * @return bool + * TRUE if access to this field is allowed per default, FALSE otherwise. + */ + public function defaultAccess($operation = 'view', AccountInterface $account = NULL); + + /** * Filters out empty field items and re-numbers the item deltas. */ public function filterEmptyValues(); 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.deprecated.inc b/core/modules/field/field.deprecated.inc index fb97eff..4356671 100644 --- a/core/modules/field/field.deprecated.inc +++ b/core/modules/field/field.deprecated.inc @@ -1210,3 +1210,32 @@ function field_get_items(EntityInterface $entity, $field_name, $langcode = NULL) function field_get_default_value(EntityInterface $entity, $field, $instance, $langcode = NULL) { return $instance->getFieldDefaultValue($entity); } + +/** + * Determines whether the user has access to a given field. + * + * @param string $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; 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) { + $access_controller = \Drupal::entityManager()->getAccessController($entity_type); + + $items = $entity ? $entity->get($field->id()) : NULL; + return $access_controller->fieldAccess($op, $field, $account, $items); +} diff --git a/core/modules/field/field.module b/core/modules/field/field.module index c355e67..f41206f 100644 --- a/core/modules/field/field.module +++ b/core/modules/field/field.module @@ -770,42 +770,6 @@ function field_view_field(EntityInterface $entity, $field_name, $display_options } /** - * Determines whether the user has access to a given field. - * - * @param string $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; FALSE if the operation is denied. - */ -function field_access($op, FieldInterface $field, $entity_type, $entity = NULL, $account = NULL) { - global $user; - - if (!isset($account)) { - $account = $user; - } - - 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; -} - -/** * Extracts the bundle name from a bundle object. * * @param $entity_type 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..a893cbd 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 = NULL) { + 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 b401470..19755c8 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,9 @@ */ use Drupal\Core\Entity\EntityInterface; +use Drupal\Core\Entity\Field\FieldDefinitionInterface; +use Drupal\Core\Entity\Field\FieldInterface; +use Drupal\Core\Session\AccountInterface; use Drupal\entity\Entity\EntityFormDisplay; use Drupal\field\Entity\Field; use Drupal\field\Entity\FieldInstance; @@ -369,13 +372,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 = NULL) { + 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; + } } } }