Entity access hooks

As I mentioned, the core entity access handler invokes access hooks that modules that don't own the entity type can implement in order to have their say in the access to an entity. There are two sets of access hooks to speak of. The first set covers create operations, as follows:

  • hook_entity_create_access()
  • hook_[entity_type]_create_access()

The second set covers view, update, and delete operations:

  • hook_entity_access()
  • hook_[entity_type]_access()

For each set, we have two hooks invoked at the same time that go from generic to entity type-specific. For example, when trying to view a node, the second hook that is invoked is hook_node_access().

The entity access hook implementations, as you remember from our earlier discussion, also have to return an AccessResultInterface. This is because the result is used inside the orIf() combination with the access result of the access handler.

So, let's take a look at how we can implement these access hooks, especially their signatures. Hence, we begin with the first set:

/** 
 * Implements hook_entity_create_access(). 
 */ 
function my_module_entity_create_access(DrupalCoreSessionAccountInterface $account, array $context, $entity_bundle) { 
  // Perform access check and return an AccessResultInterface instance. 
}  

This is the generic entity create access hook. To make it specific to an entity type, we replace the word entity from the function name with the actual ID of the entity type. The parameters, however, remain the same—the user account being checked for access, a context (an array containing the entity type ID and the langcode of the entity being created), and the bundle of the entity being created.

The second set looks like this:

function  
my_module_entity_access(DrupalCoreEntityEntityInterface $entity, $operation, DrupalCoreSessionAccountInterface $account)  
{ 
  // Perform access check and return an AccessResultInterface instance. 
} 

Again, to make it specific to an entity type, we can just replace the word entity with the ID of the entity type we want. Once again, the parameters remain, in essence, consistent—the entity being accessed (type-hinted with the relevant entity interface if implementing the more specific hook), the operation being attempted (one of three strings: view, update, and delete), and the user account being checked for access.

That's pretty much it. These hooks are invoked dynamically whenever access is being checked on an entity for the given operation. Let's talk about some examples of this.

First, the entity routes that come out of the box are checking access against these operations, so no need to worry there. So, if we navigate to the canonical, form, or delete URL, access will be checked.

Secondly, if we programmatically load an entity and render it as we saw in Chapter 6, Data Modeling and Storage, using the view builder handler, the entity access with the view operation gets invoked. However, if we load the entity and simply retrieve some data from it and print it within our own template, we bypass access control. If we are doing this, we will need to make sure that we always check access manually:

$access = $entity->access('view', $account);  

This will return a Boolean, unless you specify a third argument as TRUE, which will return an AccessResultInterface object; your call, depending on the circumstances.

Thirdly, if we load an entity programmatically that we use inside a form builder and want to render the form, we again bypass the access check. So, we should perform it manually again using the update operation instead.

When it comes to programmatically dealing with URLs and menu links to pages that have CRUD connotations with regard to entities, we will need to perform access checking ourselves, but we will discuss entity access in routes in a minute; first, a word of caution.

Earlier, I made a note about extracting entity data and simply rendering field values. The same problem occurs when running entity queries—the results will contain entities that the current user may not have access to. So, we must be aware of this and handle it appropriately. This problem becomes even more prominent with Views, which makes custom database queries and will include potentially inaccessible entities in the result set. Compounded by the possibility of rendering field values with Views, this can cause quite unexpected behavior. So, keep in mind that for cases like this, the entity access hooks and access control handler do not fire. The Node module, however, has a complex grant system that takes care of all this, but, unfortunately, this is available only for node entities. We will talk about these soon as well.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset