Eu uso hook_init()
para verificar o último horário de acesso dos usuários. Se o último horário de acesso for ontem, incremento um contador e defino algumas variáveis.
O problema é que hook_init()
algumas vezes é executado mais de uma vez (posso ver isso usando dsm()
) para o mesmo carregamento de página, portanto, meu código é executado várias vezes, resultando em variáveis incorretas.
Por que é hook_init()
executado mais de uma vez?
Qual seria a melhor abordagem para o meu problema? Devo usar outro gancho?
Eu
pesquisei um pouco mais sobre isso: procuro chamadas para o hook_init () (procurei por string module_invoke_all('init');
), mas encontrei apenas a chamada principal). Não sei se isso pode ser chamado de maneira diferente.
Este é o meu hook_init ()
function episkeptis_achievements_init(){
dsm('1st execution');
dsm('REQUEST_TIME: '.format_date(REQUEST_TIME, 'custom', 'd/m/Y H:i:s').' ('.REQUEST_TIME.')');
}
e esta é a saída:
1st execution
REQUEST_TIME: 09/07/2012 11:20:32 (1341822032)
então, alterou a mensagem dsm () para dsm('2nd execution');
e executou novamente, esta é a saída:
1st execution
REQUEST_TIME: 09/07/2012 11:20:34 (1341822034)
2nd execution
REQUEST_TIME: 09/07/2012 11:22:28 (1341822148)
Você pode ver que o código é executado duas vezes. No entanto, a primeira vez que executa uma cópia antiga do código e a segunda vez a cópia atualizada. Há também uma diferença de tempo de 2 segundos.
Esta é uma versão d7 com o php 5.3.10
REQUEST_TIME
seria o mesmo.REQUEST_TIME
vier da mesma solicitação de página, seu valor é o mesmo; não há nem dois segundos de diferença. Verifique se não há código que altere o valor deREQUEST_TIME
.Respostas:
hook_init()
é invocado pelo Drupal apenas uma vez para cada página solicitada; é o último passo realizado em _drupal_bootstrap_full () .Se
hook_init()
estiver sendo executado mais de uma vez, você deve descobrir por que isso acontece. Até onde posso ver, nenhuma dashook_init()
implementações no Drupal verifica se está sendo executada duas vezes (veja, por exemplo, system_init () ou update_init () ). Se isso é algo que normalmente pode acontecer com o Drupal,update_init()
verifique primeiro se ele já foi executado.Se o contador for o número de dias consecutivos em que um usuário efetuou login, eu preferiria implementar
hook_init()
com código semelhante ao seguinte.Se
hook_init()
for chamado duas vezes consecutivas durante a mesma solicitação de página,REQUEST_TIME
conterá o mesmo valor e a função retornaráFALSE
.O código in
mymodule_increase_counter()
não é otimizado; é apenas para mostrar um exemplo. Em um módulo real, eu preferiria usar uma tabela de banco de dados em que o contador e as outras variáveis sejam salvas. O motivo é que as variáveis Drupal são todas carregadas na variável global$conf
quando o Drupal é iniciado ( consulte _drupal_bootstrap_variables () e variable_initialize () ); se você usar variáveis do Drupal para isso, o Drupal carregará na memória informações sobre todos os usuários para os quais você salvou as informações, quando para cada página solicitada houver apenas uma conta de usuário salva na variável global$user
.Se você estiver contando o número de páginas visitadas dos usuários em dias consecutivos, implementaria o código a seguir.
Você notará que no meu código eu não uso
$user->access
. O motivo é que$user->access
poderia ser atualizado durante a inicialização do Drupal, antes dehook_init()
ser chamado. O manipulador de gravação de sessão usado no Drupal contém o seguinte código. (Consulte _drupal_session_write () .)Quanto a outro gancho que você pode usar, com o Drupal 7 você pode usar hook_page_alter () ; você simplesmente não altera o conteúdo de
$page
, mas aumenta seu contador e altera suas variáveis.No Drupal 6, você pode usar hook_footer () , o gancho chamado de template_preprocess_page () . Você não retorna nada, mas aumenta seu contador e altera suas variáveis.
No Drupal 6 e Drupal 7, você pode usar hook_exit () . Lembre-se de que o gancho também é chamado quando a inicialização não está completa; o código não pode ter acesso a funções definidas a partir de módulos ou outras funções do Drupal, e você deve primeiro verificar se essas funções estão disponíveis. Algumas funções estão sempre disponíveis
hook_exit()
, como as definidas em bootstrap.inc e cache.inc . A diferença é quehook_exit()
é invocado também para páginas em cache, enquantohook_init()
não é invocado para páginas em cache.Por fim, como exemplo de código usado em um módulo Drupal, consulte statistics_exit () . O módulo Estatísticas registra as estatísticas de acesso de um site e, como você vê, ele usa
hook_exit()
, nãohook_init()
. Para poder chamar as funções necessárias, ele chama drupal_bootstrap () passando o parâmetro correto, como no código a seguir.Atualizar
Talvez haja alguma confusão sobre quando
hook_init()
é invocado.hook_init()
é chamado para cada solicitação de página, se a página não estiver em cache. Não é chamado uma vez para cada solicitação de página proveniente do mesmo usuário. Se você visitar, por exemplo, http://example.com/admin/appearance/update e http://example.com/admin/reports/status ,hook_init()
será chamado duas vezes: um para cada página."O gancho é chamado duas vezes" significa que há um módulo que executa o código a seguir, depois que o Drupal conclui sua inicialização.
Se for esse o caso, a seguinte implementação de
hook_init()
mostraria o mesmo valor, duas vezes.Se o seu código for exibido para
REQUEST_TIME
dois valores para os quais a diferença é de 2 minutos, como no seu caso, o gancho não será chamado duas vezes, mas será chamado uma vez para cada página solicitada, como deve acontecer.REQUEST_TIME
é definido em bootstrap.inc com a seguinte linha.Até que a página solicitada no momento não seja retornada ao navegador, o valor de
REQUEST_TIME
não será alterado. Se você vir um valor diferente, estará observando o valor atribuído em uma página de solicitação diferente.fonte
Lembro-me disso acontecendo muito no Drupal 6 (não tenho certeza se ainda acontece no Drupal 7), mas nunca descobri o porquê. Eu me lembro de ter visto em algum lugar que o núcleo Drupal não chama esse gancho duas vezes.
Sempre achei que a maneira mais fácil de contornar isso era usar uma variável estática para verificar se o código já foi executado:
Isso garantirá que ele seja executado apenas uma vez em um único carregamento de página.
fonte
hook_init()
implementações, e algumas delas evitariam com prazer serem executadas duas vezes seguidas. Também é provável que o OP desejehook_init()
ser executado uma vez por dia, se o contador contar o número de dias consecutivos em que os usuários efetuaram login no site.hook_init
verifique se já correu uma vez durante o dia e falha se tiver. Então a coisa toda se torna um problema de qualquer maneiraVocê pode achar que hook_init () é chamado várias vezes se houver algum AJAX acontecendo na página (ou você estiver carregando imagens de um diretório privado - embora eu não tenha muita certeza disso). Existem alguns módulos que usam o AJAX para ajudar a ignorar o cache da página para certos elementos, por exemplo - a maneira mais fácil de verificar é abrir o monitor de rede no seu depurador de escolha (firefox ou inspetor da web) e ver se há alguma solicitação são feitas que podem estar acionando o processo de inicialização.
Você só receberá o dpm () na página seguinte se for uma chamada AJAX. Digamos que você atualize a página 5 minutos depois, você receberá a chamada AJAX da mensagem de inicialização de 5 minutos atrás e a nova.
Uma alternativa para hook_init () é hook_boot (), que é chamado antes que qualquer cache seja feito. Ainda não há módulos carregados, então você realmente não tem muita força aqui além de definir variáveis globais e executar algumas funções do Drupal. É útil para ignorar o cache de nível regular (mas não ignora o cache agressivo).
fonte
No meu caso, esse comportamento foi causado pelo módulo Administration Menu (admin_menu).
hook_init não estava sendo chamado a cada solicitação, mas o menu admin faria com que / js / admin_menu / cache / 94614e34b017b19a78878d7b96ccab55 fosse carregado pelo navegador do usuário logo após a solicitação principal, acionando outra inicialização drupal.
Existem outros módulos que fazem coisas semelhantes, mas o admin_menu é provavelmente um dos mais comuns.
fonte