開発ブログ

株式会社Nextatのスタッフがお送りする技術コラムメインのブログ。

電話でのお問合わせ 075-744-6842 ([月]-[金] 10:00〜17:00)

  1. top >
  2. 開発ブログ >
  3. CMS >
  4. baserCMS >
  5. [baserCMS3] テーマフックはどこへ消えた? テーマ内からイベントリスナーでコアの処理に介入する
no-image

[baserCMS3] テーマフックはどこへ消えた? テーマ内からイベントリスナーでコアの処理に介入する

こんにちは、ナカエです。

先週に続きbaserCMS3の記事です。
 

テーマフックとは

baserCMS2にはテーマフックという機能がありました。
参考:テーマに関する用語 - baserCMS公式wiki

テーマフックはbaserCMSの処理の途中で別の処理を割り込ませるための機能です。
テーマを作成中に、「プラグインを用意する程でもないけどコアの処理を少し変えたい」時に重用されていたはずです(推定)。


baserCMS3ではコアの処理のフックの仕組みが整理され、BaserEvent に変更されています。
プラグインからフックの処理を実行するためには単純化された仕様のイベントリスナーを作成するだけでよく、非常に便利になったと感じます。

ただ、その煽りを食らったため(?)テーマフックは召されてしまったようです。

プラグイン作るのは面倒だし、テーマ内からでもイベントリスナーを利用したい。
この記事では、BaserEventの仕組みを利用してテーマフックを再現します。
 

お題:テーマ独自のビュー変数を全てのテンプレートで共有する

テンプレート内で使いまわしたいビュー変数(テンプレート内で利用できる変数のこと)があるとします。
エレメントテンプレートを1つ変数定義用に用意して利用の都度インクルードするという手もあります。
bootstrap.phpでグローバル変数を定義するという手もあります。

前者は若干面倒くさく、後者は変数の有効範囲(スコープ)が大きすぎるため他の機能に影響がある可能性がないとも言いきれません。できれば避けたいところです。

ビューに使う変数はテンプレート内でのみ有効である、というのが望ましいですね。

そこでイベントリスナーの出番です。
今回利用するのはビューイベントリスナー。テンプレートが読み込まれる直前のbeforeRenderイベントにフックします。

 

イベントリスナークラスの作成

{テーマのディレクトリ}/Event/ViewVariablesEventListener.phpとしてイベントリスナーを作成します。

<?php
/**
 * Class ViewVariablesEventListener
 * {テーマのディレクトリ}/Event/ViewVariablesEventListener.php
 */
class ViewVariablesEventListener extends BcViewEventListener {

    /**
     * 登録イベント
     *
     * @var array
     */
    public $events = array(
        'beforeRender',
    );


    /**
     * すべてのビューで共有させるビュー変数
     * @var array
     */
    private $variables = array();


    /**
     * コンストラクタ
     * @param array $variables ビュー変数の配列
     */
    public function __construct(array $variables) {
        parent::__construct();
        $this->variables = $variables;
    }


    /**
     * beforeRender
     * ビューテンプレートの読込前の処理
     * 共通のビュー変数を追加する
     * @param CakeEvent $event
     */
    public function beforeRender(CakeEvent $event) {
        /**
         * @var View $view
         */
        $view = $event->subject();

        foreach($this->variables as $key => $val) {
            $view->set($key, $val);
        }
    }

}
 

イベントリスナーの登録

{テーマディレクトリ}/Core/bootstrap.php に先ほど作成したイベントリスナーの登録処理を記述します。
bootstrap.phpはbaserCMSの起動時に読み込まれます。
順番としてはル―ティングやControllerより前なので、テンプレートの読み込みよりもずっと前の段階です。
<?php
/**
 * bootstrap
 * 
 * 起動時に読み込まれます。 
 * 存在しない場合は無視します。
 */

/**
 * 今回のビュー変数に限らず、テーマ用の設定はまとめておくとすっきりする
 */
$config['MyTheme'] = array(
    'viewVars' => array(
        'siteTitle' => 'サイトタイトル',
        'startYear' => '2015',
    ),
);

/**
 * Configureクラスで設定を書き込んでおくとテンプレート内でも利用できる
 * イベントリスナーを使わずこれだけでもビューで共通の設定を利用することは可能
 * ただし長くて鬱陶しい
 * ex. <?php echo h(Configure::read('MyTheme.viewVars.siteTitle')) ?>
 */
Configure::write('MyTheme', $config['MyTheme']);


/**
 * イベントリスナーを設定
 */
//テーマのEventディレクトリをクラスの読み込み元として追加登録
App::build(array(
    'Event'    => array(dirname(__FILE__) . '/../Event/')
));

//利用するクラスを読込
App::uses('ViewVariablesEventListener', 'Event');
App::uses('CakeEventManager', 'Event');

//イベントリスナーを登録
$eventListener = new ViewVariablesEventListener(Configure::read('MyTheme.viewVars'));
CakeEventManager::instance()->attach($eventListener);

テーマ内のEventディレクトリはそのままではコアには認識されないので認識されるように変更し、 イベントリスナーのクラスを呼び出しています。


ここまで設定すれば、後はテンプレートで通常通り利用できます。
<?php echo h($siteTitle) ?>
いかがでしたでしょうか? 今回のお題は単なる一例ですが、 テーマ内からコアの処理をフックできると制作の自由度は広がるかと思います。 プラグイン開発のハードルが高いなあと思っている皆様には、その足がかりとしてもおすすめです。

参考記事

[baserCMS]プラグインを用意せずにイベント処理を発動させる方法例 - Qiita

最後に 〜baserCMS公式Wiki

最後に知名度が低いようなので宣伝をば。
baserCMS公式サイトにもマニュアルがありますが、
baserCMS公式Wikiにも有用な情報が掲載されています。

baserCMSをご利用の皆様、ぜひとも周知や編集にご協力お願いします。m(_ _)m
TOPに戻る