hook_init()
dipanggil oleh Drupal hanya sekali untuk setiap halaman yang diminta; itu adalah langkah terakhir yang dilakukan di _drupal_bootstrap_full () .
// Drupal 6
//
// Let all modules take action before menu system handles the request
// We do not want this while running update.php.
if (!defined('MAINTENANCE_MODE') || MAINTENANCE_MODE != 'update') {
module_invoke_all('init');
}
// Drupal 7
//
// Let all modules take action before the menu system handles the request.
// We do not want this while running update.php.
if (!defined('MAINTENANCE_MODE') || MAINTENANCE_MODE != 'update') {
// Prior to invoking hook_init(), initialize the theme (potentially a custom
// one for this page), so that:
// - Modules with hook_init() implementations that call theme() or
// theme_get_registry() don't initialize the incorrect theme.
// - The theme can have hook_*_alter() implementations affect page building
// (e.g., hook_form_alter(), hook_node_view_alter(), hook_page_alter()),
// ahead of when rendering starts.
menu_set_custom_theme();
drupal_theme_initialize();
module_invoke_all('init');
}
Jika hook_init()
dieksekusi lebih dari sekali, Anda harus mengetahui mengapa itu terjadi. Sejauh yang saya bisa lihat, tidak ada hook_init()
implementasi dalam Drupal yang memeriksa dieksekusi dua kali (lihat misalnya system_init () , atau update_init () ). Jika itu adalah sesuatu yang biasanya dapat terjadi dengan Drupal, maka update_init()
pertama-tama akan memeriksa apakah sudah dijalankan.
Jika penghitung adalah jumlah hari berturut-turut pengguna login, saya lebih suka mengimplementasikan hook_init()
dengan kode yang mirip dengan yang berikut.
// Drupal 7
function mymodule_init() {
global $user;
$result = mymodule_increase_counter($user->uid);
if ($result[0]) {
// Increase the counter; set the other variables.
}
elseif ($result[1] > 86400) {
// The user didn't log in yesterday.
}
}
function mymodule_date($timestamp) {
$date_time = date_create('@' . $timestamp);
return date_format($date_time, 'Ymd');
}
function mymodule_increase_counter($uid) {
$last_timestamp = variable_get("mymodule_last_timestamp_$uid", 0);
if ($last_timestamp == REQUEST_TIME) {
return array(FALSE, 0);
}
$result = array(
mymodule_date($last_timestamp + 86400) == mymodule_date(REQUEST_TIME),
REQUEST_TIME - $last_timestamp,
);
variable_set("mymodule_last_timestamp_$uid", REQUEST_TIME);
return $result;
}
// Drupal 6
function mymodule_init() {
global $user;
$result = mymodule_increase_counter($user->uid);
if ($result[0]) {
// Increase the counter; set the other variables.
}
elseif ($result[1] > 86400) {
// The user didn't log in yesterday.
}
}
function mymodule_increase_counter($uid) {
$last_timestamp = variable_get("mymodule_last_timestamp_$uid", 0);
$result = array(FALSE, time() - $last_timestamp);
if (time() - $last_timestamp < 20) {
return $result;
}
$result[0] = (mymodule_date($last_timestamp + 86400) == mymodule_date(REQUEST_TIME));
variable_set("mymodule_last_timestamp_$uid", time());
return $result;
}
Jika hook_init()
dipanggil dua kali berturut-turut selama permintaan halaman yang sama, REQUEST_TIME
berisi nilai yang sama, dan fungsinya akan kembali FALSE
.
Kode dalam mymodule_increase_counter()
tidak dioptimalkan; itu hanya untuk menunjukkan contoh. Dalam modul nyata, saya lebih suka menggunakan tabel database tempat penghitung, dan variabel lainnya disimpan. Alasannya adalah bahwa variabel Drupal semua dimuat dalam variabel global $conf
ketika Drupal bootstraps (lihat _drupal_bootstrap_variables () , dan variable_initialize () ); jika Anda menggunakan variabel Drupal untuk itu, Drupal akan memuat informasi memori tentang semua pengguna yang Anda simpan informasinya, ketika untuk setiap halaman yang diminta hanya ada satu akun pengguna yang disimpan dalam variabel global $user
.
Jika Anda menghitung jumlah halaman yang dikunjungi dari pengguna dalam beberapa hari berturut-turut, maka saya akan menerapkan kode berikut.
// Drupal 7
function mymodule_init() {
global $user;
$result = mymodule_increase_counter($user->uid);
if ($result[0]) {
// Increase the counter; set the other variables.
}
elseif ($result[1] > 86400) {
// The user didn't log in yesterday.
}
}
function mymodule_date($timestamp) {
$date_time = date_create('@' . $timestamp);
return date_format($date_time, 'Ymd');
}
function mymodule_increase_counter($uid) {
$last_timestamp = variable_get("mymodule_last_timestamp_$uid", 0);
if ($last_timestamp == REQUEST_TIME) {
return array(FALSE, 0);
}
$result = array(
mymodule_date($last_timestamp + 86400) == mymodule_date(REQUEST_TIME),
REQUEST_TIME - $last_timestamp,
);
variable_set("mymodule_last_timestamp_$uid", REQUEST_TIME);
return $result;
}
// Drupal 6
function mymodule_init() {
global $user;
$result = mymodule_increase_counter($user->uid);
if ($result[0]) {
// Increase the counter; set the other variables.
}
elseif ($result[1] > 86400) {
// The user didn't log in yesterday.
}
}
function mymodule_increase_counter($uid) {
$last_timestamp = variable_get("mymodule_last_timestamp_$uid", 0);
$result = array(FALSE, time() - $last_timestamp);
if (time() - $last_timestamp < 20) {
return $result;
}
$result[0] = (mymodule_date($last_timestamp + 86400) == mymodule_date(REQUEST_TIME));
variable_set("mymodule_last_timestamp_$uid", time());
return $result;
}
Anda akan melihat bahwa dalam kode saya saya tidak menggunakan $user->access
. Alasannya adalah bahwa $user->access
dapat diperbarui selama bootstrap Drupal, sebelum hook_init()
dipanggil. Pegangan menulis sesi yang digunakan dari Drupal berisi kode berikut. (Lihat _drupal_session_write () .)
// Likewise, do not update access time more than once per 180 seconds.
if ($user->uid && REQUEST_TIME - $user->access > variable_get('session_write_interval', 180)) {
db_update('users')
->fields(array(
'access' => REQUEST_TIME,
))
->condition('uid', $user->uid)
->execute();
}
Adapun hook lain yang dapat Anda gunakan, dengan Drupal 7 Anda dapat menggunakan hook_page_alter () ; Anda hanya tidak mengubah konten $page
, tetapi menambah penghitung Anda, dan mengubah variabel Anda.
Pada Drupal 6, Anda bisa menggunakan hook_footer () , hook yang dipanggil dari template_preprocess_page () . Anda tidak mengembalikan apa pun, tetapi tingkatkan penghitung Anda, dan ubah variabel Anda.
Pada Drupal 6, dan Drupal 7, Anda bisa menggunakan hook_exit () . Ingatlah bahwa kait juga dipanggil saat bootstrap tidak lengkap; kode tidak dapat memiliki akses ke fungsi yang ditentukan dari modul, atau fungsi Drupal lainnya, dan Anda harus terlebih dahulu memeriksa fungsi-fungsi yang tersedia. Beberapa fungsi selalu tersedia hook_exit()
, seperti yang didefinisikan di bootstrap.inc , dan cache.inc . Perbedaannya adalah yang hook_exit()
dipanggil juga untuk halaman yang di-cache, sementara hook_init()
itu tidak dipanggil untuk halaman yang di-cache.
Akhirnya, sebagai contoh kode yang digunakan dari modul Drupal, lihat stats_exit () . Modul Statistik mencatat statistik akses untuk suatu situs, dan seperti yang Anda lihat, ia menggunakan hook_exit()
, bukan hook_init()
. Agar dapat memanggil fungsi yang diperlukan, ia memanggil drupal_bootstrap () yang melewati parameter yang benar, seperti dalam kode berikut.
// When serving cached pages with the 'page_cache_without_database'
// configuration, system variables need to be loaded. This is a major
// performance decrease for non-database page caches, but with Statistics
// module, it is likely to also have 'statistics_enable_access_log' enabled,
// in which case we need to bootstrap to the session phase anyway.
drupal_bootstrap(DRUPAL_BOOTSTRAP_VARIABLES);
if (variable_get('statistics_enable_access_log', 0)) {
drupal_bootstrap(DRUPAL_BOOTSTRAP_SESSION);
// For anonymous users unicode.inc will not have been loaded.
include_once DRUPAL_ROOT . '/includes/unicode.inc';
// Log this page access.
db_insert('accesslog')
->fields(array(
'title' => truncate_utf8(strip_tags(drupal_get_title()), 255),
'path' => truncate_utf8($_GET['q'], 255),
'url' => isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '',
'hostname' => ip_address(),
'uid' => $user->uid,
'sid' => session_id(),
'timer' => (int) timer_read('page'),
'timestamp' => REQUEST_TIME,
))
->execute();
}
Memperbarui
Mungkin ada beberapa kebingungan tentang kapan hook_init()
dipanggil.
hook_init()
dipanggil untuk setiap permintaan halaman, jika halaman tersebut tidak di-cache. Itu tidak dipanggil sekali untuk setiap permintaan halaman yang berasal dari pengguna yang sama. Jika Anda mengunjungi, misalnya, http://example.com/admin/appearance/update , lalu http://example.com/admin/reports/status , hook_init()
akan dipanggil dua kali: satu untuk setiap halaman.
"Hook dipanggil dua kali" berarti ada modul yang mengeksekusi kode berikut, setelah Drupal menyelesaikan bootstrapnya.
module_invoke_all('init');
Jika itu masalahnya, maka implementasi berikut hook_init()
akan menunjukkan nilai yang sama, dua kali.
function mymodule_init() {
watchdog('mymodule', 'Request time: !timestamp', array('!timestamp' => REQUEST_TIME), WATCHDOG_DEBUG);
}
Jika kode Anda ditampilkan untuk REQUEST_TIME
dua nilai yang perbedaannya adalah 2 menit, seperti dalam kasus Anda, maka kail tidak dipanggil dua kali, tetapi dipanggil sekali untuk setiap halaman yang diminta, seperti yang seharusnya terjadi.
REQUEST_TIME
didefinisikan dalam bootstrap.inc dengan baris berikut.
define('REQUEST_TIME', (int) $_SERVER['REQUEST_TIME']);
Sampai halaman yang diminta saat ini tidak dikembalikan ke browser, nilai REQUEST_TIME
tidak berubah. Jika Anda melihat nilai yang berbeda, maka Anda menonton nilai yang ditetapkan di halaman permintaan yang berbeda.