VCL for PHP-PHPコンポーネントの標準規格
Delphi for PHPは、VCL for PHPによって、ビジュアルなIDEに統合可能なPHPコンポーネントを作成するための標準規格を提供します。この標準規格は、既存のPHPのコードベースを再利用できるよう、可能な限りオープンであるかがチェックされています。
コンポーネントを作成することにより、次のようなメリットを得られます。
- 動作済みの機能を抽象化およびラップし、プロパテイ、メソッドやイベントを通して簡単に利用可能なインターフェースを提供できる
- 最高の再利用性を提供できる
- 最良のビジュアル開発のエクスペリエンスを享受できる
- さらに、サードパーティがコードを簡単に利用できる
以前ブログに掲載した記事では、わずかなHTMLとCSSで簡単にグラフを作成できることを見ました。それでは、それらのコードをコンポーネントにラップして、ツールパレットへのインストールや、フォームへのドラッグ&ドロップ、オブジェクトインスペクタでのプロパティ設定が行えるようにしましょう。
もし、Delphi for Windowsのコンポーネントを作成したことがあれば、この手順がいかにそれと似ているかが分かるでしょう。
コンポーネント作成の手順 1
フォルダ構成
コンポーネントは VCL for PHPフォルダ内の中に作らなければなりません。そのため、C:\Program Files\CodeGear\Delphi for PHP\2.0\vclの中にcsschartというフォルダを作成して、csscharts.inc.phpという名前のユニットを作成しましょう。このユニットは、これから記述しようとしている新しいコンポーネント用のコードになります。
クラスの派生
開発を始めるにあたり、ある既存のクラスから派生することが可能で、例えば、派生するのに最も適切なクラスはControlです。このControlクラスは、内部にコントロールをドラッグ&ドロップするのは許可しないものの、コンテナの中には配置可能であるビジュアルコントロールを作成したい場合には適切なクラスです。
以下は、コントロールの基本的なコードです。
<?php use_unit("controls.inc.php"); class CSSChart extends Control { function __construct($aowner = null) { parent::__construct($aowner); } } ?>
このコンポーネントクラスはCSSChartという名前で、Controlから派生し、後に利用するためにコンストラクタをオーバーライドしています。
プロパティの追加
チャートに表示するデータを格納するためのプロパティが必要になりますので、追加してみましょう。[Edit]-[Add published property]を選択すると、プロパティ名とデフォルト値の入力を促されます。以下が生成されたコードです。
protected $_data = array(); function getData() { return $this->_data; } function setData($value) { $this->_data = $value; } function defaultData() { return array(); }
情報を効率的に格納するprotectedなフィールドおよび、getter/setter/default関数が生成されました。このプロパティは'get'で始まるので、オブジェクトインスペクタに表示され、ユーザーによる値の変更も可能になります。
初期化
次に初期化用のコードを追加する必要があります。例えば、コントロールのデフォルトのサイズを設定し、デフォルト値に合致するように配列データを初期化します。
コンストラクタは次のようになるはずです。
function __construct($aowner = null) { parent::__construct($aowner); //Set the initial properties on the constructor $this->Width = 330; $this->Height = 145; $this->_data = array(); }
コンポーネントはどのようにHTMLを出力するのか?
以前ブログに掲載した記事には異なる形式のチャートがありましたが、例として水平バーのチャートを取り上げます。そのチャートを描画するのに使用したHTMLコードを見てみると、次のようになっています。
<ul class="chartlist"> <li> <a href="http://www.example.com/fruits/apples/">Apples</a> <span class="count">420</span> <span class="index" style="width: 42%">(42%)</span> </li> <li> <a href="http://www.example.com/fruits/bananas/">Bananas</a> <span class="count">280</span> <span class="index" style="width: 28%">(28%)</span> </li> <li> <a href="http://www.example.com/fruits/cherries/">Cherries</a> <span class="count">200</span> <span class="index" style="width: 20%">(20%)</span> </li> <li> <a href="http://www.example.com/fruits/dates/">Dates</a> <span class="count">100</span> <span class="index" style="width: 10%">(10%)</span> </li> </ul>
これらは基本的なリストであり、それぞれの項目にはテキストと2つのspanタグがあります。VCL for PHPのコンポーネント開発の基本は、コンポーネントのプロパティによって提供される情報を使用して、動的なコードでそれらのHTMLデータを出力することです。
ブラウザに何か表示するようコンポーネントに指示するには、dumpContents()メソッドをオーバーライドします。このメソッドは、コンポーネントのコンテンツを生成するために呼び出されます。では、HTMLデータを生成するために、以前追加したDataプロパティを使ってみましょう。
function dumpContents() { //Get the data to use $data = $this->_data; //Echoes the start of the list echo '<ul class="chartlist">'; //Iterates through the data and dump each <li> tag reset($data); while(list($key, $val) = each($data)) { echo '<li>'; echo '<A href="">'; echo $key; echo '</a>'; echo '<span class="count">' . $val . '</span>'; echo '<span class="index" style="width: ' . ($val / 10) . '%">(' . ($val / 10) . '%)</span>'; echo '</li>'; } //Echoes the end of the list echo '</ul>'; }
このコードは、表示するデータを繰り返し処理して、配列データの項目それぞれに応じて必要なコードを出力します。
コンポーネント作成の手順 2
デフォルトデータ
もし今すぐコンポーネントをインストールして、ページに配置した場合、Dataプロパティは空ですから何も表示されません。そのため、設計時には何らかの処理が必要です。
dumpContents()メソッドを書き直して、表示すべきデータがあるかどうかチェックしましょう。もし何も情報が無く、かつIDE内で実行される場合には、サンプルデータを追加して、コントロールがどのように見えるのかをユーザーがチェックできるようにします。
function dumpContents() { //Get the data to use $data = $this->_data; //If there is no information to show if(count($data) == 0) { //And we are in design-time if(($this->ControlState & csDesigning) == csDesigning) { //Let's use some sample data $data = array(); $data['PHP'] = 800; $data['Delphi'] = 700; $data['Java'] = 500; $data['C#'] = 400; } } //Echoes the start of the list echo '<ul class="chartlist">'; //Iterates through the data and dump each <li> tag reset($data); while(list($key, $val) = each($data)) { echo '<li>'; echo '<A href="">'; echo $key; echo '</a>'; echo '<span class="count">' . $val . '</span>'; echo '<span class="index" style="width: ' . ($val / 10) . '%">(' . ($val / 10) . '%)</span>'; echo '</li>'; } //Echoes the end of the list echo '</ul>'; }
IDEの中かどうかは、ControlStateプロパティとcsDesigning形式を使って判定できます。csDesigningは、コンポーネントがIDEの中で動作している時にだけ設定されます。
リストにスタイルシートを適用する
もしコンポーネントを実行すればその情報が見えますが、見た目はあまり良くありません。少なくもと元の記事と同じように見えるためには、何が足りないのでしょうか? チャートはスタイルシートを使用して描画されているので、コンポーネントにスタイル情報を出力させる必要があります。
最初の手順は、必要なスタイルすべてが含まれた.cssファイルを作成することです。では、csscharts.cssと名前を付けて、csscharts.inc.phpのあるフォルダと同じ場所に配置しましょう。
次のコードを追加します。
/* CHART LISTS */ .chartlist { font-family: Helvetica, Arial, sans-serif; color: #333; float: left; border-top: 1px solid #EEE; width: 15em; } .chartlist li { position: relative; display: block; border-bottom: 1px solid #EEE; _zoom: 1; } .chartlist li a { color: #2D7BB2; text-decoration: none; font-weight: bold; display: block; padding: 0.4em 4.5em 0.4em 0.5em; position: relative; z-index: 2; } .chartlist li a:hover { color: #333; } .chartlist .count { display: block; position: absolute; top: 0; right: 0; margin: 0 0.3em; text-align: right; color: #999; font-weight: bold; font-size: 0.875em; line-height: 2em; } .chartlist .index { display: block; position: absolute; top: 0; left: 0; height: 100%; background: #B8E4F5; text-indent: -9999px; overflow: hidden; line-height: 2em; } .chartlist li:hover { background: #EFEFEF; }
CSSスタイルシートの準備ができました。コンポーネントにそれを使用するよう指示する必要がありますが、dumpHeaderCode()メソッドをオーバーライドすることで可能です。このメソッドは、Pageコンポーネントがドキュメントの<head>セクションを生成する際に呼び出されるので、スタイルシートを出力するのに適切な場所です。
function dumpHeaderCode() { parent::dumpHeaderCode(); echo '<link type="text/css" rel="StyleSheet" href="' . VCL_HTTP_PATH .'/csschart/csscharts.css" />'; }
ここでは、親クラスのdumpHeaderCode()メソッドを呼び出して、先ほど記述したばかりの.cssファイルを取り込むための1行を出力しています。
VCL_HTTP_PATHとは?
VCL_HTTP_PATH は、VCL for PHPによって動的に定義される定数で、ブラウザで見た際に確実にVCLフォルダを参照できるようにするためのものです。そのため、そのようなことを心配せずに簡単にコンポーネント内にリソース(画像、JavaScript、CSS)を取り込めるのです。
複数のコンポーネント
しかし、ページ内に5個のチャートコンポーネントを取り込んだ場合はどうなるでしょう? .cssスタイルシートが5回も取り込まれることになるでしょう。これを防ぐ簡単な方法は、既に追加したかどうかをチェックすることです。
function dumpHeaderCode() { parent::dumpHeaderCode(); //If we have not dump the style sheet for charts yet, let's do it if(!defined('CSSCHARTS')) { define('CSSCHARTS', 1); //Note the VCL_HTTP_PATH constant echo '<link type="text/css" rel="StyleSheet" href="' . VCL_HTTP_PATH .'/csschart/csscharts.css" />'; } }
これでコンポーネントをIDEに追加する準備が整いました。これまででも追加することはできたのですが、サンプルプロジェクト上で動作させ、そこで実行時にそのコンポーネントを生成するのがベターですし、開発しながらテストできます。コンポーネントの準備がほぼ整ったら、安全にIDEに追加することができます。
IDEにコンポーネントを追加する
IDEにコンポーネントを追加するには、パッケージが必要となります。新規ユニットを作成して、作業しているフォルダと同じ場所にcsscharts.package.phpという名前で保存します。
以下は、今回のコンポーネントをインストールするパッケージ用のコードです。
<?php require_once("vcl/vcl.inc.php"); use_unit("designide.inc.php"); setPackageTitle("CSS Charts sample component"); //Change this setting to the path where the icons //for the components reside setIconPath("./icons"); //Change yourunit.inc.php to the php file //which contains the component code registerComponents("CSSChart", array("CSSChart"), "csschart/csscharts.inc.php"); registerPropertyEditor("CSSChart","Data", "TValueListPropertyEditor","native"); ?>
ユニットdesignide.inc.phpは、使用する以下の関数を含んでいます:
- setPackageTitleは、表示されるパッケージタイトルをIDEに指示します。
- setIconPathは、このパッケージ内のコンポーネントアイコンを検索する場所をIDEに指示します。
- registerComponentsは、csschart/csscharts.inc.phpユニットに格納されたCSSChartという名前のコンポーネントを、ツールパレットのCSSChartカテゴリにインストールするようIDEに指示します。そのパスは、VCL for PHPのパスからの相対パスでなければなりません。
- registerPropertyEditorは、CSSChartコンポーネントのDataプロパティを編集するのに、TValueListPropertyEditorという名前のプロパティエディタを使用するようIDEに指示します。
ここで、[Component]-[Install Packages]を選択してコンポーネントをインストールすると、ツールパレットの最下部に追加されます。それをページに配置すると、次のようになります。
Dataプロパティを選択すると、[...]ボタンが表示されクリックできるようになります。クリックするとダイアログを使ってDataプロパティの配列をカスタマイズできます。設計時にこのプロパティを変更すると、以下のような表示になります。
これまで見てきたように、VCL for PHPのコンポーネントの作成はとても簡単で、Delphi for Windowsのコンポーネントの作成と多くの類似点があります。
今後の記事では、今回のコンポーネントにDataSourceプロパティを追加する方法を紹介します。そのデータはデータベースのテーブルから取得し、今回のコンポーネントをますます便利なものにしてくれるでしょう。