4

Is there a way to force node access to allowed if there is a hook in a different module marking it as forbidden?

I have a custom module where i implement hook_node_access, returning allowed should certain conditions apply, but the result is being override by a contrib module that sets node access to forbidden.

Can i force my result?

3

The only way i found to fix this was preventing the conflicting hook from running:

function myModule_module_implements_alter(&$implementations, $hook) {

    if ($hook == 'node_access') {

      unset($implementations['conflicting_module']); // Not any more
    }
}

As it contains useful functionality, i'm running it in my own code, should my conditions for allowed not apply:

function myModule_node_access(NodeInterface $node, $op, AccountInterface $account) {

  if ($account->isAuthenticated() and myConditionIsTrue()) {

      return AccessResult::allowed();
  }

  // Run removed hook

  if (function_exists('conflicting_module_node_access')) {

    return conflicting_module_node_access($node, $op, $account);
  }

  return AccessResult::neutral();
}

This is less than ideal and i would prefer an alternative.

  • 1
    I'm not certain about 8, but in 7 if any access callback returned false the end result was false. I think it's a safe bet to be the same in 8 but it's worth checking. If that holds true, I think your solution is probably as elegant as it's going to get. You could probably tackle it lower down the chain, maybe by taking control of the node access functionality completely, removing the need for the module_implements_alter, but that opens you up to a higher maintenance burden. I've seen the same pattern implemented in 7 quite a few times if that helps to reassure – Clive Jul 27 '17 at 17:48
  • It's the same for Drupal 8. if one of the hook implementations returns forbidden, you can't access the node. – José Trindade Jul 27 '17 at 17:55
  • 1
    why not change the weight of your module for it be the last executed ? – Kevin Jul 27 '17 at 23:12
  • if another module implements hook_node_access and marks your node as forbidden, then it will not be shown, even if your own hook is marking it for allowed and is running last. the order by which the modules are run is not relevant. – José Trindade Jul 27 '17 at 23:39
  • 1
    To detect wich module use hook_node_access you can try $grants = \Drupal::moduleHandler()->invokeAll('node_access', [$node, $op, $account]); – florian_drupal Jul 28 '17 at 5:35
0

I believe it's best to not remove the conflict implementation of the same hook (Unless you REALLY need that and you know what you are doing). Instead you can follow the Drupal documentation of hook_module_implements_alter and move your hook to the end of the implementations list to override the conflict and not ignore it at all.

function YOURMODULENAME_module_implements_alter(&$implementations, $hook) {
  if ($hook == 'node_access') {

    // Move my module implementation of node_access to the end of the list.
    // \Drupal::moduleHandler()->getImplementations()
    // iterates through $implementations with a foreach loop which PHP iterates
    // in the order that the items were added, so to move an item to the end of
    // the array, we remove it and then add it.
    $group = $implementations['YOURMODULENAME'];
    unset($implementations['YOURMODULENAME']);
    $implementations['YOURMODULENAME'] = $group;
  }
}
  • That won't work. As stated above, if one of the hook callbacks returns forbidden, you can't access the node. The run order is not relevant. – José Trindade Jun 26 at 11:17

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.