Drupal で、必要最低限の機能のモジュールを作る。

Drupal でのモジュール開発を理解するということは node のコンセプト(コンテンツタイプ)と hook システム(hook と呼ばれるコールバック関数)とフォーム($form)を理解するということでもある。 「Drupal で、モジュールを開発するために必要な最低限の hook」 では、Drupal の hook について説明したが、ここでは具体的にモジュールを実装してみることにする。そのモジュールの名前は「hook」。 Drupal 5 からは、yourmodule.info、yourmodule.install、yourmodule.module、yourmodule.css の 4つのファイルが必要となった。ゆえに hook という名前のモジュールを作る場合、hook.info、hook.install、hook.module、hook.css の 4つのファイルを作る。この hook モジュールは、タイトル、本文、そして hook モジュール独自の値である 'A'~'E' の hid (=hook ID)を取る(表示上の 'A'~'E' はデータベース中では 1~5 に対応して保存される)。hid のデフォルト値は https://yourdomain.com/admin/settings/hook で設定することができる。以下、参考にしてほしい。 hook.info
; セミコロンがコメント。
name = Hook
description = "A module template."
package =
version = VERSION

;
version = "5.x-1.x-dev"
project = "Example"
hook.install
<?php
/**
* hook_install() の実装
* これを実装すると Drupal のモジュールシステム admin/build/modules に
* 組み入れることができる。基本的にこのモジュールで扱いたいデータを
* 格納するテーブルを作る。
*/
function hook_install() {

  switch (
$GLOBALS['db_type']) {
    case
'mysql':
    case
'mysqli':
     
db_query("CREATE TABLE {hook}
                (
                  `nid`       INT( 10 ) UNSIGNED NOT NULL ,
                  `hid`       INT(  3 ) UNSIGNED NOT NULL DEFAULT '1',
                   PRIMARY KEY ( `nid` )
                )  ENGINE = MYISAM"
             
);
      break;

    case
'pgsql':
      break;
  }
}

/**
* hook_uninstall() を実装する。
* このモジュールで使っていたテーブルを drop する。
* variable_del で、このモジュールで使っていた設定値を削除する。
*/
function hook_uninstall() {

 
db_query('DROP TABLE {hook}');
 
variable_del('hook_option'); // 忘れないように!!!

}
?>
hook.module
<?php

// コンスタントな文字列の定義
define('MODULE_NAME''Hook');
define('CONTENT_TYPE', 'hook');
define('PRIVILEGE_ADMIN'  'administer' MODULE_NAME . ' server settings');
define('PRIVILEGE_CREATE' 'create'     MODULE_NAME . ' forms and docs');
define('PRIVILEGE_VIEW'   'view'       MODULE_NAME . ' forms and docs');
define('PRIVILEGE_EDIT'   'edit own'   MODULE_NAME . ' forms and docs');

/**
* hook_help() を実装する。
* case にある URL での説明書き。
*/
function hook_help($section) {

  switch (
$section) {

  case
'admin/help#' . CONTENT_TYPE:
   
$o .= '<p>' . t('Submit, view and manage ' . CONTENT_TYPE . ' lists.') . '</p>';
    return
$o;

  case
'admin/modules#description':
    return
t('Allows users to submit, view and manage job records');

  case
'node/add#' . CONTENT_TYPE:
    return
t('Add a ' . MODULE_NAME . ' record.');

  }
}

/**
* hook_perm() を実装する。
* ここでの定義は、admin/user/access でのアクセスコントロールで使われる。
*/
function hook_perm() {

  return array(
         
PRIVILEGE_ADMIN,
         
PRIVILEGE_CREATE,
         
PRIVILEGE_VIEW,
         
PRIVILEGE_EDIT
       
);
}

/**
* hook_access() を実装する。
* create、update、delete、view のアクセス制御を行う。
* @param op create、view、update、delete の 4つの値を取る。
*/
function hook_access($op, $node) {

  global
$user;

  if (
$op == 'create') {
    return
user_access(PRIVILEGE_CREATE);
  }

  if (
$op == 'view') {
    return
user_access(PRIVILEGE_VIEW);
  }

  if (
$op == 'update' || $op == 'delete') {
    if (
user_access(PRIVILEGE_EDIT)
    && (
$user->uid == $node->uid)) {
      return
TRUE;
    }
  }
}

/**
* hook_menu() を実装する。
* Drupal のメニュー(パス)とそれをクリックされたときに呼び出される関数、そして
* アクセス制御の組み合わせを記述する。
*/
function hook_menu($may_cache) {

 
$items = array();

  if (
$may_cache) {

   
$items[] = array(
     
'path'                => 'node/add/' . CONTENT_TYPE,
     
'title'               => t(MODULE_NAME),
     
'access'              => user_access(PRIVILEGE_CREATE)
    );

   
$items[] = array(
     
'type'                => MENU_NORMAL_ITEM,
     
'path'                => 'admin/settings/' . CONTENT_TYPE,
     
'title'               => t(MODULE_NAME . ' default settings'),
     
'access'              => user_access(PRIVILEGE_ADMIN),
     
'callback'            => 'drupal_get_form',
     
'callback arguments'  => CONTENT_TYPE . '_admin',
     
'description'         => 'Configure ' . MODULE_NAME . ' default settings'
   
);

  }

  return
$items;
}

/**
* hook_node_info() を実装する。
* コンテンツタイプを定義する。'hook' にはモジュール名が入る。
* が、必ずしもこのモジュール名(hook)でなくてもよいため、
* array 配列に hook、name、module、description の組み合わせを追加していけば
* 1つのモジュールで複数のフォームを 実現できる。
* 必ず hook、name、module、description の組み合わせをキープすること。
*/
function hook_node_info() {

  return  array(
             
'hook'        => array(
             
'name'        => t(MODULE_NAME),
             
'module'      => CONTENT_TYPE,
             
'description' => t('You can make a ' . CONTENT_TYPE . 'hook record and view them.')
            )
          );
}

/**
* hook_admin() を実装する。
* この hook を実装すると、admin/settings/hook でこのモジュール固有のデフォルト
* 値を複数定義できる。
*/
function hook_admin() {

 
// hostname
 
$form['hook_option'] = array(
   
'#type'            => 'select',
   
'#title'           => t('hid default value'),
   
'#default_value'   => variable_get(CONENT_TYPE . '_option', 1),
   
'#options'         => array('1'=>'A', '2'=>'B', '3'=>'C', '4'=>'D', '5'=>'E'),
   
'#size'            => 1,
   
'#weight'          => -10,
   
'#required'        => TRUE
 
);

  return
system_settings_form($form);
}

/**
* hook_form() を実装する。
* フォームを定義する。
* @param node 編集の場合、すでに node は保存済みのためインスタンスが入る。
* @return $form フォームオブジェクトを返すと、Drupal が自動的にフォームを作成する。
*/

function hook_form(&$node) {

 
// $form['hid']
 
$hid = $node->hid ? $node->hid : variable_get(CONTENT_TYPE . '_option', 1);

 
$form['title'] = array(
   
'#type'           => 'textfield',
   
'#title'          => t('Title'),
   
'#default_value'  => $node->title,
   
'#weight'         => -8,
   
'#required'       => TRUE,
  );

 
$form['hid'] = array(
   
'#type'           => 'select',
   
'#title'          => t(MODULE_NAME . ' hid value'),
   
'#options'        => array('1'=>'A', '2'=>'B', '3'=>'C', '4'=>'D', '5'=>'E'),
   
'#default_value'  => $hid,
   
'#weight'         => -6,
   
'#required'       => TRUE
 
);

 
// full description / body
 
$form['body_filter']['body'] = array(
   
'#type'           => 'textarea',
   
'#title'          => t('Body'),
   
'#rows'           => 4,
   
'#default_value'  => $node->body,
   
'#weight'         => -5,
   
'#required'       => TRUE
 
);

  
$form['body_filter']['format'] = filter_form($node->format);

  return
$form;
}

/**
* hook_view() を実装する。
* フォームで保存した値を表示する。
* @param &$node  表示するオブジェクト
* @param $teaser boolean: teaser かフルノードか?
* @param $page   boolean: 自身のページを表示するか?
*/
function hook_view(&$node, $teaser = FALSE, $page = FALSE) {

 
$node = node_prepare($node, $teaser);

 
$node->content['title'] = array(
   
'#value'  => theme(CONTENT_TYPE . '_title', $node->title),
   
'#weight' => -8
 
);

 
$node->content['hid'] = array(
   
'#value'  => theme(CONTENT_TYPE . '_hid',   $node->hid),
   
'#weight' => -6
 
);

 
$node->content['body'] = array(
   
'#value'  => theme(CONTENT_TYPE . '_body'$node->body),
   
'#weight' => -4
 
);

  return
$node;
}

/**
* hook_insert() を実装する。
* フォームで、コンテンツの新規作成から submit ボタンを押したときに呼び出される。
* node に対する基本情報は Drupal が自動的に保存するから、ここでは自分で
* 用意したフィールドに値を保存してあげればよい。
* ただし node の ID である nid が拠り所となっている(リレーションを張っている)
* ので、自身の用意したテーブルにもプライマリキーとしての nid が必要である。
*/
function hook_insert($node) {

 
db_query(
   
'INSERT INTO {' . CONTENT_TYPE . '} (`nid`, `hid`) VALUES ( %d,        %d        )',
                                               
$node->nid, $node->hid
 
);
}

/**
* hook_update() を実装する。
* フォームで、編集から submit ボタンを押したときに呼び出される。
*/
function hook_update($node) {

 
db_query('UPDATE {' . CONTENT_TYPE . '} set `hid`=%d WHERE nid=%d', $node->hid, $node->nid);
}

/**
* hook_delete() を実装する。
* フォームで、削除ボタンを押したときに呼び出される。
*/
function hook_delete(&$node) {

   
db_query('DELETE FROM {' . CONTENT_TYPE . '} WHERE `nid`=%d', $node->nid);
}

/**
* hook_load() を実装する。
* Drupal でコンテンツを扱うとき、node というコンテンツの最小単位を基本として、
* あなたのモジュールで扱いたい情報はあなたが用意した別テーブルにあなたが
* 自分で保存する(hook_insert、hook_update)。
* Drupal ではコンテンツ最初単位である node の情報は自動的に処理するものの、
* Drupal があなたのモジュールの扱う情報を表示したりする場合は、
* node との差分情報をどのテーブルのどのフィールドにデータが入っているかを
* あなた自身が Drupal に教えてあげる必要がある。その実装となる関数がコレ。
*/
function hook_load($node) {

 
$r db_fetch_object(
         
db_query('SELECT `hid` FROM {' . CONTENT_TYPE . '} WHERE nid=%d', $node->nid)
        );

  return
$r;
}

/**
* hook_validate() を実装する。
* hook_insert や hook_update が実行される前に呼び出される。
* フォームに入力されてこちらのモジュールに送られてきた値が正しいかどうか
* この関数を実装することによってチェックすることができる。
*/
function hook_validate($form_id, $form_values) {

// dump the form validate variables
//print '<code>' . print_r($form_values, true); exit();

}

/**
* theme_hook_title() を実装する。
* title を表示するときのスタイルシートへの関連付け。
*/
function theme_hook_title($content) {

 
$output .= '<div class="' . CONTENT_TYPE . '_view_title">';
 
$output .= t('Title:');
 
$output .= $content;
 
$output .= '</div>';

  return
$output;
}

/**
* theme_hook_body() を実装する。
* body を表示するときのスタイルシートへの関連付け。
*/
function theme_hook_body($content) {

 
$output .= '<div class="' . CONTENT_TYPE . '_view_body">';
 
$output .= t('Body:');
 
$output .= $content;
 
$output .= '</div>';

  return
$output;
}

/**
* theme_hook_hid() を実装する。
* hid を表示するときのスタイルシートへの関連付け。
*/
function theme_hook_hid($content) {

 
$options = array('1'=>'A', '2'=>'B', '3'=>'C', '4'=>'D', '5'=>'E');

 
$output .= '<div class="' . CONTENT_TYPE . '_view_value">';
 
$output .= t('hid value: %value', array('%value' => $options[$content]));
 
$output .= '</div>';

  return
$output;
}
?>
トラックバック URL: https://perltips.twinkle.cc/trackback/197
Posted on 2007-04-30 by yas |
おぉっ!素晴らしいです。 日本語サイトでこんなに詳しく解説している所が無いですからね。 大きく応援しています。
Posted by 初心者 (未認証ユーザ) on 2007/09/11(火) 17:50
Drupal で、モジュールを開発するために必要な最低限の hook
Trackback from Perl Tips: Drupal の hook (つまりコールバック/Callback)は、その世......
Posted by Perl Tips (未認証ユーザ) on 2007/04/18(水) 03:04
Drupal: Develop a Minimum Function Set of Module (English)
Trackback from Perl Tips: Understanding the development of Drupal......
Posted by Perl Tips (未認証ユーザ) on 2007/04/19(木) 09:23
Drupal: Minimum Hooks to Develop Your Own Module
Trackback from Perl Tips: Obviously there is a learning curve to ......
Posted by Perl Tips (未認証ユーザ) on 2007/04/21(土) 20:41