You are here

function _acb_cascade_grants in Access Control Bridge 7

Same name and namespace in other branches
  1. 8 acb.module \_acb_cascade_grants()

The beating heart of this module. Receives split-sorted grants and converts it into cascaded grants to be used by this module. Workhorse for both hook_node_grants_alter() and hook_node_access_records_alter().

Parameters

array $grants: The recursive grants array.

bool $access_records: (optional) Boolean indicating if we should cascade access records (TRUE) or not user grants (FALSE)

array $output: (optional) The final output array used for recursing.

array $realm: (optional) The realm storage array used for recursing.

bool $view: (optional) The grant_view value used for recursing.

bool $update: (optional) The grant_update value used for recursing.

bool $delete: (optional) The grant_delete value used for recursing.

Return value

array The output grants array.

2 calls to _acb_cascade_grants()
acb_node_access_records_alter in ./acb.module
Implements hook_node_access_records_alter().
acb_node_grants_alter in ./acb.module
Implements hook_node_grants_alter().

File

./acb.module, line 235
Drupal hooks and functions for the acb module.

Code

function _acb_cascade_grants($grants, $access_records = FALSE, &$output = array(), $realm = array(), $view = 1, $update = 1, $delete = 1) {

  // Let's make any possible cross-combination respecting the given element order of $grants.
  if (count($grants)) {

    // This nesting level has available combinations left.
    foreach (reset($grants) as $grant) {

      // Assemble new pieces for the realm.
      $realm_storage = $realm;
      $realm_storage[] = $grant['realm'] . '+' . $grant['gid'];

      // Try to go one level deeper.
      $grants_storage = array_slice($grants, 1);

      // The recursive function is called differently for node access records and user grants.
      if ($access_records) {

        // We can use simple math to cascade each node access record grant value:
        // multiplication ensures that zeros (deny) are retained throughout cascading
        // while a one (allow) is only possible if all cascaded grants allow access.
        _acb_cascade_grants($grants_storage, $access_records, $output, $realm_storage, $view * $grant['grant_view'], $update * $grant['grant_update'], $delete * $grant['grant_delete']);
      }
      else {

        // For the user grants we call the recursive function twice: once using the updated realm and once pretending the realm wouldn't exist.
        _acb_cascade_grants($grants_storage, $access_records, $output, $realm);
        _acb_cascade_grants($grants_storage, $access_records, $output, $realm_storage);
      }
    }
  }

  // Create a record for this combination if:
  //  - in case of access records: there are no remaining nesting levels
  //  - in case of user grants: always!
  if (!count($grants) || !$access_records) {

    // Prepend 'acb' to comply to best practice of prefixing realms with the name of their responsible module.
    $final_realm = 'acb&' . implode('&', $realm);

    // Finished combination; save it.
    // Exclude empty access record grants as they are useless and only take up memory.
    if ($access_records && ($view || $update || $delete)) {

      // Node access record.
      $output[$final_realm] = array(
        'realm' => $final_realm,
        'gid' => 0,
        'grant_view' => (int) $view,
        'grant_update' => (int) $update,
        'grant_delete' => (int) $delete,
        'priority' => 100,
      );
    }
    elseif (!$access_records) {

      // User grant.
      if (!empty($realm)) {
        $output[$final_realm] = array(
          0,
        );
      }
    }
  }
  return $output;
}