You are here

function chain_menu_access_chain in Chain Menu Access API 8

Same name and namespace in other branches
  1. 6 chain_menu_access.module \chain_menu_access_chain()
  2. 7.2 chain_menu_access.module \chain_menu_access_chain()
  3. 7 chain_menu_access.module \chain_menu_access_chain()

Prepend the given access callback to the chain.

The client module should call this function from its hook_menu_alter() implementation to install its access callback.

NOTE: hook_menu_alter() is called only when the menu router table is rebuilt after the menu cache was flushed.

NOTE: MENU_DEFAULT_LOCAL_TASK items should not specify access parameters but inherit them from their parent item, because access should not be different between the two. If a client module tries to chain to such an item, the item's access parameters are cleared only.

Parameters

array $items: The menu router items array. Do not try to chain MENU_DEFAULT_LOCAL_TASK items -- chain their parent items instead.

string $path: The index into $items to the item to modify.

string $new_access_callback: The name of the client's access callback function, as documented for the 'access callback' key in hook_menu().

array $new_access_arguments: An array holding the arguments to be passed to the new access callback, as documented for the 'access arguments' key in hook_menu().

bool $or_or_pass_index: Pass FALSE to evaluate ($new_access_callback() && $old_access_callback()). Pass TRUE to evaluate ($new_access_callback() || $old_access_callback()). Pass a number to evaluate $old_access_callback() first and then pass the result as the $pass_index-th argument in $new_access_arguments to $new_access_callback().

Return value

bool TRUE if the chaining succeeded, FALSE if a MENU_DEFAULT_LOCAL_TASK item.

1 call to chain_menu_access_chain()
chain_menu_access_test_menu_alter in tests/chain_menu_access_test.module
Implements hook_menu_alter().

File

./chain_menu_access.module, line 50
An API module to help client modules chain their access callbacks into other modules' menu items.

Code

function chain_menu_access_chain(array &$items, $path, $new_access_callback, array $new_access_arguments = array(), $or_or_pass_index = FALSE) {
  $item =& $items[$path];
  if (isset($item['type']) && $item['type'] == MENU_DEFAULT_LOCAL_TASK) {

    // Inherit the parent's access! See http://drupal.org/node/1186208.
    unset($item['access callback'], $item['access arguments']);
    return FALSE;
  }

  // Look through the child items for the MENU_DEFAULT_LOCAL_TASK.
  $child_paths = array_filter(array_keys($items), function ($p) use ($path) {
    return preg_match("#^{$path}/[^/]*\$#", $p);
  });
  foreach ($child_paths as $child_path) {
    $child_item =& $items[$child_path];
    if (isset($child_item['type']) && $child_item['type'] == MENU_DEFAULT_LOCAL_TASK) {

      // The default local task must inherit its access from its parent.
      unset($child_item['access callback'], $child_item['access arguments']);
    }
  }

  // Normalize the menu router item.
  if (!isset($item['access callback']) && isset($item['access arguments'])) {

    // Default callback.
    $item['access callback'] = 'user_access';
  }
  if (!isset($item['access callback'])) {
    $item['access callback'] = 0;
  }
  if (is_bool($item['access callback'])) {
    $item['access callback'] = intval($item['access callback']);
  }
  $old_access_arguments = isset($item['access arguments']) ? $item['access arguments'] : array();
  if (is_bool($new_access_callback)) {
    $new_access_callback = intval($new_access_callback);
  }

  // Prepend a parameter array plus the $new_access_arguments to the existing
  // access arguments array. This works repeatedly, too.
  $or = $or_or_pass_index === TRUE;
  $pass_index = $or_or_pass_index === TRUE ? FALSE : $or_or_pass_index;
  $item['access arguments'] = array_merge(array(
    array(
      $item['access callback'],
      $new_access_callback,
      count($new_access_arguments),
      $or,
      $pass_index,
    ),
  ), $new_access_arguments, $old_access_arguments);
  $item['access callback'] = '_chain_menu_access_callback';
  return TRUE;
}