web-dev-qa-db-ja.com

hook_preprocess_page: "node_load()+ node_page_view()"対 "%node + node_page_view()"

基本ノード(nid "123")が存在し、モジュールは_hook_menu_を使用して2つのパスを登録しました:

  • _first/%node_
  • second

両方のページコールバックはnode_page_view($node)を使用してノードの全ページビューを表示しますが、2番目のコールバックはnode_load(123)を使用して_$node_への参照を取得します。

したがって、_http://localhost/first/123_と_http://localhost/second_は、ユーザーに関する限り同じように見えます。


ただし、_hook_preprocess_page_は最初のパスでのみnode変数を受け取るため、Drupalは_node_load_を検出すると_%node_以外の処理を実行しますワイルドカード、_hook_preprocess_page_がどちらの場合でも_$node_への参照を受け取るようにするための任意の考え? (2番目のパスですべてを内部で処理すると、2番目のパスから最初のパスにリダイレクトするよりもはるかにわかりやすいURLが生成されるため)。

例:

_<?php

/**
 * Implementation of hook_preprocess_page().
 */
function mymodule_preprocess_page(&$vars){
    if (@isset($vars['node'])) echo '<h1>[mymodule.module] Node is defined</h1>';
    else echo '<h1>[mymodule.module] Node is NOT defined</h1>';
}


/**
 * Implementation of hook_menu().
 */
function mymodule_menu(){
    return array(
        'first/%node' => array(
            'title' => 'First callback',
            'page callback' => 'mymodule_page_first',
            'page arguments' => array(1),
            'access callback' => TRUE, 
        ),
        'second' => array(
            'title' => 'Second callback',
            'page callback' => 'mymodule_page_second',
            'access callback' => TRUE, 
        ),
    );
}

/**
 * Page callback for url "http://localhost/first/123".
 */
function mymodule_page_first($node){
    echo '<h1>[mymodule.module] Function mymodule_page_first</h1><pre>';
    var_dump($node);
    echo '</pre>';

    return node_page_view($node);
}


/**
 * Page callback for url "http://localhost/second".
 */
function mymodule_page_second(){
    $node = node_load(123); //the ID of an existing node

    echo '<h1>[mymodule.module] Function mymodule_page_second</h1><pre>';
    var_dump($node);
    echo '</pre>';

    return node_page_view($node);
}
_

(ファイルのソース_mymodule.module_)


これまでの私の最高の/唯一の希望は、_node_page_view_のソースを調査し、_node_page_view_が呼び出された瞬間と_module_invoke_all_が呼び出された瞬間の間に何が起こるかを見つけるまでトリガーするすべての関数ですフックが呼び出されるトリガー。

2
wildpeaks

「first /%node」パスに対してmymodule_preprocess_page()が呼び出されると、パスがモジュールのノードに関連付けられているため、ノードオブジェクトが取得されます。
パスにノードIDとしてマークされているノードIDへの参照が含まれていないため、Drupalはノードオブジェクトを「/ admin/content/node」などのパス(Drupal 6パス)に関連付けることができません。 Drupal Webサイトに数百のノードが含まれる可能性があることを考慮して、どのノードオブジェクトがこのようなパスに対して返すかDrupal

あなたの質問は、「Drupalある場合にノードオブジェクトを関連付けることはできますが、別の場合には関連付けないことはできますか?」です。

答えは template_preprocess_page() コードにあります。このコードは、テンプレートpage.tpl.phpがレンダリングされる前に実行されます。
その関数には、次のコードがあります。

_if ($node = menu_get_object()) {
  $variables['node'] = $node;
}
_

menu_get_object() のデフォルトパラメータは_$type = 'node', $position = 1, $path = NULL_です。これは、template_preprocess_page()が、位置#1のプレースホルダに関連付けられているノードオブジェクトを要求していることを意味します。たとえば、arg(1)から返される値。

menu_get_object()のソースを見ると、実行されているコードが次のようになっていることがわかります。

_function menu_get_object($type = 'node', $position = 1, $path = NULL) {
  $router_item = menu_get_item($path);
  if (isset($router_item['load_functions'][$position]) && !empty($router_item['map'][$position]) && $router_item['load_functions'][$position] == $type . '_load') {
    return $router_item['map'][$position];
  }
}
_

デフォルトの引数を使用して、関数はルートアイテム#1に関連付けられた読み込み関数がnode_load()であることを確認します。ロード関数がそれである場合、ロード関数によって返された値を呼び出し関数(この場合はtemplate_preprocess_node())に返します。

ノードオブジェクトを自動的に取得するには、メニューコールバックで「second /%node」のようなパスを使用する必要があります(デフォルトのmenu_get_object()引数と互換性があります)。唯一の問題は、そのようなパスの場合、ノードIDを渡す必要があることです。 URLが http://example.com/second の場合、Drupalは、プレースホルダーの必須パラメーターが渡される必要があるため、404エラーページを表示します。
この問題を解決するには、モジュールが2つのメニューコールバックを定義する必要があります。1つは「秒」に関連付けられ、もう1つは「秒/%node」に関連付けられています。最初のメニューコールバックはノードオブジェクトを取得しませんが、2番目のメニューコールバックはノードオブジェクトを取得します(そしてmymodule_preprocess_page()もそれを取得します)。

別の方法として、mymodule_preprocess_page()のコードを次のようなものに変更する必要があります。

_/**
 * Implementation of hook_preprocess_page().
 */
function mymodule_preprocess_page(&$vars){
  // Check if the page being served is one of the pages handled by the module.
  if (arg(0) == 'first' || arg(0) == 'second') {
    if (isset($vars['node'])) {
      // The page is a node page.
    }
    else {
      $vars['node'] = mymodule_load_the_default_node();
    }
    // …
  }
}
_
3
kiamlaluno

Drupalは、URLに '%node'ワイルドカードを表示すると、引数がノードIDを参照していることを認識しているため、$node変数を自動的に設定し、hook_preprocess_page。「2番目の」メニューコールバックで、$vars['node']変数を設定する必要があります。これにより、hook_preprocess_pageを使用できます。

リファレンス: http://drupal.org/node/22417

1
Chaulky