Hai un esempio di callback di accesso hook_menu ()?


18

Ho scaricato il progetto di esempio , ma nel modulo menu_example tutti access callbacksono impostati su true... difficile capire come funziona.

Nel mio esempio, la voce meno dovrebbe essere visibile sui nodi, ma solo per i ruoli che dispongono delle autorizzazioni per modificare i propri nodi.

Non riesco a trovare un esempio un po 'più dettagliato di un callback di accesso.

Qualcuno ne ha uno?

Risposte:


12

Modifica: mi è sfuggita la parte relativa all'autorizzazione "modifica nodo proprio", perché non solo è necessario controllare l'autorizzazione, ma anche se quel nodo appartiene all'utente corrente. Ho aggiornato il mio esempio di seguito, ma lascio la spiegazione sopra così com'era.

La tua voce di menu è sotto node / nid (es. Node / 1234 / qualcosa)? Quindi probabilmente non è nemmeno necessario un callback di accesso personalizzato.

Se definisci il tuo percorso di menu come nell'esempio seguente, chiamerà solo il callback di accesso (e quindi il callback della pagina), se stai visualizzando un nodo valido.

'node/%node/something'

Ciò significa che chiamerà node_load (1234) per l'esempio sopra e continuerà solo se viene restituito un oggetto nodo valido. Quindi puoi definire la tua autorizzazione con argomenti di accesso come al solito.

Detto questo, scrivere un callback di accesso è davvero semplice. È solo una funzione che riceverà qualsiasi argomento definito negli argomenti di accesso. Ad esempio, il callback di accesso predefinito è user_access () e quando si definiscono i tuoi argomenti di accesso come 'access arguments' => array('a permission string'), il risultato sarà la seguente chiamata: user_access('a permission string').

Se hai più argomenti, questi verranno passati come secondo, terzo e così via alla tua funzione. Per accedere al nodo attualmente attivo, è possibile utilizzare menu_get_object () .

Quindi potresti scrivere il callback di accesso in questo modo, ma potresti non aver nemmeno bisogno di crearne uno.

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

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

Invece di codificare la stringa di autorizzazione, potresti passarla come argomento alla funzione o qualunque cosa tu voglia fare.


non avrei mai potuto raggiungere l'ultimo esempio: con $items['node/%node/edit']['access callback'] = 'admin_access_only'; e $node = menu_get_object();nel callback fn, $nodenon ho mai restituito nulla. Ho usato invece quello $node = node_load(arg(1)); che ha funzionato ... Ulteriori spiegazioni sarebbero davvero ben accette
Kojo

19

Drupal è esso stesso un esempio di come scrivere codice.

L'esempio più semplice è aggregator_menu () , che contiene il seguente codice.

  $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 questo caso, il callback di accesso è l'impostazione predefinita ( user_access () ) e gli argomenti di accesso sono un array contenente la stringa per l'autorizzazione. Il codice non può controllare più di un'autorizzazione; se le autorizzazioni da verificare sono due o le condizioni da verificare non sono solo autorizzazioni, il callback di accesso dovrebbe essere diverso, incluso uno personalizzato.

node_menu () definisce alcuni menu che utilizzano un callback di accesso diverso da quello predefinito. La funzione contiene il seguente codice.

  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',
    );
  }

La funzione definita come callback di accesso ( node_access () ) è la seguente:

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;
}

Vi sono tre punti da notare:

  • Gli argomenti dichiarati con "argomenti di accesso" verranno passati alla funzione nello stesso ordine; la funzione utilizza un terzo parametro perché non viene utilizzato solo per accedere al callback.
  • La funzione ritorna TRUEse l'utente ha accesso al menu e FALSEse l'utente non ha accesso al menu.
  • Un callback di accesso può essere utilizzato anche quando un menu deve essere visualizzato solo in circostanze specifiche.

Quando dichiari una access callbackfunzione personalizzata , sembra che debba risiedere nel tuo .modulefile, perché Drupal non riesce a trovarlo nella filedichiarazione (almeno per me).
tyler.frankenstein,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.