Como devo implementar hook_menu ()?

103

Quais são os fundamentos da implementação hook_menu()?

Gostaria de ver o básico abordado em uma única pergunta, para evitar ter que responder repetidamente as mesmas perguntas semelhantes, mas diferentes.

Letharion
fonte

Respostas:

148

Esta informação é válida para o Drupal 6 e 7. No Drupal 8, hook_menu()foi substituído por um novo sistema de roteamento . Abaixo, implementamos hook_menu()em três etapas simples.

Passo um

Crie um módulo vazio seguindo as instruções em Como criar um módulo vazio . No código mostrado aqui, supõe-se que o módulo seja chamado helloworld .

Passo dois

Adicione o seguinte código ao arquivo do módulo.

/**
 * Implements hook_menu().
 */
function helloworld_menu() {
  $items['hello'] = array(
    'title' => 'Hello world!',
    'page callback' => 'helloworld_page',
    'access callback' => TRUE,
  );

  return $items;
}

/**
 * Page callback for /hello.
 */
function helloworld_page() {
  return 'Hello world!';
}

Passo três

Habilite o módulo e visite http://example.com/hello . (Substitua example.com pelo nome de domínio do seu servidor.)
Você deverá ver a mensagem "Olá, mundo!". É isso aí! Você tem uma hook_menu()implementação totalmente funcional . A seguir, são apresentados vários tópicos mais avançados hook_menu(). Em particular, convém ler sobre permissões, pois a página acima poderá ser visualizada por qualquer pessoa.

Argumentos

Se você quiser passar mais dados para o retorno de chamada da página, poderá usar argumentos da página para conseguir isso. Os argumentos da página devem ser uma matriz de argumentos a serem transmitidos para o retorno de chamada da página. Se um número inteiro for usado como argumento, ele representará uma parte da URL, iniciando em 0, incrementada uma vez para cada barra (/). No exemplo a seguir, isso significa que o 0 será transformado em 'olá'.

function helloworld_menu() {
  $items['hello'] = array(
    'page callback' => 'helloworld_page',
    'page arguments' => array(0),
  );

  return $items;
}

function helloworld_page($argument1) {
  return $argument1;
}

As strings serão enviadas literalmente, para que array(0, 'world')possam ser usadas hello worldnovamente.

function helloworld_page($argument1, $argument2) {
  return $argument1 . ' ' . $argument2;
}

"Curingas" podem ser usados ​​para aceitar dados arbitrários do URL.

function helloworld_menu() {
  $items['hello/%'] = array(
    'page callback' => 'helloworld_page',
    'page arguments' => array(1),
  );

  return $items;
}

function helloworld_page($argument1) {
  return $argument1;
}

Visitar olá / mundo $argument1será igual world.

Carregamento automático de argumento

Geralmente, um argumento de URL será o número que identifica, por exemplo, uma entidade. Para evitar a duplicação do código que converte esse ID no objeto correspondente, o Drupal oferece suporte ao carregamento automático para curingas "nomeados". Quando um curinga nomeado é usado, o Drupal verifica se há uma função com o mesmo nome que o curinga, com o sufixo _load. Se essa função for encontrada, ela será chamada com o valor do valor na URL e o que for retornado pela função loader será passado para o retorno de chamada da página no lugar do valor original. Como o Drupal já possui essa função para carregar nós node_load(), podemos obter nós carregados automaticamente e passados ​​para o retorno de chamada da página.

function helloworld_menu() {
  $items['hello/%node'] = array(
    'page callback' => 'helloworld_page',
    'page arguments' => array(1),
  );

  return $items;
}

function helloworld_page($node) {
  return t('Hello node (ID = !nid)', array('!nid' => $node->nid));
}

Carregamento automático avançado

Às vezes, será necessário carregar automaticamente mais com base em mais de um argumento. Como apenas o argumento nomeado é passado para o carregador por padrão, é necessário informar explicitamente ao Drupal quais argumentos de carga extra devem ser passados ​​para o carregador. Por exemplo, para carregar uma revisão específica de um nó, é necessário passar para node_load()um ID de nó e um ID de revisão. Isso pode ser realizado pelo seguinte código.

function helloworld_menu() {
  $items['hello/%node/revision/%'] = array(
    'page callback' => 'helloworld_page',
    'page arguments' => array(1),
    'load arguments' => array(3),
  );

  return $items;
}

function helloworld_page($node) {
  return t('Hello node (ID = !nid, revision ID = !rid)', array('!nid' => $node->nid, '!rid' => $node->vid));
}

Permissões

'access callback' => TRUE,é necessário tornar visível o exemplo simples acima, mas dificilmente é o ideal, pois não permite nenhum controle. Qualquer pessoa que tentar visitar / olá terá acesso concedido. A maneira mais fácil de fornecer alguma medida de controle é fornecer um retorno de chamada de acesso, semelhante ao retorno de página da página acima. O código a seguir ainda permite acesso a qualquer pessoa, mas mostra como mover a lógica para uma função chamada no momento do acesso, permitindo uma lógica mais complexa.

/**
 * Implements hook_menu().
 */
function helloworld_menu() {
  $items['hello'] = array(
    'page callback' => 'helloworld_page',
    'access callback' => 'helloworld_access',
  );

  return $items;
}

/**
 * Access callback for /hello.
 */
function helloworld_access() {
  return TRUE;
}

Esta não é necessariamente a melhor maneira, pois o uso de uma função personalizada geralmente duplicará desnecessariamente o código. Uma maneira melhor será, na maioria das vezes, usar user_access(). Juntos, o retorno de chamada de acesso é possível definir argumentos de acesso. É possível exigir que a página seja visível pelos usuários com a permissão de acessar perfis de usuário com o código a seguir.

/**
 * Implements hook_menu().
 */
function helloworld_menu() {
  $items['hello'] = array(
    'page callback' => 'helloworld_page',
    'access callback' => 'user_access',
    'access arguments' => array('access user profiles'),
  );

  return $items;
}

Como o retorno de chamada de acesso, por padrão, é user_access, ele pode ser deixado de fora, como no código acima.

Tópicos mais avançados

A hook_menu()documentação oficial fornece muito mais informações sobre os casos de uso mais complexos do gancho.

Letharion
fonte
3
Impressionante! Por uma questão de completude, a titlepropriedade é necessária para todos os itens devolvidos dehook_menu()
Clive
1
Eu sei que os documentos dizem isso, mas quando eu testei no D7, esse não foi o caso. Eu poderia adicioná-lo ao primeiro exemplo, eu acho, mas queria manter as coisas no mínimo absoluto para facilitar o máximo possível.
Letharion
1
Eu diria que adicionar um título a uma página é uma das coisas mínimas absolutas que você poderia querer fazer com hook_menu (), mas é o seu post: P Talvez valha a pena corrigir os erros de sintaxe (exemplos de código 2, 4, 5 e 6), para que as pessoas possam copiar e colar
Clive
1
Argh, inicialmente fui diligente na execução do código, mas com o passar do tempo fiquei mais desleixado e comecei a copiar e colar. Corrigimos os erros de sintaxe, pelo menos aqueles que eu vi;) Bem, você está certo que deveria haver um título, é claro, então adicionei um ao exemplo inicial.
Letharion
1
Como registrar um arquivo php em um caminho usando hook_menu? É um arquivo php escrito personalizado que inclui o drupal bootstrap, usa variáveis ​​de sessão drupal e aceita um argumento que é um ID de usuário.
Елин Й.