Experimental project
This is a sandbox project, which contains experimental code for developer use only.
Target audience:
Before you read on, please understand this is an API only module. In other words, it provides extra features for module developers. It does nothing by itself. If you're a module developer, read on.
Overview
Drupal's core Field API defines a hook for field access, hook_field_access, that is restrictive as all module developers are aware. In other words, given field F, if a single module implementing hook_field_access returns a Boolean false, thus denying access to the field, Drupal will deny access to the field even if there is another module that absolutely requires access to the field.
Normally, this is acceptable but sometimes a module might want to override the grants for a field denied access by another module. Or, a module might contain logic to grant access to a field but another completely independent module has denied access. Because of the restrictive nature of the field_access function, which internally invokes hook_field_access, access will be denied.
There are numerous scenarios that are similar in nature to hook_file_download_access and hook_file_download_access_alter. For a possible scenario, read on.
Possible scenario:
Assume we have 2 modules, M1 and M2, and a field F. Both modules are configured to operate on F. M1 contains logic to deny access to F from users outside of Canada. M2 contains logic to deny access to F from users without an "Editor" role.
Given a user, U, from England, that has the "Editor" role, M1 would deny access to F - they are not from Canada - and M2 would grant access to F - they have the "Editor" role.
The end result however is that access to F will be denied because a single module, in this case M1, denied access.
The only way to overcome this problem is through a mechanism that allows M2 to override the grants of M1. This can be accomplished through another hook, hook_field_access_alter, which unfortunately is not provided by core. That's where this module comes in - it introduces that much needed hook.
It is worth noting that, following the basic implementation approach for this module - read on for details on that - it is possible to make the field_access function permissive versus restrictive instead of providing an alter hook. But to accommodate additional scenarios - read on for details on that - an alter hook is preferred.
How it works:
This module works with a play on of the Adapter Pattern, procedural style. It defines 2 hooks, hook_field_access_field_access and hook_field_access_field_access_alter.
Internally, the module implements hook_field_access. This implementation acts as the adapter. The implementation then simply invokes hook_field_access_field_access. That hook is simply a replacement for core's hook_field_access. Third party modules that want other modules to alter their grants should simply implement that new hook instead of core's.
After invoking hook_field_access_field_access, the implementation saves the grant for each implementing module and then invokes hook_field_access_field_access_alter, passing the complete collection of grants.
Finally, the implementation checks if there is a single module that denied access. If there is, it also denies access. Otherwise, access is granted. So it maintains core's restrictive nature.
Why an alter hook?
Following the basic implementation of this module, through an adapter, it is simply possible to ignore the alter hook, hook_field_access_field_access_alter, and make the hook_field_access_field_access permissive instead.
But to open up the possibility of modules detecting other modules prior to altering grants, an alter hook is needed. So, for example, an alter hook opens up the possibility of M2 of basing its alter logic on the grant provided by M1.
Intended usage and possible abuse:
Modules implementing hook_field_access_field_access_alter should really only alter the grants if they have granted access and want to make sure no other module denied access. In other words, if they want to override the restrictive nature of the field_access function.
Consider why, citing the example of the 2 modules above M1 and M2. M1 denied access and M2 granted access. Consider this code for M1's implementation of the alter hook:
function m1_field_access_field_access_alter(array &$grants, ...) {
$m1_grant = $grants['m1'];
if($m1_grant === false) {
foreach($grants as $module_name => $module_grant) {
$grants[$module_name] = false;
}
}
}
If the M1 implementation for this hook is invoked, for what ever reason, after the M2 implementation, access will be denied. The code is pretty self explanatory. This will be so, even if the M2 implementation altered the grants to remove any denied grants.
So not only is this a possible abuse, it is also incorrect and will lead to potential bugs. The correct approach for the implementation of this hook is as follows:
function m1_field_access_field_access_alter(array &$grants, ...) {
$m1_grant = $grants['m1'];
if($m1_grant === true) {
foreach($grants as $module_name => $module_grant) {
$grants[$module_name] = true;
}
}
}
Of course, additional logic can be added. But the overall idea is the same. Modules should only really alter grants if they themselves have granted access. Otherwise, they should return silently.
Project information
- Project categories: Developer tools, Site structure
- Created by 9ee1 on , updated