Como adiciono uma condição de acesso a um item de menu?

17

Como posso adicionar novas condições sobre as condições existentes que determinam se um item de menu está visível? Essas condições não devem se limitar às configurações de permissões.

Como exemplo de caso de uso (não necessariamente o motivo desta pergunta): suponha que eu tenha um tipo de conteúdo do qual os usuários tenham permissão para criar apenas um nó. Eu tenho um item de menu para adicionar esse tipo de conteúdo. Mas se o usuário já criou um nó desse tipo de conteúdo, desejo ocultar o item de menu. Meu primeiro pensamento é executar uma consulta para verificar a existência de um nó criado pelo usuário atual que é do tipo de conteúdo específico. Se existir, oculte o item de menu.

Eu acho que esse tipo de funcionalidade deve entrar hook_menu_alter()e adicionar a lógica necessária lá. Mas não tenho certeza de como fazer isso sem ignorar as verificações existentes, como verificar se o usuário tem permissões para criar esse tipo de conteúdo. Eu precisaria incluir essa lógica em minha própria condição? Ou posso adicionar à lógica de acesso existente sem substituí-la?


Editar: algumas pessoas parecem focadas em responder "como faço para limitar um usuário a criar um nó de um tipo de conteúdo". Essa não é a questão aqui. A questão é como adicionar condições de acesso personalizadas a um item de menu.

Chaulky
fonte

Respostas:

11

O que você precisa fazer é adicionar seu retorno de chamada via hook_menu_alter () e, dentro do retorno de chamada, você simplesmente faz sua lógica e retorna os dados pelo retorno de chamada original.

Para ter certeza de que você não substituirá nenhuma outra alteração hook_menu_alter (), você deve passar o retorno de chamada anterior para o retorno de chamada através do argumento de acesso.

Tudo isso é teórico, mas o código deve ser algo como isto:

MYMODULE_menu_alter(&$items) {
  $items['menu']['access arguments'] = array_merge(array($items['menu']['access callback']), $item['menu']['access arguments']);
  $items['menu']['access callback'] = 'MYMODULE_access_callback';
}

MYMODULE_access_callback() {
  $args = func_get_args();

  // Do Stuff.
  if ($something == FALSE) {
    return FALSE;
  }

  $function = array_shift($args);
  return call_user_func_array($function, $args);
}
Decifrar
fonte
portanto, se eu atribuir uma nova função de retorno de chamada de acesso, isso definitivamente substituirá o retorno de chamada original?
Chaulky
Sim, você pode ter apenas um retorno de chamada de acesso por item de menu, portanto, certifique-se de retornar ao retorno de chamada original. Eu vi um módulo que faz algo parecido com isto, um dos módulos pesados ​​de permissões, mas não consigo lembrar qual deles.
Decipher
o que está fazendo o array_shift em $ args?
Chaulky
Ele extrai o primeiro argumento dos 'argumentos de acesso', que criamos no antigo 'retorno de chamada de acesso'. Portanto, se o retorno de chamada antigo era 'MYMODULE2_access_callback', é isso que array_shift está retornando. Também o remove da matriz, para que apenas passemos os argumentos que o retorno de chamada está esperando.
Decipher
1

Em resposta aos comentários acima, a solução em D7 seria usar:

/**
 * Implements hook_node_access().
 */
function mymodule_node_access($node, $op, $account) {
  $type = is_string($node) ? $node : $node->type;

  if ($op == 'create' && $type == 'mynodetype' && db_query("SELECT 1 FROM {node} WHERE type = :type AND uid = :uid", array(':type' => $type, ':uid' => $account->uid))->fetchField()) {
    // If the user has already created a node of a specific type, they cannot
    // create any more.
    return NODE_ACCESS_DENY;
  }

  // Otherwise do not affect any node access.
  return NODE_ACCESS_IGNORE;
}
Dave Reid
fonte
1
Parece que isso não tem nada a ver com itens de menu. Ainda não estou muito familiarizado com o D7, mas parece que isso é específico para a criação de nós. A questão está focada nos itens de menu em geral.
Chaulky 17/03/11
Ah, entendo ... isso é uma resposta ao meu comentário, pedindo mais detalhes sobre sua solução D7 sugerida na sua resposta que aponta para o módulo Limite de Nó. Ainda um pouco fora de tópico, mas apreciado.
Chaulky 17/03/11
Porque a visibilidade dos links criam mynodetype é controlado pela função node_access (), que iria invocar esse gancho no Drupal 7
Dave Reid
1

Você está procurando o módulo da API de acesso ao menu em cadeia .

A API de encadeamento de acesso ao menu permite que seu módulo encadeie suas próprias funções de retorno de chamada de acesso ao menu nas entradas do roteador de menu de outros módulos.

Há pelo menos um exemplo no Drupal Stack Exchange de como usá-lo.

Crantok
fonte
-1

Uma opção seria criar uma nova função que tenha permissão para criar conteúdo para o seu tipo de conteúdo. Depois que um usuário cria um nó desse tipo, retire essa função e ele não poderá mais criar.

cjworden
fonte
-1

Talvez você deva tentar o módulo Limite de Nó .

Na página do projeto:

O módulo Limite de nós permite que os administradores restrinjam o número de nós de um tipo específico que funções ou usuários podem criar. Por exemplo, se um site tiver uma função "Anunciante" que possa criar nós de "anúncio", o administrador do limite de nós poderá restringir todos os usuários nessa função a um número específico de nós. Ele também pode restringir os usuários por usuário.

Dave Reid
fonte
Limitar a um nó é apenas um exemplo de caso de uso para adicionar um método de retorno de chamada de acesso personalizado. Além disso, o Node Limit não remove o item de menu, apenas impede que o usuário adicione outro nó desse tipo de conteúdo.
Chaulky
Isso é verdade agora que olho novamente a descrição do módulo. Se isso estivesse no Drupal 7, seria realmente fácil, pois você pode usar hook_node_access ($ node, 'create', $ account), o que afetaria a visibilidade do próprio link do tipo de nó de criação.
Dave Reid
Isso é interessante. Eu pretendo mudar para D7 em breve. você se importaria de escrever com mais detalhes e postar uma resposta?
Chaulky 13/03/11
Versão D7 da resposta postada.
Dave Reid