BegGuide
提供: GeeklogJpWiki
[6]開発者用ドキュメント > アプリケーション開発
目次 |
アプリケーション開発
原著者:Alan McKay
Geeklogは強力なブログのコンテンツ管理システム(CMS)で,ポピュラーな言語であるPHPで書かれ,ポピュラーなデータベースであるMySQLを使用しています。Geeklogの本体機能はとても充実しているので,多くのユーザは独自のアプリケーションを書く必要はありませんが,Geeklogは極めて柔軟性が高いので,追加機能が必要であるならアプリケーションを開発することができます。開発環境が用意されているので開発はとても簡単です。PHPでプログラムを書きますが,若干の制限があるものの,Geeklogの関数ライブラリを使用できます。
Hello, World
どのコンピュータ言語でも最初に書くプログラムは"Hello World"で,次に示すのはそのGeeklog版です。これをGeeklogの"public_html"ディレクトリにhello.phpの名前で保存すれば,http://yourdomain/hello.phpでアクセスできます。
<?php require_once( 'lib-common.php' ); $display = COM_siteHeader(); $display .= "Hello World"; $display .= COM_siteFooter(); echo $display; ?>
このプログラムで注目すべきいくつかの重要な点は,
- GeeklogのプログラムはPHPモードのまま - PHP言語の場合と違い,PHPとHTMLの間を行ったり来たりしません。つまり,全てのプログラムは"<?php" で始まって "?>"で終わり,その間にはPHPのコードしかないということです。
- HTMLを吐き出すecho文は1つだけにしてください。途中のプログラムは全部,出力するHTMLをまとめているに過ぎません。デバッグ用にecho文を付け加えてもよいですが,画面の最上部に表示されます。ただし,デバッグ用を別にすれば,echo文は最後に1つだけです。
- どのGeeklogのプログラムも"lib-common.php"は必ずインクルードしなければなりません。必要とするものは全てlib-common.phpに含まれており,これさえあれば他は不要です。
- Geeklogには,たとえば,COM_siteHeader()とCOM_siteFooter()のように,様々なことをやってくれる関数群があります。一般にGeeklogの関数名は大文字2つか3つとアンダーバー'_'で始まります。これで関数の種類がわかります。たとえば,COM_で始まる関数は"共通の(common)"の関数というわけで,大して意味がある訳ではありません。しかし,ユーザーが特定のグループに所属しているかどうかを調べる SEC_inGroup() 関数のように SEC_ で始まる関数を使えば,Geeklogの強力なセキュリティ機能にアクセスできるということです。そして,DB_で始まる関数を使えば,Geeklogのデータベースにアクセスできます。
セキュリティ
Geeklogの強力なセキュリティモデルの話が出たので(私がが自分のサイト用にGeeklogを選んだ重要な理由の1つです),"geeker"グループに属するユーザーは"Hello, World"のメッセージを見ることができるが,そうでない人(ログインしていないユーザーを含む)には"permission denied"のエラーメッセージが表示されるよう,さっきの"Hello, World"プログラムを改造する方法を紹介します。
<?php
require_once( 'lib-common.php' );
$display = COM_siteHeader();
if ( SEC_inGroup( 'geeker' ) )
$display .= "Hello World";
else
$display .= "Access Denied";
$display .= COM_siteFooter();
echo $display;
?>
利用可能な全てのセキュリティ関数とその使い方をチェックするには,それらが実装されている/path/to/geeklog/system/lib-security.phpを読んでください。
上述のコードの書き方はちょっと格好悪くあまり役に立たないので,更に改造して,ほとんどのプログラムがどのようにグループのパーミッションを扱っているかを見てみましょう。
<?php
require_once( 'lib-common.php' );
$display = COM_siteHeader();
if ( ! SEC_inGroup( 'geeker' ) )
{
$display .= "Access Denied";
$display .= COM_siteFooter();
echo $display;
exit;
}
$display .= "Hello World";
// do some other stuff here
$display .= COM_siteFooter();
echo $display;
?>
このバージョンの最大の違いは,プログラムの一番最初でグループのパーミッションを検査しているということです。ユーザーがパーミッションを持っていなければ,サイトのフッタを表示して終了します。だから,"geeker"グループに入っていないユーザーはそこでおしまいになり,プログラムの残りの部分の動作を目にすることは決してありません。とても単純だが,極めて強力です。まさにこのようにしてGeeklogではアクセスコントロールをしているわけです。
どこに置くか
小さなプログラムしか書かないなら,上述のようにファイルを1つ"public_html"ディレクトリにアップしておけば立派に動作します。でも,自分独自のインクルードファイルを作り始めるような段階になったら,ディレクトリを作りたくなるでしょう。その場合,"public_html"ディレクトリ内に例えば"hello"というディレクトリを作ればいいでしょう。そしてそこに上述のプログラムを含む"index.php"を置きます。オリジナルのプログラムをほんの少し書き換えるだけです。答えを見る前に違いを見つけられるでしょうか?
<?php require_once( '../lib-common.php' ); $display = COM_siteHeader(); $display .= "Hello World"; $display .= COM_siteFooter(); echo $display; ?>
そう,その通り,"require_once" 文の中で"lib-common.php"に"../"を付け加えるだけです。(※"require_once"はPHPではインクルード文の一種) 理由は単純です。lib-common.php はpublic_htmlにあり,最初のプログラムは同じディレクトリ内にありました。今度のプログラムはpublic_htmlのサブディレクトにあるので,インクルードファイルを手に入れるには親ディレクトリまで上がっていかなければなりません。
インストールしたGeeklogシステムに他のものを混ぜたくないなら,いつも私がやっている方法ですが、自分のプログラムを置くディレクトリをGeeklogがインストールされているディレクトリの外に置けばよいのです。そして,Webサーバーのディレクティブを使って,そのディレクトリをGeeklogがインストールされている領域にマッピングします。難しそうに聞こえますが簡単です。Apacheの場合には設定ファイルの中で次のように"Alias"ディレクティブを使います。
Alias /hello/ "/path/to/your/hello/"
もちろん,この場合,"require_once"文ではlib-common.phpのフルパスを指定する必要があります。
require_once( '/path/to/geeklog/public_html/lib-common.php' );
プラグインにすべきか
これはやや高度な話題で,いくつかの点でここで論じるのはふさわしくありませんが,Geeklogを知っていて少し使ったことがある人ならほとんど誰でもGeeklogのプラグインについて知っているでしょう。自分独自のGeeklogのプログラムを書いている時には,この疑問について考えていることは明らかです。Geeklogのプログラムがプラグインとは限りません。上述の例もそうです。プラグインを書くにはある特定の様式でプログラムを書き,Geeklog独自の関数を実装する必要があります。また,Geeklogにプラグインの存在を知らせるため,データベースに項目を追加する必要があります。
一般的には,Geeklogのコメントエンジンを使いたい,Geeklogの検索エンジンを使いたい(つまり,プログラムのデータをGeeklogの検索機能に統合したい),あるいはGeeklogの投稿エンジンを使いたい場合は,プラグインを書かなければなりません。そうでないなら,ただコードを書けばよいのです。サイズは重要ではありません。ある大きさを超えたらプラグインにしなければならないという制限はないからです。
いくつかの注意点
Geeklogの基本について,2つ3つ手短に紹介します。
- $_USER配列はGeeklogによって値をセットされた状態で渡されます。$_USER['uid']が1よりも大きければ,そのユーザーがログインしているとわかります。そうでなければゲストユーザーです。
訳注:ゲストユーザーの場合は$_USERが定義されないこともあるので,単にif ($_USER['uid'] > 1) {とするよりは,
if (isset($_USER['uid']) && $_USER['uid'] > 1) {とする方がよいとされています。
だから上述の例で,"geekerグループのメンバー"でなく"ログインユーザー"であるかを調べたい場合は,このif文を相応に変更しさえすればよいのです。この配列にはGeeklogのユーザーテーブルから取り出した全ての情報を含んでいて,2番目に役に立つインデックスは$_USER['username']です。
- $_CONF 配列にはconfig.phpで設定している全ての情報が含まれています。どんなことが載っているのかはconfig.phpを調べてください。
- 上述の2つの配列はグローバル変数なので,関数内で使用するにはPHPの流儀に従って,
global $_CONF, $_USER;
とする必要があります。プログラム本体の関数の外側では,この2つの変数をglobal宣言なしで使えます。
他の関数
最も広く使われている、Geeklogが提供する関数COM_siteHeader()とCOM_siteFooter()に注目してください。それぞれオプションのパラメータを渡すことで,ある目的を達成できます。
COM_siteHeader() と COM_siteFooter()
COM_siteHeader()はヘッダと左ブロックを表示しますが,パートナーであるCOM_siteFooter()はフッタと右ブロックを制御します。
デフォルトでは,COM_siteHeader()は左ブロックを表示し,COM_siteFooter()は右ブロックを表示しありません。この動作を変更するにはどうしたらよいかは,lib-common.php中のソースコードを調べてください。
COM_startBlock() と COM_endBlock() lib-common.phpで定義されていて,同じように役に立つ関数の組み合わせはCOM_startBlock()とCOM_endBlock()です。COM_startBlock()は3つのオプション・パラメータを受け取ます。タイトル,ヘルプファイル,テンプレートです。最も役に立ち,ほぼいつでも使われるのはタイトルで,ブロックのタイトル部分に表示される文字列です。ヘルプファイルを指定すれば,Geeklogはそのブロック用のクエスチョンマークアイコンを表示し,ヘルプファイルへのリンクも張ます。そして,他のテンプレートファイルが指定されない限り,デフォルトでは'blockheader.thtml'テンプレートが使用されます。COM_startBlock()を呼び出す度にCOM_endBlock()を呼び出さなければなりません。COM_endBlock()の唯一のオプション・パラメータはテンプレートで,デフォルトはblockfooter.thtmlです。
どのGeeklogのサイトを見てもわかりますが,ブロックはそれぞれ内部でネストすることができます。
<?php
require_once( 'lib-common.php' );
$display = COM_siteHeader();
$display .= COM_startBlock("Outer Block")
. "This text should be inside the outer block but outside the inner block"
. COM_startBlock("Inner Block")
. "This text should be inside the inner block"
. COM_endBlock()
. COM_endBlock();
$display .= COM_siteFooter();
echo $display;
?>
HTMLの表の中でネストされたブロックを使用するときには,適切な場所でCOM_endBlock()を確実に呼び出しさえすればよいのです。これらの関数は HTMLの表も出力するので,適切な場所でCOM_endBlock()を呼び出さないと,ただしく表示されません。
<?php
require_once( 'lib-common.php' );
$display = COM_siteHeader();
$display .= COM_startBlock("Outer Block")
. "This text should be inside the outer block but outside the inner blocks"
. "<table align=center width=100% border=0>"
. "<tr><td align=center width=50%>"
. COM_startBlock("Left Inner Block")
. "This text should be inside the left inner block"
. COM_endBlock()
. "</td>"
. "<td align=center width=50%>"
. COM_startBlock("Left Inner Block")
. "This text should be inside the right inner block"
. COM_endBlock()
. "</td></tr></table>"
. "This text should be below the inner blocks but inside the outer block"
. COM_endBlock();
$display .= COM_siteFooter();
echo $display;
?>
この2つの関数を使う大きな利点は,サイトの管理者やユーザーがGeeklogのテーマを変更するときはいつでも,GUIが追従して変化するということです。あなたのプログラムはいつでもサイト全体の外観と同じものになます。
lib-common.phpには他にもHTMLを生成する有用な関数があり,とても役に立つはずです。
COM_optionList( $table, $selection, $selected='', $sortcol=1 )
この関数は,引数の$selected変数をHTMLのselect文に使い,与えられたテーブルからHTMLの"<option" リストを作ます。この関数が行っていることより良く理解するにはソースコードを見るとよいのですが,とても役に立ちます。同様に,
COM_checkList( $table, $selection, $where='', $selected='' )
は,引数のselect文とwhere文を使って内部で与えられたテーブルに問合せを行い,チェックボックスのリストを作ります。もう1つ役に立つのは,
COM_errorLog( $logentry, $actionid = '')
関数で,$actionidが1ならGeeklogのログファイルに,2なら画面にログを出力します。
COM_checkWords( $Message )
この関数を使えば,Geeklogの(やや原始的な)禁止語フィルタリング機能にアクセスできます。たとえば"cock"をフィルタリングすると,全く無害な"peacock"という単語もフィルタリングされてしまうので,あまり役に立つとは言えません。それでも禁止語フィルタリング機能を使いたいなら,単純に次のようにしてください。
$text = COM_checkWords( $text );
COM_mail( $to, $subject, $message, $from = '', $html = false, $priority = 0 )
この関数は、その名前の通りメール送信機能を提供します。 lib-common.phpにはここで説明しきれないほど多くの関数がありますが,特に,クエリ文字列へのアクセス機能を提供する2つの非常に重要な関数を紹介します。クエリ文字列とは次のようなものです。
http://www.example.com/someprogram.php?variable=value&othervariable=othervalue
クエリ文字列は?以降の部分です。この部分がプログラムに渡されます。この例では,someprogram.php内で,PHPの設定が"register_globals"がオンになっていれば,"$variable"という変数がプログラム内で自動的に生成され,"value"という値を持ちます。でも,"register_globals"がオンになっているとある種のセキュリティ上の問題が生じるので,オンにすることを好まない人が多いのです。残念なことに,現時点では,Geeklogでは"register_globals"をオンにしておかなければならない(そうしなくてもよくなるよう,プログラマが書き直すまでは,ということですが)ので,関連する危険を減らすために,クエリ文字列を取得する特別な関数を利用できるようになっています。
訳注:バージョン1.4.0以降,Geeklog本体は"register_globals"がオフで動作するようになりましたが,プラグインの中には対応していないものがあります。
プログラムの最初で,次のようなコードを挿入するだけです。最初の行ではプログラムで期待するグローバル変数だけを定義し,次の行でその変数の値を安全に取得しています。
COM_setArgNames(array('variable','othervariable'));
$variable = COM_getArgument('variable');
$othervariable = COM_getArgument('othervariable');
データベースの使用
Geeklogにはデータベースを抽象化するレイヤーがあり,理論上はバックエンドにどんなデータベースシステムでも使えるはずですが,実際Geeklogで実装しているのはポピュラーなMySQLだけです。いずれにせよ,Geeklogでプログラムを書くときには,PHPにふつうに備わっているデータベースではなく,同じような名前がついていてほぼ同じふるまいをするDB_関数を使います。
Geeklogで重要なことは,クエリの中でテーブル名を直接指定してはいけないということです。代わりに, $_TABLESグローバル変数を使い,独自のテーブルを使うなら,そのテーブル名を$_TABLESに追加しておきます。こうしないと,Geeklogではインストーラで "テーブル接頭辞" を指定することができるので,テーブル名を直接指定すると,自分の書いたコードがテーブル接頭辞が違うシステムでは動かないからです。自分が書いたコードを他のGeeklogサイトで実行したいとは思わないかもしれませんが,先のことはわからないので,ルールを守ることをお勧めします。私は他のGeeklogサイトで実行する必要はないだろうと思ったコードを書いたことがありますが,案の定,2年後にはテーブル接頭辞の違うサイトで走らせたくなって,全部$_TABLESを使って書き直すハメになっています。
最後に,Geeklogでデータベースを使う際にとても重要なことを述べると,いかなる状況にせよ,デフォルトのGeeklogのテーブルに変更を加えてはならないということです。こんなことをしたくなるのは,たとえば,ユーザー用のある特定のオプションを記憶しておきたくて,Geeklogのusers テーブルにフィールドを1つ2つ追加したくなるようなときです。たとえば,"売買"プログラムを書いていて販売する品物の入力をユーザーに許可しているとしよう。売りに出されているものの一覧を見るときに,ユーザーが自分自身が売りに出している品物を表示するかどうかを決めさせたいだろう。"seeown"という論理型のフィールドをGeeklogのusersテーブルに追加したくなるかもしれませんが,絶対にしてはいけません。代わりに,独自の"buysell_userprefs"というテーブルを作成し,必要なフィールドを追加することです。少なくともユーザーIDを表すフィールドは必要だと思われるので,"bsp_uid"という名前にします。"自分の品物も見る(see your own items)"というフィールドも必要なので,"bsp_seeown"という名前にしましょう。
一般的には,テーブル名の略語を各フィールド名の先頭に付けるのが好まれます。今の場合では,ユーザー毎の "売買の設定(buy sell preferences)"を保存するテーブルなので,全フィールに"bsp_"という名前を付けます。これは必須ではないが,良い習慣で,異なるテーブルで同じ名前のフィールドが存在する事態は避けられます。テーブル名の接頭辞をつけないと,場合によっては,クエリで問題が生じたり,予期せぬ結果になることがあります。
$_TABLESへ追加
既に述べたように,独自のテーブルを定義するなら,テーブル名を$_TABLESに追加する必要があります。
$_TABLES['buysell_userprefs'] = $_DB_table_prefix . 'buysell_userprefs';
テーブル名の接頭辞を表すグローバル変数を追加したので,このコードはどのGeeklogサイトでも動作するようになった。もちろん,テーブルを追加する毎に$_TABLESにテーブル名を追加するコードを書かなければなりません。最後に,他のグローバル変数と同様,関数内で使用したいなら,global変数であることを宣言しなければなりません。
このコードは,プラグインを書いている場合は,ふつう,プラグインのconfig.phpに記述します。そうでないなら,コードのまとめ方に応じていくつか選択肢があります。大きなファイルを1つ作るなら,そのファイルの先頭に書くし,自分が書いているプログラムファイル全部から使用するなら,インクルードファイル内に書く。基本的には,置けるところにはできるだけ置き,プログラムから実行され,見えるようにしておくべきです。
まとめ
最後に以上をまとめます。'bsp_seeown'設定にセットされているものを表示するだけの単純なプログラムを書きます。
<?php
require_once('lib-common.php');
$display = COM_siteHeader();
if ( $_USER['uid'] < 2 ) {
$display .= "ログインしていません。";
$display .= COM_siteFooter();
echo $display;
exit;
}
$_TABLES['buysell_userprefs'] = $_DB_table_prefix . 'buysell_userprefs';
$sql = "SELECT bsp_seeown FROM {$_TABLES['buysell_userprefs']} "
. " WHERE {$_TABLES['buysell_userprefs']}.bsp_uid = {$_USER['uid']} ";
$result = DB_query( $sql );
if ( ! $result ) {
// エラーが発生したので,プログラムを終了する方がよい
}
if ( DB_numRows( $result ) <> 1 ) {
// ユーザー毎に項目は1つしかいらないはず
// そうでない場合は,エラーにしたいだろう
// あるいは,最初にこの変数が1よりも小で
// あることをチェックしたいかもしれありません。
// この場合は,ユーザーがまだ設定を行っ
// ていないということになます。
}
$bsp = DB_fetchArray( $result );
if ( ! $bsp ) {
// some error condition
}
$display .= COM_startBlock("あなたの設定値は次の通りです: ")
. $bsp['bsp_seeown']
. COM_endBlock();
$display .= COM_siteFooter();
echo $display;
?>
うわぁ,このプログラムでは多くのことが行われています。思っていたより遙かに多い! Geeklogでデータベースを使うときには,最初にチェックすべきエラー条件がたくさんあります。実際には,普通のPHPのMySQL関数を使ってプログラムしている場合と全く同じなのだが。エラー条件をチェックし,それに応じた行動を起こすのはいつだって非常に良い習慣です。
ユーザーの設定を調べる前に,もちろんログインしていることを確認しなければなりません。そうでないなら,そこでプログラムを終了させます。次に,自分が使う独自のテーブルを$_TABLESグローバル変数に追加します。その次は,SELECT文の中では$_TABLES変数を使うことで,コードがポータブルであることを保証します。このコードを他のGeeklogサイトへ持って行っても何も変更する必要はありません。
使用した個々のDB_関数に関しては,似たような名前のPHPのMySQL関数と同じ振る舞いをします。どのような動作かよく知らないなら,Geeklogのソースコードだけでなく,PHPのマニュアルも確認してください。利用できる DB_ 関数一覧については, /path/to/geeklog/system/lib-database.php をチェックしてください。
関数を定義する
Geeklogで関数を定義するのは,もちろんPHPの場合と全く同じです。とはいえ,Geeklogのコード作法からはいくつか学ぶべきものがあります。手頃なのは,関数名に3文字から5文字の接頭辞をつけることです。こうすることで自分が書いた関数と他の開発者が書いた関数が衝突し,両立できないという事態が避けられます。例えば,自分が書いた User Pages プラグインでは,全ての関数に "UPAGE_" という接頭辞を選んでつけた。
関数からどのようにして返り値を返すかを理解するのは,GeeklogあるいはPHP全般でも決して簡単ではありません。多くの関数ではHTMLフォーマットの文字列を返すので,エラー条件を返すのは難しい。どの状況でも通用する解決策はありません。とはいえ,僕はたいていの場合はうまく方法を2つ発見した。関数内でエラーが発生したら,NULL文字列を返して呼び出す側にNULL文字列かどうかを確認してもらってもよいし,遭遇した問題に関するエラーメッセージを返すだけでもよい。この場合,呼び出す側は何かおかしなことが起こったことがわからないだろう。これは問題になるかもしれないし,そうならないかもしれありません。呼び出す側次第です。
データベースからHTMLの選択ボックスを作る2つの関数を見てみましょう。最初の関数が本質的にGeeklogの COM_optionList 関数と同じだが,様々な引数で呼ばれ,COM_optionListよりやや非力です。
下記の関数の定義で最初にわかることは,PHPでは関数の引数にデフォルト値を設定することができるということです。つまり,この関数を呼び出すときには,最初の2つの "myName" と "myOptions" という引数しか指定する必要はありません。myName はこの要素が持つ変数名であり,myOptions は "mySep" パラメータ(デフォルト値は "|")で区切られたオプションのリストです。
パラメータにデフォルト値を指定することに関して理解しておくべき重要なことは,右側にある X個の引数にしかデフォルト値を指定できないということです。つまり,第1引数にデフォルト値を指定して,第2引数に指定せず,第3変数には指定するなどといったことはできありません。最初のパラメータ(0個以上)にはデフォルト値を指定せず,デフォルト値を指定したパラメータ以降の残りのパラメータにはすべてデフォルト値を指定しなければならないということです。下記の関数を呼び出すときに,たとえば,"mySep"パラメータに値を指定してデフォルト値を上書きしたいとしたら,その左側にあるパラメータには全て値を指定してデフォルト値を上書きしなければならなくなます。だから,"myDefault", "myMulti", "mySize" に値を指定しなければなりません。
というわけで,次のどの形でも,この関数を呼び出すことができます。
$display .= SSM_inputSelect( "SelectBox", "one|two|three" ); $display .= SSM_inputSelect( "SelectBox", "one|two|three", "one" ); $display .= SSM_inputSelect( "SelectBox", "one|two|three", "one", 0 ); $display .= SSM_inputSelect( "SelectBox", "one|two|three", "one", 0, 1 ); $display .= SSM_inputSelect( "SelectBox", "one:two:three", "one", 0, 1, ":" );
でもたとえ "mySep" しか指定したくなくても,次のようにはできありません。
$display .= SSM_inputSelect( "SelectBox", "one:two:three", ,,, ":" );
従って,この話の教訓は,パラメータにデフォルト値を持たせる予定なら,引数の順序をよく考えなければならないということです。一番変更されにくそうなパラメータを最後に置き,一番変更されそうなパラメータを最初に置きたいだろう。
function SSM_inputSelect( $myName, $myOptions, $myDefault="", $myMulti=0,
$mySize=1, $mySep="|", $visible=true )
{
$retval .= ""
. "<SELECT size=\"" . $mySize . "\" name=\"" . $myName . "\"";
$retval .= ($myMulti == 0) ? ">" : " multiple>";
$arrayOptions = explode($mySep,$myOptions);
foreach ($arrayOptions as $oneOption) {
$oneOption = trim($oneOption);
if ( $myMulti == 0 )
if ( $oneOption == $myDefault )
$retval .= "<OPTION SELECTED>" . $oneOption . "</OPTION>";
else
$retval .= "<OPTION>" . $oneOption . "</OPTION>";
else
if ( in_array( $oneOption, $myDefault ))
$retval .= "<OPTION SELECTED>" . $oneOption . "</OPTION>";
else
$retval .= "<OPTION>" . $oneOption . "</OPTION>";
}
$retval .= ""
. "</SELECT>"
. "";
return $retval;
}
さて,上記の関数を元にして,データベースからデータを取り出し,オプションリストの中に表示するもう一つの関数を見てみましょう。
function SSM_inputSelectDBField( $myName, $myTable, $myField, $myDefault="",
$mySize=1, $myMulti=0, $extra="", $mySep="|" )
{
// select distinct entries from the given field of given table
$sql = "SELECT DISTINCT " . $myField . " FROM " . $myTable
. " ORDER BY " . $myField;
// allows us to add an extra entry that was not in the DB
if ( $extra != "" )
$myOpts = $extra . $myOpts;
$result = DB_query($sql);
// format the data as required by SSM_inputSelect()
while ( $R = DB_fetchArray( $result ) )
if ( $myOpts == "" )
$myOpts .= $R[$myField];
else
$myOpts .= $mySep . $R[$myField];
// now call the guy doing the actual work
$retstr .= SSM_inputSelect( $myName, $myOpts, $myDefault, $myMulti,
$mySize, $mySep );
return $retstr;
}
最終的にできたのは,SSM_inputSelect 関数を元にした同類の関数だが,今度は,ENUM型のフィールドを取り,存在する限りの ENUM型の値全てから選択ボックスをつくります。
// Does not yet allow multi select but should be rewritten to do this
function SSM_inputEnumDBField( $myName, $myTable, $myField, $myDefault="", $visible=true )
{
// query the DB to extract the enum values
$qqq = "DESCRIBE $myTable $myField";
$result = DB_query( $qqq );
$arow = DB_fetchArray( $result );
$myArr = explode( ",", trim( strstr( $arow['Type'], "(" ), "()")) ;
// now format the values as required by SSM_inputSelect()
$idx=0;
$cnt = count($myArr);
while($idx<$cnt)
{
$myArr[$idx] = trim( $myArr[$idx], "'" );
$idx++;
}
sort( $myArr );
$myList = implode( "|", $myArr );
// now call our workhorse
return SSM_inputSelect( $myName, $myList, $myDefault );
}
ここでの教訓は,関数をきちんと定義して再利用可能にするということです。お互いに関係のない2つの違う関数を書くこともできただろうが,その代わりに3つめのベースになる関数を書き,残りの2つの関数はこの関数に仕事をやらせた。たとえ選択ボックスの表示法をかなり変えるとしても,変更は1箇所で済みます。
サポートなど
Geeklogでサポートを求める最適な場所はもちろん,Geeklog本家のサイトです。でも,Squatty と Portal Partsを含めて,他にいくつかチェックすべき素晴らしい場所があります。Squatty と Blaine は筋金入りの開発者であり,いくつかのポピュラーなテーマ,プラグイン,ハックに対して責任を持っています。
バグ報告や機能リクエストをしたいなら,ここでアカウントを取得してから行うこと。おかしな箇所がわからなければ修正のしようもないからです。僕もいくつかバグを報告し,即座に修正してもらった。また,バグの原因を突き止めて修正コードを投稿して,採用されたこともあります。機能リクエストを行い,何年かかけて追加してもらった。Geeklogの開発チームは小規模だが,非常に献身的でユーザーからのフィードバックを待っています。
