1

I am trying to customize the access of user fields. We have an internal list of all users, which all members can access (for things like mail/address/phone number). However, due to privacy, each user should be able to manage these field, and can hide certains fields from showing to particular members or groups.

For this, I created a database table which stores all preferences, and fetch them using dynamic query. For the field access, I use

function MY_MODULE_has_access($operation, $field_machine_name, $uid){
  Code for determining access here
  return if $uid has access
}
function MY_MODULE_entity_field_access($operation, $field_definition, $account, $items = NULL) {
  if ($field_definition->getName() == "field_address") {
    $user = \Drupal::currentUser();
    $result = AccessResult::forbiddenIf(!MY_MODULE_has_access($operation, "field_address", $user->id()));
    $result->addCacheableDependency($user);
    return $result;
  }
  return AccessResult::neutral();
}

However, due to caching, this only works one time. If the user changes its preferences, the field access still remains unchanged. How can I fix this?

1

The variable $user should probably be the parent entity of the field:

$user = $items->getEntity();

Which then when used as cache dependency should solve the caching issue:

$result->addCacheableDependency($user);

BTW you find the current user already in $account. If your access check depends on it then don't add it as object but use this predefined method for caching:

$result->cachePerUser();

But most times access code depends only on the current user roles and the resulting permissions, then you could use instead

$result->cachePerPermissions();

which is much better for cache performance.

| improve this answer | |
  • Thanks, that solved the problem! One more question, in some cases, the $items parameter is null (I have a view which imports some fields). Is it still possible to get the target entityid from the $field_definition, or should I handle the access in the view? – stinosaurus Jun 15 at 15:53
  • When you don't have the parent entity as context you can't use the other field values and so you don't need to add it for caching. You can't get the entity from the field definitions, those are static and don't contain any data about the actual entity. A view usually contains a row entity, but since you can have joined tables of more than one entity type it is not always that simple and yes, such things can be handled more efficiently in the view itself when you prepare the database tables so that they are accessible through sql. – 4k4 Jun 15 at 19:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.