Как запускать код при каждом запросе страницы - после загрузки модулей?


Я хочу написать модуль, который перенаправляет посетителей на другую страницу на основе модуля geoip.

Существует функция hook_boot(), которая выполняется при всех запросах страниц, но до загрузки модулей. Существует также hook_init(), который не запускается на кэшированных страницах. Мне нужно что-то, что запускается после загрузки всех модулей, но до того, как будут обработаны кэшированные страницы. Я пропустил еще один крючок в документации?

Примечание: Отключение кэша не является опция по соображениям производительности.

 4
Author: albertski, 2012-06-30

5 answers

Я думаю, что лучше всего обобщить варианты в новом ответе:

Во-первых: Нет крючка, который выполняется между hook_boot() и hook_init(). Это означает, что нет крючка, который имеет полностью инициализированную среду drupal и выполняется независимо от кэша страниц. -- спасибо @kiamlaluno за то, что прояснил это.

Есть еще два способа получить аналогичный эффект:

  1. Можно выборочно загружать включаемые файлы или модули в hook_boot() с помощью module_load_include() или drupal_load() соответственно. Это особенно полезно, если вам нужна только некоторая довольно автономная функциональность, которая не распространяется на большое количество файлов.
  2. Модуль dynamic_cache можно использовать для динамической деактивации кэша при определенных загрузках страниц, установив $GLOBALS['conf']['cache'] = FALSE в hook_boot(), а затем выполнив тяжелую работу в hook_init(). - благодаря @David Meister

Эти два метода также могут быть объединены, чтобы сузить число запросы, в которых необходимо отключить кэширование: Используйте минимальную начальную загрузку в hook_boot(), чтобы точно определить, когда необходимо отключить кэширование.

Однако модуль dynamic_cache кажется довольно хакерским. Так что пока я буду придерживаться метода 1.

 7
Author: zwirbeltier, 2015-07-08 16:59:43

Мне нужно что-то, что запускается после загрузки всех модулей, но до того, как будут обработаны кэшированные страницы.

Вы не можете, так как загрузка всех модулей является последней фазой начальной загрузки Drupal, в то время как кэшированные страницы обслуживаются на втором этапе начальной загрузки.

Смотрите код, используемый drupal_bootstrap().

  switch ($current_phase) {
    case DRUPAL_BOOTSTRAP_CONFIGURATION:
      _drupal_bootstrap_configuration();
      break;

    case DRUPAL_BOOTSTRAP_PAGE_CACHE:
      _drupal_bootstrap_page_cache();
      break;

    case DRUPAL_BOOTSTRAP_DATABASE:
      _drupal_bootstrap_database();
      break;

    case DRUPAL_BOOTSTRAP_VARIABLES:
      _drupal_bootstrap_variables();
      break;

    case DRUPAL_BOOTSTRAP_SESSION:
      require_once DRUPAL_ROOT . '/' . variable_get('session_inc', 'includes/session.inc');
      drupal_session_initialize();
      break;

    case DRUPAL_BOOTSTRAP_PAGE_HEADER:
      _drupal_bootstrap_page_header();
      break;

    case DRUPAL_BOOTSTRAP_LANGUAGE:
      drupal_language_initialize();
      break;

    case DRUPAL_BOOTSTRAP_FULL:
      require_once DRUPAL_ROOT . '/includes/common.inc';
      _drupal_bootstrap_full();
      break;
  }

Если вы посмотрите на _drupal_bootstrap_page_cache(), вы заметите, что hook_boot() в конечном итоге вызывается до того, как страница будет отправлена из кэшированные данные, в то время как hook_exit() в конечном итоге вызывается после того, как страница будет обработана из кэшированных данных. Эти крючки вызываются, если значение переменной Drupal "page_cache_invoke_hooks" равно TRUE.

  if (variable_get('page_cache_invoke_hooks', TRUE)) {
    bootstrap_invoke_all('boot');
  }
  drupal_serve_page_from_cache($cache);
  // If the skipping of the bootstrap hooks is not enforced, call
  // hook_exit.
  if (variable_get('page_cache_invoke_hooks', TRUE)) {
    bootstrap_invoke_all('exit');
  }

Обратите внимание, что в Drupal 8, hook_boot() был удален и , так же как и hook_exit(). Это означает, что Drupal 8 никогда не будет вызывать эти крючки.

 7
Author: kiamlaluno, 2016-12-29 18:29:10

Я знаю, что вы сказали, что отключение кэша не является опцией, но модуль динамического кэша позволяет отключать кэш условно в hook_boot, что на самом деле может быть опцией, так как кэш будет отключен только для пользователей, которых вы собираетесь перенаправить - http://drupal.org/project/dynamic_cache

Если вы можете извлечь необходимую логику из GeoIP в hook_boot(), то вы можете отключить кэш для загрузки этой страницы и просто выполнить drupal_goto() в hook_init().

 1
Author: David Meister, 2012-06-30 16:50:16

Или вы можете просто загрузить модули в hook_boot(), тогда drupal не придется загружать их позже, и вы сможете делать с модулями все, что захотите. Я понимаю, что это немного нерегулярно, но программирование на Drupal, похоже, требует нескольких нерегулярных способов выполнения задач.

 1
Author: Halcyon, 2012-09-27 12:28:19

Вы можете попробовать hook_exit, который запускается даже на кэшированных страницах. Я не уверен, работает ли drupal_goto внутри него, но если это не так, вы могли бы сделать то, что делает модуль boost, и использовать header('Location: mynewurl').

 0
Author: Alexandru Badiu, 2012-06-30 11:31:02