16.1 drupal_deliver_html_page

作者:老葛,北京亚艾元软件有限责任公司,http://www.yaiyuan.com

我们在node_menu里面,并没有定义'delivery callback',所以这里的$default_delivery_callback将会使用Drupal的默认值。$page_callback_result就是刚才返回的包含节点对象的呈现数组。现在,让我们来看一下drupal_deliver_page,是怎么将这个数组转换成整个页面,并返回给浏览器的。

function drupal_deliver_page($page_callback_result, $default_delivery_callback = NULL) {

  if (!isset($default_delivery_callback) && ($router_item = menu_get_item())) {

    $default_delivery_callback = $router_item['delivery_callback'];

  }

  $delivery_callback = !empty($default_delivery_callback) ? $default_delivery_callback : 'drupal_deliver_html_page';

  // Give modules a chance to alter the delivery callback used, based on

  // request-time context (e.g., HTTP request headers).

  drupal_alter('page_delivery_callback', $delivery_callback);

  if (function_exists($delivery_callback)) {

    $delivery_callback($page_callback_result);

  }

  else {

    // If a delivery callback is specified, but doesn't exist as a function,

    // something is wrong, but don't print anything, since it's not known

    // what format the response needs to be in.

    watchdog('delivery callback not found', 'callback %callback not found: %q.', array('%callback' => $delivery_callback, '%q' => $_GET['q']), WATCHDOG_ERROR);

  }

}

实际上我们并没有在任何地方设置$delivery_callback,所以将会使用默认的'drupal_deliver_html_page'。这里的

drupal_alter('page_delivery_callback', $delivery_callback);

用来允许第三方模块修改这里的$delivery_callback,但是实际上,我基本上没有见过哪个第三方模块实现了这个钩子函数。Drupal提供了太多的钩子函数,有些可能从来没有被使用过。

function_exists负责检查函数是否存在,drupal_deliver_html_page这个函数是存在的,所以这里实际调用的是:

drupal_deliver_html_page($page_callback_result);

为什么不直接调用drupal_deliver_html_page呢?我们要的就是html页面啊。Drupal核心的开发者是这样考虑的,这个地方留个接口,这样第三方模块就可以实现,比如说:

drupal_deliver_json_page

drupal_deliver_xml_page

也就是说,Drupal不仅仅支持HTML,返回有可能还是jsonxml等其它格式。我们这里只用到了html,所以让我们来看一下默认的具体实现。

/**

 * Packages and sends the result of a page callback to the browser as HTML.

 *

 * @param $page_callback_result

 *   The result of a page callback. Can be one of:

 *   - NULL: to indicate no content.

 *   - An integer menu status constant: to indicate an error condition.

 *   - A string of HTML content.

 *   - A renderable array of content.

 *

 * @see drupal_deliver_page()

 */

function drupal_deliver_html_page($page_callback_result) {

  // Emit the correct charset HTTP header, but not if the page callback

  // result is NULL, since that likely indicates that it printed something

  // in which case, no further headers may be sent, and not if code running

  // for this page request has already set the content type header.

  if (isset($page_callback_result) && is_null(drupal_get_http_header('Content-Type'))) {

    drupal_add_http_header('Content-Type', 'text/html; charset=utf-8');

  }

 

  // Send appropriate HTTP-Header for browsers and search engines.

  global $language;

  drupal_add_http_header('Content-Language', $language->language);

 

  // Menu status constants are integers; page content is a string or array.

  if (is_int($page_callback_result)) {

    // @todo: Break these up into separate functions?

    switch ($page_callback_result) {

      case MENU_NOT_FOUND:

        // Print a 404 page.

        drupal_add_http_header('Status', '404 Not Found');

 

        watchdog('page not found', check_plain($_GET['q']), NULL, WATCHDOG_WARNING);

 

        // Check for and return a fast 404 page if configured.

        drupal_fast_404();

 

        // Keep old path for reference, and to allow forms to redirect to it.

        if (!isset($_GET['destination'])) {

          $_GET['destination'] = $_GET['q'];

        }

 

        $path = drupal_get_normal_path(variable_get('site_404', ''));

        if ($path && $path != $_GET['q']) {

          // Custom 404 handler. Set the active item in case there are tabs to

          // display, or other dependencies on the path.

          menu_set_active_item($path);

          $return = menu_execute_active_handler($path, FALSE);

        }

 

        if (empty($return) || $return == MENU_NOT_FOUND || $return == MENU_ACCESS_DENIED) {

          // Standard 404 handler.

          drupal_set_title(t('Page not found'));

          $return = t('The requested page "@path" could not be found.', array('@path' => request_uri()));

        }

 

        drupal_set_page_content($return);

        $page = element_info('page');

        print drupal_render_page($page);

        break;

 

      case MENU_ACCESS_DENIED:

        // Print a 403 page.

        drupal_add_http_header('Status', '403 Forbidden');

        watchdog('access denied', check_plain($_GET['q']), NULL, WATCHDOG_WARNING);

 

        // Keep old path for reference, and to allow forms to redirect to it.

        if (!isset($_GET['destination'])) {

          $_GET['destination'] = $_GET['q'];

        }

 

        $path = drupal_get_normal_path(variable_get('site_403', ''));

        if ($path && $path != $_GET['q']) {

          // Custom 403 handler. Set the active item in case there are tabs to

          // display or other dependencies on the path.

          menu_set_active_item($path);

          $return = menu_execute_active_handler($path, FALSE);

        }

 

        if (empty($return) || $return == MENU_NOT_FOUND || $return == MENU_ACCESS_DENIED) {

          // Standard 403 handler.

          drupal_set_title(t('Access denied'));

          $return = t('You are not authorized to access this page.');

        }

 

        print drupal_render_page($return);

        break;

 

      case MENU_SITE_OFFLINE:

        // Print a 503 page.

        drupal_maintenance_theme();

        drupal_add_http_header('Status', '503 Service unavailable');

        drupal_set_title(t('Site under maintenance'));

        print theme('maintenance_page', array('content' => filter_xss_admin(variable_get('maintenance_mode_message',

          t('@site is currently under maintenance. We should be back shortly. Thank you for your patience.', array('@site' => variable_get('site_name', 'Drupal')))))));

        break;

    }

  }

  elseif (isset($page_callback_result)) {

    // Print anything besides a menu constant, assuming it's not NULL or

    // undefined.

    print drupal_render_page($page_callback_result);

  }

 

  // Perform end-of-request tasks.

  drupal_page_footer();

}

最前面的两端代码,是用来添加http header的(drupal_add_http_header),我们不用去管它。

再往下是对$page_callback_result做了整数判断。

if (is_int($page_callback_result)) {

什么时候会是整数呢,当MENU_NOT_FOUNDMENU_ACCESS_DENIEDMENU_SITE_OFFLINE的时候,会是整数。我们这里面返回的是数组,不是整数,我们这里也就跳过了这三种特殊情况,继续往下看代码。

  elseif (isset($page_callback_result)) {

    // Print anything besides a menu constant, assuming it's not NULL or

    // undefined.

    print drupal_render_page($page_callback_result);

  }

 

  // Perform end-of-request tasks.

  drupal_page_footer();


Drupal版本: