Utilizo hook_init()
para verificar el último tiempo de acceso de los usuarios. Si el último tiempo de acceso es ayer, incremente un contador y establezco algunas variables.
El problema es que a hook_init()
veces se ejecuta más de una vez (puedo ver esto usando dsm()
) para la misma carga de página, por lo que mi código se ejecuta varias veces dando como resultado variables incorrectas.
¿Por qué se hook_init()
ejecuta más de una vez?
¿Cuál sería el mejor enfoque para mi problema? ¿Debo usar otro gancho?
Investigué un poco más sobre esto: busco llamadas al hook_init () (busqué cadena module_invoke_all('init');
) pero encontré solo la llamada principal). No sé si esto se puede llamar de manera diferente.
Este es mi 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.')');
}
y esta es la salida:
1st execution
REQUEST_TIME: 09/07/2012 11:20:32 (1341822032)
luego, cambió el mensaje dsm () dsm('2nd execution');
y ejecutó nuevamente, esta es la salida:
1st execution
REQUEST_TIME: 09/07/2012 11:20:34 (1341822034)
2nd execution
REQUEST_TIME: 09/07/2012 11:22:28 (1341822148)
Puede ver que el código se ejecuta dos veces. Sin embargo, la primera vez ejecuta una copia antigua del código y la segunda vez la copia actualizada. También hay una diferencia de tiempo de 2 segundos.
Esta es una versión d7 con php 5.3.10
REQUEST_TIME
sería el mismo.REQUEST_TIME
proviene de la misma solicitud de página, su valor es el mismo; Ni siquiera hay una diferencia de dos segundos. Verifique que no haya código que altere el valor deREQUEST_TIME
.Respuestas:
hook_init()
Drupal invoca solo una vez para cada página solicitada; Es el último paso realizado en _drupal_bootstrap_full () .Si
hook_init()
se ejecuta más de una vez, debe descubrir por qué sucede eso. Hasta donde puedo ver, ninguna de lashook_init()
implementaciones en Drupal comprueba que se esté ejecutando dos veces (ver, por ejemplo, system_init () o update_init () ). Si eso es algo que normalmente puede suceder con Drupal,update_init()
primero verificará si ya se ha ejecutado.Si el contador es el número de días consecutivos que un usuario inició sesión, preferiría implementar un
hook_init()
código similar al siguiente.Si
hook_init()
se invoca dos veces seguidas durante la misma solicitud de página,REQUEST_TIME
contiene el mismo valor y la función volveríaFALSE
.El código
mymodule_increase_counter()
no está optimizado; es solo para mostrar un ejemplo. En un módulo real, prefiero usar una tabla de base de datos donde se guardan el contador y las otras variables. La razón es que todas las variables de Drupal se cargan en la variable global$conf
cuando los bootstraps de Drupal (ver _drupal_bootstrap_variables () y variable_initialize () ); si usa variables de Drupal para eso, Drupal cargaría en la información de la memoria acerca de todos los usuarios para los que guardó información, cuando para cada página solicitada solo hay una cuenta de usuario guardada en la variable global$user
.Si está contando el número de páginas visitadas por los usuarios en días consecutivos, entonces implementaría el siguiente código.
Notarás que en mi código no uso
$user->access
. La razón es que$user->access
podría actualizarse durante el arranque de Drupal, antes de quehook_init()
se invoque. El controlador de escritura de sesión utilizado desde Drupal contiene el siguiente código. (Ver _drupal_session_write () .)En cuanto a otro gancho que puede usar, con Drupal 7 puede usar hook_page_alter () ; simplemente no altera el contenido de
$page
, sino que aumenta su contador y cambia sus variables.En Drupal 6, puede usar hook_footer () , el gancho llamado desde template_preprocess_page () . No devuelve nada, pero aumenta su contador y cambia sus variables.
En Drupal 6 y Drupal 7, puede usar hook_exit () . Tenga en cuenta que el gancho también se invoca cuando el bootstrap no está completo; el código no puede tener acceso a las funciones definidas desde los módulos u otras funciones de Drupal, y primero debe verificar que esas funciones estén disponibles. Algunas funciones siempre están disponibles
hook_exit()
, como las definidas en bootstrap.inc y cache.inc . La diferencia es quehook_exit()
se invoca también para páginas en caché, mientrashook_init()
que no se invoca para páginas en caché.Finalmente, como ejemplo de código utilizado desde un módulo de Drupal, vea stats_exit () . El módulo Estadísticas registra las estadísticas de acceso de un sitio y, como puede ver, usa
hook_exit()
nohook_init()
. Para poder llamar a las funciones necesarias, llama a drupal_bootstrap () pasando el parámetro correcto, como en el siguiente código.Actualizar
Tal vez haya cierta confusión sobre cuándo
hook_init()
se invoca.hook_init()
se invoca para cada solicitud de página, si la página no está en caché. No se invoca una vez por cada solicitud de página que provenga del mismo usuario. Si visita, por ejemplo, http://example.com/admin/appearance/update , y luego http://example.com/admin/reports/status ,hook_init()
se invocará dos veces: una para cada página."El gancho se invoca dos veces" significa que hay un módulo que ejecuta el siguiente código, una vez que Drupal ha completado su arranque.
Si ese es el caso, la siguiente implementación de
hook_init()
mostraría el mismo valor, dos veces.Si su código se muestra para
REQUEST_TIME
dos valores para los cuales la diferencia es de 2 minutos, como en su caso, el gancho no se invoca dos veces, sino que se invoca una vez para cada página solicitada, como debería suceder.REQUEST_TIME
se define en bootstrap.inc con la siguiente línea.Hasta que la página solicitada actualmente no se devuelva al navegador, el valor de
REQUEST_TIME
no cambia. Si ve un valor diferente, está viendo el valor asignado en una página de solicitud diferente.fuente
Recuerdo que esto sucedió mucho en Drupal 6 (no estoy seguro de si todavía sucede en Drupal 7), pero nunca supe por qué. Sin embargo, recuerdo haber visto en alguna parte que el núcleo de Drupal no llama a este gancho dos veces.
Siempre encontré que la forma más fácil de evitarlo era usar una variable estática para ver si el código ya se había ejecutado:
Eso asegurará que solo se ejecute una vez en una sola carga de página.
fuente
hook_init()
implementaciones, y algunos de ellos evitarían ser ejecutados dos veces seguidas. También es probable que el OP quierahook_init()
ejecutarse una vez al día, si el contador cuenta el número de días consecutivos que los usuarios han iniciado sesión en el sitio.hook_init
verifique si ya se ejecutó una vez por el día y rescata si lo ha hecho. Entonces, de todos modosEs posible que se llame a hook_init () varias veces si ocurre algún AJAX en la página (o si está cargando imágenes desde un directorio privado, aunque no estoy tan seguro de eso). Hay algunos módulos que usan AJAX para ayudar a evitar el almacenamiento en caché de páginas para ciertos elementos, por ejemplo: la forma más fácil de verificar es abrir el monitor de red en el depurador de su elección (firefox o inspector web) y ver si hay alguna solicitud están hechos para desencadenar el proceso de arranque.
Sin embargo , solo obtendrá el dpm () en la carga de la página siguiente si se trata de una llamada AJAX. Supongamos que actualiza la página 5 minutos más tarde, recibirá la llamada AJAX del mensaje de inicio de hace 5 minutos, así como la nueva.
Una alternativa a hook_init () es hook_boot () que se llama antes de que se realice el almacenamiento en caché. Tampoco se han cargado módulos, por lo que realmente no tiene mucha potencia aquí, aparte de configurar variables globales y ejecutar algunas funciones de Drupal. Es útil para omitir el almacenamiento en caché de nivel regular (pero no omitirá el almacenamiento en caché agresivo).
fuente
En mi caso, este comportamiento fue causado por el módulo del Menú de Administración (admin_menu).
No se llamaba a hook_init en cada solicitud, pero el menú de administración provocaría que / js / admin_menu / cache / 94614e34b017b19a78878d7b96ccab55 fuera cargado por el navegador del usuario poco después de la solicitud principal, desencadenando otro arranque de drupal.
Habrá otros módulos que hacen cosas similares, pero admin_menu es probablemente uno de los más comúnmente implementados.
fuente