Delphi for PHP - Zend Frameworkを統合する: ZCache - パート2

By: Tomohiro Takahashi

Abstract: この記事は、Delphi for PHPの開発者であるJosé León氏のブログに掲載されたものです。残りのプロパティやメソッドを追加した後、ラッパーの全てのプロパティを使用してZend_Cacheコンポーネントを生成し、コンポーネントを完成させます。

Zend Frameworkを統合する: ZCache (パート2)

前回の記では、Zend Frameworkコンポーネントをラップする基礎になるものを作成する方法を解説しました。また、このコンポーネントはDelphi for PHP 2.0にインストールして、ビジュアル的に使用することができました。さらにコンポーネントにプロパティやサブプロパティを追加する方法についても解説しました。

この記事では、残りのプロパティやメソッドを追加した後、ラッパーの全てのプロパティを使用してZend_Cacheコンポーネントを生成し、コンポーネントを完成させようと思います。

Backendの選択項目を追加する

Frontendと同様に、Backendにはいくつかの選択項目があります。次のドキュメントで確認してください:

http://framework.zend.com/manual/ja/zend.cache.backends.html

まず、Frontendの選択項目の時と同様に、サブプロパティを作成するために永続化プロパティを追加する必要があります:

class ZCacheBackendSQLiteOptions extends Persistent
{
protected $_databasepath="";

function getDatabasePath() { return $this->_databasepath; }
function setDatabasePath($value) { $this->_databasepath=$value; }
function defaultDatabasePath() { return ""; }

protected $_vacuumfactor=10;

function getVacuumFactor() { return $this->_vacuumfactor; }
function setVacuumFactor($value) { $this->_vacuumfactor=$value; }
function defaultVacuumFactor() { return 10; }
}
class ZCacheBackendMemcachedOptions extends Persistent
{
protected $_servers=array();

function getServers() { return $this->_servers; }
function setServers($value) { $this->_servers=$value; }
function defaultServers() { return array(); }

protected $_compression="0";

function getCompression() { return $this->_compression; }
function setCompression($value) { $this->_compression=$value; }
function defaultCompression() { return "0"; }
}

次に、それらをプロパティとして追加する必要があります:

protected $_backendsqliteoptions=null;

function getBackendSQLiteOptions() { return $this->_backendsqliteoptions; }
function setBackendSQLiteOptions($value) { $this->_backendsqliteoptions=$value; }
function defaultBackendSQLiteOptions() { return null; }

protected $_backendmemcachedoptions=null;

function getBackendMemcachedOptions() { return $this->_backendmemcachedoptions; }
function setBackendMemcachedOptions($value) { $this->_backendmemcachedoptions=$value; }
function defaultBackendMemcachedOptions() { return null; }

そしてそれらをコンストラクタの中で生成します:

$this->_backendsqliteoptions=new ZCacheBackendSQLiteOptions();
$this->_backendmemcachedoptions=new ZCacheBackendMemcachedOptions();

最後に、パッケージでプロパティエディタを設定します:

registerBooleanProperty("ZCache", "BackendMemcachedOptions.Compression");
registerPropertyEditor("ZCache","BackendMemcachedOptions.Servers","TStringListPropertyEditor","native");
registerPropertyEditor("ZCache","BackendSQLiteOptions.DatabasePath","TFilenamePropertyEditor","native");

最終的な結果は次のようになります:

Hide image
Click to see full-sized image

コンポーネントを使ってアプリケーションを実行する

新しくアプリケーションを作成して、ページにZCacheコンポーネントをドロップし実行すると、"Cannot serialize a component without an owner"というエラーが発生します。これは、作成したPersistentを継承したサブプロパティによるものですが、VCL for PHPのストリーミングシステムは所有者オブジェクトを必要としており、これによりセッションにプロパティを格納する際に完全修飾名を生成することができるのです。

そのため、ZCacheの全てのサブプロパティ用に基本クラスを作成し、適切な所有者を返します。今回の場合はZCacheコンポーネントになります。

class ZCacheOptions extends Persistent
{
protected $ZCache=null;

function readOwner()
{
return($this->ZCache);
}

function __construct($aowner)
{
parent::__construct();
$this->ZCache=$aowner;
}
}

次に、全ての選択項目についてその基本クラスをPersistentからZCacheOptionsに変更して、そのコンストラクタの中でプロパティを生成する際に$thisを渡す必要があります:

function __construct($aowner = null)
{
//Calls inherited constructor
parent::__construct($aowner);

//Frontend properties
$this->_frontendfunctionoptions= new ZCacheFrontendFunctionOptions($this);
$this->_frontendclassoptions= new ZCacheFrontendClassOptions($this);
$this->_frontendfileoptions= new ZCacheFrontendFileOptions($this);
$this->_frontendpageoptions= new ZCacheFrontendPageOptions($this);

//Backend properties
$this->_backendsqliteoptions=new ZCacheBackendSQLiteOptions($this);
$this->_backendmemcachedoptions=new ZCacheBackendMemcachedOptions($this);
}

これで、ZCacheコンポーネントを配置したシンプルなページを実行してもエラーが発生しなくなります。

Zend_Cacheコンポーネントを生成する

以上で全ての情報が揃いました。全ての選択項目を使用してZend_Cacheコンポーネントを生成する必要がありますが、ユーザーが選択したFrontendおよびBackendによって異なります。

コンポーネントに、Zend_Cacheのインスタンスを保持するメンバーを追加する必要があります:

public $zend_cache=null;

このメンバ変数はpublicにしましたので、場合によってはユーザーがラッパーを通さずに直接利用することが可能です。

そしてZend_Cacheコンポーネントを生成するタイミングを決定しなければなりませんが、適切なタイミングとしてコンポーネントの初期化中、つまり、コンポーネントの全てのプロパティが読み込まれて利用可能になり、コントロールのイベントが呼び出される前にライブラリから呼び出されるpreinit()メソッドをオーバーライドするのが良いでしょう。
ます最初に行うのは、FrontendおよびBackendの設定に関する共通のプロパティを、Zend_Cacheコンポーネントの要求する配列に変換することです:

$frontendOptions=array();
$backendOptions=array();

//Frontend common properties
$frontendOptions['caching']=$this->_enabled;
$frontendOptions['cache_id_prefix']=$this->_prefix;
$frontendOptions['lifetime']=$this->_lifetime;
$frontendOptions['logging']=$this->_logging;
$frontendOptions['write_control']=$this->_checkwrite;
$frontendOptions['automatic_serialization']=$this->_serialization;
$frontendOptions['automatic_cleaning_factor']=$this->_cleaningfactor;
$frontendOptions['ignore_user_abort']=$this->_ignoreuserabort;

//Backend common properties
$backendOptions['cache_dir']=$this->_cachedir;
$backendOptions['file_locking']=$this->_filelocking;
$backendOptions['read_control']=$this->_checkread;
$backendOptions['read_control_type']=$this->_readcontroltype;
$backendOptions['hashed_directory_level']=$this->_hasheddirectorylevel;
$backendOptions['hashed_directory_umask']=$this->_hasheddirectoryumask;
$backendOptions['file_name_prefix']=$this->_filenameprefix;
$backendOptions['cache_file_umask']=$this->_cachefileumask;
$backendOptions['metadatas_array_max_size']=$this->_metadatasize;

次に、プロパティに応じてどのFrontendおよびBackendを使用するのか選択します:

switch ($this->_frontend)
{
case cfOutput:
$frontend='Output';
break;

case cfFunction:
$frontend='Function';
break;

case cfClass:
$frontend='Class';
break;

case cfFile:
$frontend='File';
break;

case cfPage:
$frontend='Page';
break;
}

switch ($this->_backend)
{
case cbFile:
$backend='File';
break;

case cbSQLite:
$backend='Sqlite';
break;

case cbMemcached:
$backend='Memcached';
break;

case cbAPC:
$backend='Apc';
break;

case cbZendPlatform:
$backend='Zend Platform';
break;
}

最後に、選択した設定項目を基にZend_Cacheコンポーネントを生成します:

$this->zend_cache=Zend_Cache::factory($frontend, $backend, $frontendOptions, $backendOptions);

メソッドを追加する

キャッシュを利用できるようにするには、メソッドを追加して、その中で対応するZend_Cacheの各メソッドを単に呼び出して情報を読み書きできるようにする必要があります:

function load($id, $doNotTestCacheValidity = false, $doNotUnserialize = false)
{
$this->zend_cache->load($id, $doNotTestCacheValidity, $doNotUnserialize);
}

function save($data, $id = null, $tags = array(), $specificLifetime = false)
{
$this->zend_cache->save($data, $id, $tags, $specificLifetime);
}

function start($id, $doNotTestCacheValidity = false)
{
$this->zend_cache->start($id, $doNotTestCacheValidity);
}

function end($tags = array(), $specificLifetime = false)
{
$this->zend_cache->end($tags, $specificLifetime);
}

function remove($id)
{
$this->zend_cache->remove($id);
}

function cleanAll()
{
$this->zend_cache->clean(Zend_Cache::CLEANING_MODE_ALL);
}

function cleanOld()
{
$this->zend_cache->clean(Zend_Cache::CLEANING_MODE_OLD);
}

function cleanMatching($tags)
{
$this->zend_cache->clean(Zend_Cache::CLEANING_MODE_MATCHING_TAG, $tags);
}

function cleanNotMatching($tags)
{
$this->zend_cache->clean(Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG, $tags);
}

function call($name, $parameters = array(), $tags = array(), $specificLifetime = false)
{
$this->zend_cache->call($name, $parameters, $tags, $specificLifetime);
}

clean()メソッドの呼び出しが4種類ありますが、Zend_Cacheの定数を使用しなくても良い点に注目してください。

コンポーネントのテスト

簡単なテストを行うには、フォームにZCacheコンポーネントをドロップして、出力内容をキャッシュするように、そのプロパティをデフォルトのままにします。次にフォームにボタンを配置してダブルクリックし、OnClickイベントハンドラを生成します。そのイベントハンドラ内に以下のように記述します:

function Button1Click($sender, $params)
{
if(!$this->ZCache1->start('mypage'))
{
// output as usual:
echo 'Hello world! ';
echo 'This is cached ('.time().') ';
$this->ZCache1->end(); // the output is saved and sent to the browser
}
echo 'This is never cached ('.time().').';
}

これは、同様の方法で利用可能なZend Frameworkから持ってきたサンプルですが、もちろん多くのコードを書く必要はありませんし、キャッシュをどのように生成して初期化するのか憶えておく必要もありません。コンポーネントには全てのプロパティが適切な値でリストアップされており、ドロップダウンで選択可能になっているためです。

ボタンをクリックすると、次のような出力が得られます:

Hide image

何度クリックしても最初の出力と同じものが表示されます。これは、出力がキャッシュされているので、実行されずに直接キャッシュから出力されたことを意味します。他方、2つ目の数字は毎回実行されたものです。

さて、このパート2の記事でコンポーネントが完成し、利用する準備が整いました。記事がとても長くなってしまうので、Zend_Cacheコンポーネントを生成する際にサブプロパティをどのように使用しているのかは解説していません。

とにかく次の記事では、VCL for PHPと統合する方法を解説します。これによりユーザーは、どのコンポーネントやページをキャッシュするのか簡単に選択できます。

気に入ったでしょ?

Server Response from: ETNASC02