Czy masz przykład wywołania zwrotnego dostępu hook_menu ()?

18

Pobrałem przykłady projektu, ale w menu_example Moduł wszystkie access callbacksą ustawione true.. trudno zrozumieć, jak to działa.

W moim przykładzie mój wpis meno powinien być widoczny w węzłach, ale tylko dla ról, które mają uprawnienia do edycji własnych węzłów.

Nie mogę znaleźć przykładu bardziej szczegółowego wywołania zwrotnego dostępu.

Czy ktoś ma taki?

Strae
źródło

Odpowiedzi:

12

Edycja: Brakowało mi części dotyczącej uprawnienia do „edycji własnego węzła”, ponieważ wtedy musisz nie tylko sprawdzić uprawnienia, ale także czy ten węzeł należy do bieżącego użytkownika. Zaktualizowałem swój przykład poniżej, ale powyższe wyjaśnienie pozostawiam bez zmian.

Czy pozycja menu poniżej węzła / nid (np. Węzeł / 1234 / coś)? Prawdopodobnie nie potrzebujesz nawet niestandardowego połączenia zwrotnego.

Jeśli zdefiniujesz ścieżkę menu jak w poniższym przykładzie, będzie ona wywoływać oddzwanianie dostępu (a zatem i oddzwanianie strony), jeśli przeglądasz prawidłowy węzeł.

'node/%node/something'

Oznacza to, że wywoła node_load (1234) dla powyższego przykładu i będzie kontynuował tylko wtedy, gdy zwrócony zostanie poprawny obiekt węzła. Możesz więc jak zwykle zdefiniować swoje uprawnienie za pomocą argumentów dostępu.

To powiedziawszy, napisanie wywołania zwrotnego dostępu jest naprawdę proste. To tylko funkcja, która odbierze argumenty zdefiniowane w argumentach dostępu. Na przykład, funkcja zwrotna domyślny dostęp jest user_access () i podczas definiowania twoje argumenty dostępu podoba 'access arguments' => array('a permission string'), będzie to prowadzić do następującego zaproszenia: user_access('a permission string').

Jeśli masz wiele argumentów, zostaną one przekazane do funkcji jako drugi, trzeci itd. Aby uzyskać dostęp do aktualnie aktywnego węzła, możesz użyć menu_get_object () .

Możesz więc napisać oddzwonienie dostępu w ten sposób, ale znowu może nie być konieczne utworzenie takiego.

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

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

Zamiast na stałe wpisywać ciąg uprawnień, możesz przekazać go jako argument funkcji lub cokolwiek chcesz zrobić.

Berdir
źródło
nigdy nie mógł osiągnąć ostatni przykład: z $items['node/%node/edit']['access callback'] = 'admin_access_only'; i $node = menu_get_object();w fn oddzwonienia, $nodenigdy nie wrócił niczym. Użyłem zamiast tego, $node = node_load(arg(1)); który działał ... Dalsze wyjaśnienia byłyby bardzo mile widziane
Kojo
19

Drupal sam w sobie jest przykładem pisania kodu.

Prostszym przykładem jest agregator_menu () , który zawiera następujący kod.

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

W takim przypadku wywołanie zwrotne dostępu jest domyślnym ( user_access () ), a argumentami dostępu jest tablica zawierająca ciąg uprawnień. Kod nie może sprawdzić więcej niż pozwolenia; jeśli uprawnienia do sprawdzania są dwa lub warunki sprawdzania nie są tylko uprawnieniami, wówczas wywołanie zwrotne dostępu powinno być inne, w tym niestandardowe.

node_menu () definiuje niektóre menu, które używają wywołania zwrotnego innego niż domyślne. Funkcja zawiera następujący kod.

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

Funkcja zdefiniowana jako wywołanie zwrotne dostępu ( node_access () ) jest następująca:

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

Należy zwrócić uwagę na trzy punkty:

  • Argumenty zadeklarowane za pomocą „argumentów dostępu” zostaną przekazane do funkcji w tej samej kolejności; funkcja używa trzeciego parametru, ponieważ nie jest używana tylko do wywołania zwrotnego.
  • Funkcja zwraca, TRUEjeśli użytkownik ma dostęp do menu i FALSEjeśli użytkownik nie ma dostępu do menu.
  • Oddzwonienia dostępu można również użyć, gdy menu powinno być wyświetlane tylko w określonych okolicznościach.
kiamlaluno
źródło
Kiedy deklarujesz niestandardową access callbackfunkcję, wydaje się, że musi ona znajdować się w twoim .modulepliku, ponieważ Drupal nie może znaleźć jej w filedeklaracji (przynajmniej dla mnie).
tyler.frankenstein