Haben Sie ein Beispiel für einen Hook_Menu () -Zugriffsrückruf?


18

Ich habe das Beispielprojekt heruntergeladen , aber im Modul menu_example sind alle access callbackauf true.. schwer zu verstehen, wie es funktioniert.

In meinem Beispiel sollte mein Menüeintrag auf Knoten sichtbar sein, jedoch nur für Rollen, die über die Berechtigung zum Bearbeiten eigener Knoten verfügen.

Ein etwas ausführlicheres Beispiel für einen Access Callback kann ich nicht finden.

Hat jemand eine?

Antworten:


12

Bearbeiten: Ich habe den Teil über die Berechtigung "Eigenen Knoten bearbeiten" verpasst, da Sie dann nicht nur die Berechtigung überprüfen müssen, sondern auch, ob dieser Knoten dem aktuellen Benutzer gehört. Ich habe mein Beispiel unten aktualisiert, lasse aber die obige Erklärung unverändert.

Befindet sich Ihr Menüeintrag unter node / nid (zB node / 1234 / something)? Dann brauchen Sie wahrscheinlich nicht einmal einen benutzerdefinierten Rückruf.

Wenn Sie Ihren Menüpfad wie im folgenden Beispiel definieren, wird der Zugriffsrückruf (und damit der Seitenrückruf) nur aufgerufen, wenn Sie einen gültigen Knoten anzeigen.

'node/%node/something'

Dies bedeutet, dass es für das obige Beispiel node_load (1234) aufruft und nur dann fortfährt, wenn ein gültiges Knotenobjekt zurückgegeben wird. So können Sie Ihre Berechtigung wie gewohnt mit Zugriffsargumenten definieren.

Das Schreiben eines Zugriffsrückrufs ist jedoch sehr einfach. Es ist nur eine Funktion, die alle Argumente empfängt, die Sie in den Zugriffsargumenten definiert haben. Zum Beispiel ist der Standard - Zugriffs Rückruf user_access () und wenn Sie Ihren Zugang Argumente wie definieren 'access arguments' => array('a permission string'), wird es in dem folgenden Aufruf zur Folge: user_access('a permission string').

Wenn Sie mehrere Argumente haben, werden diese als zweites, drittes usw. Argument an Ihre Funktion übergeben. Um auf den aktuell aktiven Knoten zuzugreifen, können Sie menu_get_object () verwenden .

Sie könnten also Ihren Access Callback wie folgt schreiben, müssen aber möglicherweise noch nicht einmal einen erstellen.

function yourmodule_access_check() {
  global $user;
  $node = menu_get_object();

  return $node && $node->uid == $user->uid && user_access('edit own ' . $node->type . ' content');
}

Anstatt die Berechtigungszeichenfolge fest zu codieren, können Sie sie als Argument an die Funktion übergeben oder was auch immer Sie tun möchten.


konnte nie das letzte Beispiel erreichen: mit $items['node/%node/edit']['access callback'] = 'admin_access_only'; und $node = menu_get_object();im Callback fn, gab $nodenie etwas zurück. Ich habe stattdessen verwendet, $node = node_load(arg(1)); was funktioniert ... Weitere Erklärungen wären wirklich willkommen
Kojo

19

Drupal ist selbst ein Beispiel für das Schreiben von Code.

Das einfachere Beispiel ist aggregator_menu () , das den folgenden Code enthält.

  $items['admin/config/services/aggregator'] = array(
    'title' => 'Feed aggregator', 
    'description' => "Configure which content your site aggregates from other sites, how often it polls them, and how they're categorized.", 
    'page callback' => 'aggregator_admin_overview', 
    'access arguments' => array('administer news feeds'), 
    'weight' => 10, 
    'file' => 'aggregator.admin.inc',
  );
  $items['admin/config/services/aggregator/add/feed'] = array(
    'title' => 'Add feed', 
    'page callback' => 'drupal_get_form', 
    'page arguments' => array('aggregator_form_feed'), 
    'access arguments' => array('administer news feeds'), 
    'type' => MENU_LOCAL_ACTION, 
    'file' => 'aggregator.admin.inc',
  );

In diesem Fall ist der Zugriffsrückruf der Standardwert ( user_access () ), und die Zugriffsargumente sind ein Array, das die Zeichenfolge für die Berechtigung enthält. Der Code kann nicht mehr als eine Berechtigung prüfen. Wenn die zu überprüfenden Berechtigungen zwei sind oder die zu überprüfenden Bedingungen nicht nur Berechtigungen sind, sollte der Zugriffsrückruf ein anderer sein, einschließlich eines benutzerdefinierten.

node_menu () definiert einige Menüs, die einen vom Standard abweichenden Zugriffsrückruf verwenden. Die Funktion enthält den folgenden Code.

  foreach (node_type_get_types() as $type) {
    $type_url_str = str_replace('_', '-', $type->type);
    $items['node/add/' . $type_url_str] = array(
      'title' => $type->name, 
      'title callback' => 'check_plain', 
      'page callback' => 'node_add', 
      'page arguments' => array($type->type), 
      'access callback' => 'node_access', 
      'access arguments' => array('create', $type->type), 
      'description' => $type->description, 
      'file' => 'node.pages.inc',
    );
  }

Die als Zugriffsrückruf ( node_access () ) definierte Funktion ist die folgende:

function node_access($op, $node, $account = NULL) {
  $rights = &drupal_static(__FUNCTION__, array());

  if (!$node || !in_array($op, array('view', 'update', 'delete', 'create'), TRUE)) {
    // If there was no node to check against, or the $op was not one of the
    // supported ones, we return access denied.
    return FALSE;
  }
  // If no user object is supplied, the access check is for the current user.
  if (empty($account)) {
    $account = $GLOBALS['user'];
  }

  // $node may be either an object or a node type. Since node types cannot be
  // an integer, use either nid or type as the static cache id.

  $cid = is_object($node) ? $node->nid : $node;

  // If we've already checked access for this node, user and op, return from
  // cache.
  if (isset($rights[$account->uid][$cid][$op])) {
    return $rights[$account->uid][$cid][$op];
  }

  if (user_access('bypass node access', $account)) {
    $rights[$account->uid][$cid][$op] = TRUE;
    return TRUE;
  }
  if (!user_access('access content', $account)) {
    $rights[$account->uid][$cid][$op] = FALSE;
    return FALSE;
  }

  // We grant access to the node if both of the following conditions are met:
  // - No modules say to deny access.
  // - At least one module says to grant access.
  // If no module specified either allow or deny, we fall back to the
  // node_access table.
  $access = module_invoke_all('node_access', $node, $op, $account);
  if (in_array(NODE_ACCESS_DENY, $access, TRUE)) {
    $rights[$account->uid][$cid][$op] = FALSE;
    return FALSE;
  }
  elseif (in_array(NODE_ACCESS_ALLOW, $access, TRUE)) {
    $rights[$account->uid][$cid][$op] = TRUE;
    return TRUE;
  }

  // Check if authors can view their own unpublished nodes.
  if ($op == 'view' && !$node->status && user_access('view own unpublished content', $account) && $account->uid == $node->uid && $account->uid != 0) {
    $rights[$account->uid][$cid][$op] = TRUE;
    return TRUE;
  }

  // If the module did not override the access rights, use those set in the
  // node_access table.
  if ($op != 'create' && $node->nid) {
    if (module_implements('node_grants')) {
      $query = db_select('node_access');
      $query->addExpression('1');
      $query->condition('grant_' . $op, 1, '>=');
      $nids = db_or()->condition('nid', $node->nid);
      if ($node->status) {
        $nids->condition('nid', 0);
      }
      $query->condition($nids);
      $query->range(0, 1);

      $grants = db_or();
      foreach (node_access_grants($op, $account) as $realm => $gids) {
        foreach ($gids as $gid) {
          $grants->condition(db_and()
            ->condition('gid', $gid)
            ->condition('realm', $realm)
          );
        }
      }
      if (count($grants) > 0) {
        $query->condition($grants);
      }
      $result =  (bool) $query
        ->execute()
        ->fetchField();
      $rights[$account->uid][$cid][$op] = $result;
      return $result;
    }
    elseif (is_object($node) && $op == 'view' && $node->status) {
      // If no modules implement hook_node_grants(), the default behavior is to
      // allow all users to view published nodes, so reflect that here.
      $rights[$account->uid][$cid][$op] = TRUE;
      return TRUE;
    }
  }

  return FALSE;
}

Es gibt drei Punkte zu beachten:

  • Die mit "Zugriffsargumenten" deklarierten Argumente werden in derselben Reihenfolge an die Funktion übergeben. Die Funktion verwendet einen dritten Parameter, da dieser nicht nur für den Zugriffsrückruf verwendet wird.
  • Die Funktion kehrt zurück, TRUEwenn der Benutzer Zugriff auf das Menü hat und FALSEwenn der Benutzer keinen Zugriff auf das Menü hat.
  • Ein Zugriffsrückruf kann auch verwendet werden, wenn ein Menü nur unter bestimmten Umständen angezeigt werden soll.

Wenn Sie eine benutzerdefinierte access callbackFunktion deklarieren , muss sie in Ihrer .moduleDatei gespeichert sein, da Drupal sie file(zumindest für mich) nicht in der Deklaration zu finden scheint .
tyler.frankenstein
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.