Você tem um exemplo de retorno de chamada de acesso hook_menu ()?

18

Eu baixei o projeto de exemplos , mas no módulo menu_example todos access callbackestão definidos como true... difíceis de entender como ele funciona.

No meu exemplo, minha entrada de menu deve estar visível nos nós, mas apenas para funções que tenham permissões para editar seus próprios nós.

Não consigo encontrar um exemplo um pouco mais detalhado de um retorno de chamada de acesso.

Alguém tem um?

Strae
fonte

Respostas:

12

Editar: eu perdi a parte sobre a permissão "editar nó próprio", porque você deve não apenas verificar a permissão, mas também se esse nó pertence ao usuário atual. Atualizei meu exemplo abaixo, mas estou deixando a explicação acima como estava.

A sua entrada de menu está abaixo de node / nid (por exemplo, node / 1234 / alguma coisa)? Então você provavelmente nem precisa de um retorno de chamada de acesso personalizado.

Se você definir o caminho do menu como no exemplo a seguir, ele chamará apenas o retorno de chamada de acesso (e, portanto, o retorno de chamada da sua página), se estiver visualizando um nó válido.

'node/%node/something'

Isso significa que ele chamará node_load (1234) para o exemplo acima e só continuará se um objeto de nó válido for retornado. Assim, você pode definir sua permissão com argumentos de acesso, como de costume.

Dito isto, escrever um retorno de chamada de acesso é realmente simples. É apenas uma função que receberá os argumentos que você definiu nos argumentos de acesso. Por exemplo, o retorno de chamada de acesso padrão é user_access () e, quando você define seus argumentos de acesso 'access arguments' => array('a permission string'), resultará na seguinte chamada:user_access('a permission string') .

Se você tiver vários argumentos, eles serão passados ​​como segundo, terceiro e assim por diante à sua função. Para acessar o nó ativo no momento, você pode usar menu_get_object () .

Assim, você pode escrever seu retorno de chamada de acesso dessa maneira, mas, novamente, talvez nem seja necessário criar um.

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

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

Em vez de codificar a string de permissão, você pode passá-la como argumento para a função ou o que você deseja fazer.

Berdir
fonte
nunca poderia alcançar o último exemplo: com $items['node/%node/edit']['access callback'] = 'admin_access_only'; e $node = menu_get_object();no retorno de chamada fn, $nodenunca retornou nada. Eu costumava vez $node = node_load(arg(1)); que trabalhou ... Mais explicações seriam muito bem-vindos
Kojo
19

O próprio Drupal é um exemplo de como escrever código.

O exemplo mais fácil é o agregator_menu () , que contém o seguinte código.

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

Nesse caso, o retorno de chamada de acesso é o padrão ( user_access () ) e os argumentos de acesso são uma matriz que contém a cadeia de caracteres da permissão. O código não pode verificar mais do que uma permissão; se as permissões para verificar forem duas ou as condições para verificar não forem apenas permissões, o retorno de chamada de acesso deverá ser diferente, incluindo um personalizado.

node_menu () define alguns menus que usam um retorno de chamada de acesso diferente do padrão. A função contém o seguinte código.

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

A função definida como retorno de chamada de acesso ( node_access () ) é a seguinte:

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

Há três pontos a serem observados:

  • Os argumentos declarados com "argumentos de acesso" serão passados ​​para a função na mesma ordem; a função usa um terceiro parâmetro porque não é usado apenas para acessar o retorno de chamada.
  • A função retornará TRUEse o usuário tiver acesso ao menu e FALSEse o usuário não tiver acesso ao menu.
  • Um retorno de chamada de acesso também pode ser usado quando um menu deve ser exibido apenas em circunstâncias específicas.
kiamlaluno
fonte
Ao declarar uma access callbackfunção personalizada , parece que ela deve estar no seu .modulearquivo, porque o Drupal parece não encontrá-la na filedeclaração (pelo menos para mim).
tyler.frankenstein