読者です 読者をやめる 読者になる 読者になる

Piece Frameworkで独自のプラグインを作る

PHP

Piece_Unity_Plugin_Factory::addPluginDirectoryを使うと、PEARでインストールしたディレクトリ以外に、Piece_Unityのプラグインを置くことができます。
KernelConfiguratorプラグインが提供する設定ポイントpluginDirectoriesを使うのが推奨のようです。詳しくは、公式サイトのアプリケーション独自のプラグインディレクトリを設定するを参照してください。
この機能を利用して、処理にかかった時間を記録する独自のフィルターとインターセプタを作ってみたいと思います。


Piece Frameworkは、フレームワーク利用者側からは、「インタセプタ→アクション→レンダリング→出力フィルタ」の順番で処理が行われているように見えます
そこで、インタセプタで処理を開始した時刻を記録して、出力フィルタで処理が終了した時刻を取得し、記録することにします。


まず、エントリーポイントとなるphpに以下のような記述を追加しました。

//...
ini_set('include_paht', $lib. PATH_SEPARATOR. ini_get('include_path'));

Piece_Unity_Plugin_Factory::addPluginDirectory($lib);
//...

$libがカスタム・プラグインの配置先ディレクトリです。


フィルターは、インターセプタは"Piece_Unity_Plugin_{クラス名}"のように命名し、PEARのディレクトリ配置規約にしたがってファイルを配置します。
処理開始を記録するインタセプタのクラス名をPiece_Unity_Plugin_Interceptor_ExectimeStart、処理時間を計算し出力する出力フィルタPiece_Unity_Plugin_OutputFilter_ExectimeEndとしました。
独自のフィルタ、インタセプターなのにPiece_Unity_Plugin接頭辞を使うのは気持ちが悪いですね。でも、現段階では仕方がなさそうなので、このまま進めます。


最終的なディレクトリ構造は次のようになります。

-public_html
  index.php エントリポイント
-webaps
 -actions
  -lib
    -Piece
      -Unity
         -Plugin
           -Interceptor
              ExectimeStart.php 
           -OutputFilter
              ExectimeEnd.php
...

ExectimeStart.phpは次のようなクラスです。

<?php
// ExectimeStart.php
require_once 'Piece/Unity/Plugin/Common.php';

class Piece_Unity_Plugin_Interceptor_ExectimeStart extends Piece_Unity_Plugin_Common
{
    function invoke() {
        list($s, $m) = explode(" ", microtime());
        $GLOBALS['__exectime_stime__'] = $s + $m;
        return true;
    }
}
?>

Piece_Unity_Plugin_Commonを継承し、invokeメッソドを実装し、プラグイン内で実行したい処理を記述します。
piece-unity-config.yamlで設定項目を追加するためのオプションも提供されていますが、今回は特に必要がないので省略しました。
このクラス内で、取得した時刻を、次の出力フィルタに渡す必要がありますが、今回は、グローバル変数を使いました。
一方、ExectimeEnd.phpは次のようなクラスです。

<?php
// ExectimeEnd.php
require_once 'Piece/Unity/Plugin/Common.php';

class Piece_Unity_Plugin_OutputFilter_ExectimeEnd extends Piece_Unity_Plugin_Common
{
    function invoke($buffer) {
        list($s, $m) = explode(" ", microtime());
        $etime = $s + $m;
        $totaltime = $etime - $GLOBALS['__exectime_stime__'];
        return $buffer. "\n<!-- $totaltime sec -->";
    }
}
?>

先のExectimeStartクラスと同じく、Piece_Unity_Plugin_Commonを継承して作ります。
invokeメッソドを実装しているところまでは同じですが、出力フィルタの場合は、引数に$buffer、すなわちビューがレンダリングした出力内容を受け取っているところが異なります。


piece-unity-config.yamlにフィルター、インタセプタの設定を追加すれば、リクエストの処理時間を記録することができます。

- name: KernelConfigurator
  point:
    - name: pluginDirectories
      type: configuration
      value:
        - ../webapp/lib
- name: InterceptorChain
  point:
    - name: interceptors
      type: extension
      value:
        - Interceptor_ExectimeStart
- name: OutputBufferStack
  point:
    - name: filters
      type: extension
      value:
         - OutputFilter_ExectimeEnd

Piece_Unityのプラグインは、singletonです。このことを利用すれば、インタセプタと出力フィルタを別々に作らずに、次のように一つにすましてしまうこともできます。

<?php
// Exectime.php
require_once 'Piece/Unity/Plugin/Common.php';

class Piece_Unity_Plugin_Filter_Exectime extends Piece_Unity_Plugin_Common
{
    var $stime;

    function invoke($buffer = null) {
        if (is_null($buffer)) {
            list($s, $m) = explode(" ", microtime());
            $this->stime = $s + $m;
            return true;
        }
        else {
            list($s, $m) = explode(" ", microtime());
            return $buffer. "<!-- ". ($this->stime - $s - $m). "-->";
        }
    }
}
?>

このプラグインを使う場合は、piece-unity-config.yamlを次のように設定します。

- name: KernelConfigurator
  point:
    - name: pluginDirectories
      type: configuration
      value:
        - ../webapp/lib
- name: InterceptorChain
  point:
    - name: interceptors
      type: extension
      value:
        - Filter_Exectime # (A)
- name: OutputBufferStack
  point:
    - name: filters
      type: extension
      value:
         - Filter_Exectime # (A)と同じインスタンス!