エクステンションの作成

エクステンションは第三者の開発者によって使われるはずのものなので、作るためにはさらにいくらかの努力を必要とします。 次に示すのは一般的なガイドラインです。

  • エクステンションは自己充足的でなければなりません。つまり外部の依存は最小限でなければなりません。 エクステンションがさらなるパッケージ、クラスまたはリソースファイルのインストールを必要とするならば、 それはユーザの頭痛となるでしょう。
  • エクステンションに属しているファイルは、エクステンション名を名前とする同じディレクトリの下で組織される必要があります。
  • エクステンションのクラスは、他のエクステンションのクラスとの競合を避けるために、何文字かの識別子を名前の前に置かれなければなりません。
  • エクステンションは、コードと合せて詳細なインストールとAPIドキュメンテーションが必要です。 これにより、エクステンションが使われる際に他の開発者に必要な時間と努力を減らします。
  • エクステンションは、適当なライセンスを持っていなければなりません。 オープンソースとクローズドソースプロジェクトの両方にエクステンションを使って貰いたければ BSD、MIT、その他のようなライセンスを考慮したほうが良いでしょう。GPLではありません。 なぜならGPLはその派生コードに同様にオープンソースであることを要求するためです。

以下に、概要で解説される分類により、新しいエクステンションを作成する方法を解説します。 主に自身のプロジェクトで使われるコンポーネントを作成するときも、これらの説明があてはまります。

1. アプリケーションコンポーネント

アプリケーションコンポーネントIApplicationComponentインタフェースを実装するかまたはCApplicationComponentの継承です。 メインのメソッドではIApplicationComponent::initを実装する必要があり、そこでコンポーネントの初期化処理を行います。 このメソッドはコンポーネントが生成された後で起動され、アプリケーション構成 で規定される初期値が適用されます。

デフォルトではリクエスト処理中に最初にアクセスされるときに生成され、初期化されます。 もしアプリケーションインスタンスが生成された直後にアプリケーションコンポーネントが生成される必要があるならば、 ユーザはそのIDをCApplication::preloadプロパティに記述しておかなければなりません。

2. ウィジェット

ウィジェットCWidgetまたはその子クラスの継承です。 新しいウィジェットを作成する最も簡単な方法は、既存のウィジェットを継承し、そのメソッドをオーバライドするか、またはそのデフォルトプロパティ値を変更することです。 たとえば、より素晴らしいCSSスタイルを[CTabView]に適用したいなら、ウィジェットを使用する際にそのCTabView::cssFileプロパティを構成することができます。 以下のようにCTabViewを継承することで、ウィジェットを使うときもはやプロパティを構成しないようにすることも可能です。

class MyTabView extends CTabView
{
    public function init()
    {
        if($this->cssFile===null)
        {
            $file=dirname(__FILE__).DIRECTORY_SEPARATOR.'tabview.css';
            $this->cssFile=Yii::app()->getAssetManager()->publish($file);
        }
        parent::init();
    }
}

上記において、プロパティがセットされてなければ、CWidget:initメソッドをオーバライドし、新しいデフォルトCSSスタイルをURLCTabView:cssFileに割り当てます。 拡張としてまとめられるように、MyTabViewクラスファイルを含む同じディレクトリの下に新しいCSSスタイルファイルを置きました。 CSSスタイルファイルはWebアクセスできないので、アセットとして公開する必要があります。

ゼロから新しいウィジェットを作製するために、主にCWidget::initCWidget::runの2つのメソッドを実装する必要があります。 ウィジェットをビューに挿入するために$this->beginWidgetを使うとき、最初のメソッドが呼ばれます。 最後に$this->endWidgetを呼ぶとき、第2のメソッドが呼ばれます。 これらの2つのメソッドの間で表示される内容を捕えて処理したい場合には、CWidget::initの中で出力バッファリングを用います。 さらにCWidget::runの中でバッファされた出力を取り出し処理を行います。

ウィジェットは、しばしば、CSS、JavaScriptまたは他のリソースファイルをウィジェットを使うページに含むことが必要です。 彼らがウィジェットクラスファイルと共にいて、通常ウェブユーザーによってアクセスできないので、これらのファイルはアセットと呼ばれます。 これらのファイルにウェブアクセスできるようにするため、上記のコード断片で示すように、[WebApplication::assetManager]を用いて公開する必要があります。 この他、CSSまたはJavaScriptファイルを現在のページに含めたいならば、CClientScriptを用いてそれを登録する必要があります。

class MyWidget extends CWidget
{
    protected function registerClientScript()
    {
        // ...CSS又はJavaScriptファイルをここで公開...
        $cs=Yii::app()->clientScript;
        $cs->registerCssFile($cssFile);
        $cs->registerScriptFile($jsFile);
    }
}

ウィジェットは、それ自身のビューファイルも備えているかもしれません。 もしそうならば、ウィジェットクラスファイルを含んでいるディレクトリの下にviewsという名のディレクトリをつくり、すべてのビューファイルをそこに置いてください。 ウィジェットクラスでは、ウィジェットの表示を行うために$this->render('ViewName')を用いてください。 そしてそれはコントローラで行う方法と似ています。

3. アクション

アクションCActionまたはその子クラスから継承されるべきです。 アクションとして主に実装されるべきメソッドはIAction::runです。

4. フィルタ

フィルタCFilterまたはその子クラスから継承されるべきです。 フィルタとして主に実装されるべきメソッドはCFilter::preFilterCFilter::postFilterです。 前者はアクションが実行される前に呼び出され、後者はアクションの実行後に呼び出されます。

class MyFilter extends CFilter
{
    protected function preFilter($filterChain)
    {
        // アクションが実行される前に行われるロジック
        return true; // アクションが実行されるべきでない場合は偽
    }
 
    protected function postFilter($filterChain)
    {
        // アクションが実行された後に行われるロジック
    }
}

$filterChainパラメータはCFilterChainタイプで、現在フィルタされているアクションの情報を含みます。

5. コントローラ

イクステンションとして配布されるコントローラCControllerの継承ではなくCExtControllerを継承するべきです。 主な理由は、CControllerはビューファイルがapplication.views.ControllerIDの下に存在するのに対し、CExtControllerはビューファイルが、コントローラクラスファイルを含むディレクトリのサブディレクトリであるviewsディレクトリに存在すると仮定するからです。 したがって、そのビューファイルがコントローラクラスファイルと共に存在するため、コントローラを再配布することはより簡単です。

6. バリデータ

バリデータはCValidatorを継承し、CValidator::validateAttributeメソッドを実装するべきです。

class MyValidator extends CValidator
{
    protected function validateAttribute($model,$attribute)
    {
        $value=$model->$attribute;
        if($value has error)
            $model->addError($attribute,$errorMessage);
    }
}

7. コンソールコマンド

コンソールコマンドCConsoleCommandを継承し、 CConsoleCommand::runメソッドを実装するべきです。 付加的に、CConsoleCommand::getHelpをオーバライドし、コマンドの素敵なヘルプ情報を表示することも可能です。

class MyCommand extends CConsoleCommand
{
    public function run($args)
    {
        // $argsは、このコマンドに対するコマンドラインの引数の配列です
    }
 
    public function getHelp()
    {
        return '使用法: このコマンドの使いかた';
    }
}

8. モジュール

モジュールの作成する方法についてはモジュールに関する章を参照してください。

モジュール開発の一般的なガイドラインは、自分自身を含むことです。 モジュールによって使用されるリソースファイル(例えばCSS, JavaScript, 画像)はモジュールと共に配布されるべきです。 そしてモジュールはそれらのファイルがWebからアクセス可能なように公開されるべきです。

9. 生成コンポーネント

生成コンポーネントエクステンションの開発はクラスを書くことに似ています。 再び、コンポーネントは自分自身を含むべきです。理由は他の開発者が容易に使用できるためです。

$Id: extension.create.txt 749 2009-02-26 02:11:31Z qiang.xue $

Be the first person to leave a comment

Please to leave your comment.