PowerCMS Xの編集画面でリレーションの写映をする

公開

PowerCMS Xの編集画面において、リレーションで選択しているオブジェクトのデータを表示したいケースがあるようです。具体的には、セミナーモデルで講師モデルのオブジェクトを選択できるように設定し(タイプを数値にして単一選択)、セミナーモデルの編集画面で講師オブジェクトが選択されている場合はその付近に講師オブジェクトの名前・会社名・職種カラムを表示するというものです。MySQLに「ビュー」がありますが、それに近いイメージと言えば良いでしょうか。

昨年からPADOに写映タイプを作ることを考えていたのですが、難しそうなので代替テンプレートとpre_viewフックを使用する方法で検討を進めました。

完成した表示を示します。データベースが正規化された状態を維持しつつ、リレーションで関連付けているオブジェクトの情報も編集画面で確認できるようになりました。
リレーションで選択したオブジェクトのデータを表示させた例

カスタマイズ方法

テンプレート

講師の情報を表示をするために、alt-tmplで講師カラムのテンプレートをカスタマイズします。tmpl/edit.tmplからリレーションの表示に関わる部分をコピーし、その後ろでプラグインでセットする変数を出力するようにします。

<mt:ignore>ここに edit.tmpl のリレーション編集テンプレートをコピーする</mt:ignore>

<mt:ignore>写映する内容を記述</mt:ignore>
<mt:if name="value">
<div class="row form-group">
  <div class="col-lg-2">
    講師名
  </div>
  <div class="col-lg-10">
      <div class="form-control" style="background-color: #eceeef;"><mt:var name="instructor_name" escape /></div>
  </div>
</div>

<div class="row form-group">
  <div class="col-lg-2">
    会社名
  </div>
  <div class="col-lg-10">
      <div class="form-control" style="background-color: #eceeef;"><mt:var name="instructor_company" escape /></div>
  </div>
</div>

<div class="row form-group">
  <div class="col-lg-2">
    職種
  </div>
  <div class="col-lg-10">
      <div class="form-control" style="background-color: #eceeef;"><mt:var name="instructor_position" escape /></div>
  </div>
</div>
</mt:if>

プラグイン

pre_viewフックを利用し、講師が選択されている場合は講師オブジェクトを取得して変数にセットします。

<?php
require_once LIB_DIR . 'Prototype' . DS . 'class.PTPlugin.php';

class Sample extends PTPlugin {

    public function __construct () {
        parent::__construct();
    }

    /**
     * 講師オブジェクトのデータを変数に格納する
     *
     * @param Prototype $app
     * @param PADOMySQL $seminar
     * @return void
     */
    private function set_instructor_data( $app, $seminar ) {
        if ( $seminar->instructor ) {
            $instructor = $app->db->model( 'instructor' )->load( $seminar->instructor );
            if ( $instructor ) {
                $app->ctx->vars['instructor_name']     = $instructor->name;
                $app->ctx->vars['instructor_company']  = $instructor->company;
                $app->ctx->vars['instructor_position'] = $instructor->position;
            }
        }
    }

    /**
     * pre_viewフックでの処理
     *
     * @param Prototype $app
     * @return void
     */
    public function pre_view( $app ) {
        if (
            $app->param( '_model' ) === 'seminar' &&
            $app->param( '_type' ) === 'edit' &&
            ! empty( $app->param( 'id' ) )
        ) {
            $seminar = $app->ctx->stash( 'seminar' );
            $this->set_instructor_data( $app, $seminar );
        }
    }

}

リレーションで設定している講師オブジェクトが変わった際にどうするかが課題ですが、保存するまではJavaScriptで値を空にする、もしくはJavaScriptで選択したオブジェクトのデータを取得する、のいずれかでしょうか。

選択したオブジェクトのデータをJSONで返すメソッド(/powercmsx/index.php?__mode=object_data_json&_model=instructor&id=1)は以下のようなコードです。

/**
 * オブジェクトのデータをJSONで返す
 *
 * @param Prototype $app
 * @return void
 */
public function get_object_data_json( $app ) {
    $id = $app->param( 'id' );
    $table_name = $app->param( '_model' );
    $table = $app->get_table( $table_name );

    if ( $app->is_login() && ! empty( $id ) && isset( $table ) ) {
        $object = $app->db->model( $table_name )->load( $id );
        if ( $object ) {
            $json = [
                'name'     => $object->name,
                'company'  => $object->company,
                'position' => $object->position,
            ];
            header( 'Content-type: application/json' );
            echo json_encode( $json );
        } else {
            $app->json_error( 'Object not found.', null, 404 );
        }
    } else {
        $app->json_error( 'Invalid request.', null, 403 );
    }
}