baserCMSのサンプルプラグインで遊ぼう

baserCMSのアドベントカレンダーのためにQiitaへ登録して
初めて記事を書くことになりました。

ネタは色々あったけど、調べることが多すぎて時間の関係でボツになったので
素材(baserCMS)の味を活かした記事を書くことにします。

## baserCMSのサンプルプラグインについて
### サンプルプラグイン(BcPluginSample)とは
baserCMSは特に設定を変更せずそのままインストールするとサンプルテーマなどの
初期データが入ります。baserCMS5系だと、その中に「BcPluginSample」という
サンプルプラグインも同梱されていると思います。

今回は、baserCMS 5.1.4とサンプルプラグインを使って
baserCMSの表示処理を変えてみたいと思います。

### プラグインのインストール
※念の為、壊れてもいいようなbaserCMS環境を用意しましょう。


このプラグインは初期状態ではインストールされてないので、管理画面にログインし、
プラグイン管理画面からインストールしてみましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3946212/ee420ae2-7faa-c571-d9d3-a5f12b41b179.png)

> ツールバーに少しの変化をもたらすだけのサンプルプラグインです。

何やら意味深ですが、インストールしてみると変化に気がつくと思います。
ログイン時に表示されるツールバーを見ると・・・。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3946212/e33969f3-a6bc-8427-c351-64fafefa997d.png "マスコットキャラクター「べっしー」")

baserCMSの公式マスコットキャラ「べっしー」が表示されてます。
これがこのサンプルプラグインの動作になります。

## プラグインの処理内容
### ビューイベントリスナー
このプラグインの処理内容を見るために下記ソースファイルを確認しましょう。
```/plugins/BcPluginSample/src/Event/BcPluginSampleViewEventListener.php
    public function rightOfToolbar() {
        $html = new HtmlHelper(new View());
        $img = $html->image('BcPluginSample.bassy.png', ['width' => '24px']);
        $link = $html->link($img, 'https://basercms.net', ['target' => '_blank', 'escape' => false]);
        echo '<li>' . $link . '</li>';
    }
```

サンプルプラグインにはビューイベントリスナーというビュー(View)に関する
イベントに対して、実行したいコールバック関数を登録するソースファイルが存在します。

コールバック関数の内容はシンプルで、rightOfToolbarイベント時に
べっしーアイコンのリンクを表示するというもの。
これによりツールバーのログインユーザー名の左にべっしーが表示されます。

### イベントの発火箇所

今回使われている「rightOfToolbarイベント」は下記ソースファイルを見ると
発火箇所がわかります。
※こちらはbaserCMSのコアファイルなので変更しないようにしましょう。

```/vendor/baserproject/bc-admin-third/templates/element/toolbar.php
    if(method_exists($this, 'dispatchLayerEvent')) {
        // EVENT rightOfToolbar
        $event = $this->dispatchLayerEvent('rightOfToolbar', [], ['layer' => 'View', 'class' => '', 'plugin' => '']);
        if ($event !== false) {
          echo ($event->getResult() === null || $event->getResult() === true)? '' : $event->getResult();
        }
    }
```

イベントの詳しい説明は割愛しますが、動きとしてはイベント発火のタイミングで
そのイベントに対して登録されているコールバック関数が実行されます。

今回のサンプルプラグインを例にすると、従来の処理に加えてツールバーの右側表示時に
「べっしーの表示」を追加で行っているようなイメージです。

詳細についてはbaserCMS公式の[イベント](https://baserproject.github.io/5/plugin/event)をご確認ください。

## 表示のカスタマイズ
### ツールバー左側にも表示
先ほどのtoolbar.phpをよく見てみると「leftOfToolbarイベント」もあることに
気付いたかもしれません。
もちろんこのleftOfToolbarイベントも利用可能です。

それではサンプルプラグインに、leftOfToolbarイベント時にも
べっしーを表示する処理を追加してみましょう。

やることは単純で、イベントキー($events)へのイベント追加と
rightOfToolbar関数をコピーして関数名を「leftOfToolbar」に変更するだけです。


```/plugins/BcPluginSample/src/Event/BcPluginSampleViewEventListener.php
    // eventsにleftOfToolbarを追加
    public $events = ['rightOfToolbar', 'leftOfToolbar'];

    // 省略

    // rightOfToolbar関数をコピーして関数名を「leftOfToolbar」に変更
    public function leftOfToolbar() {
        $html = new HtmlHelper(new View());
        $img = $html->image('BcPluginSample.bassy.png', ['width' => '24px']);
        $link = $html->link($img, 'https://basercms.net', ['target' => '_blank', 'escape' => false]);
        echo '<li>' . $link . '</li>';
    }
```

ページを更新してみるとどうなるでしょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3946212/b154ad7f-7c41-52a3-ddb1-17333303e83f.png "増えるべっしー")

左右にべっしーが表示されるようになりました！

### ページ内にランダムな位置で表示
その気になればどこにでもべっしーを追加できるでしょう。

たとえばページ内容全体を取得できる「afterLayoutイベント」を使えば
以下のようなことも可能です。

```/plugins/BcPluginSample/src/Event/BcPluginSampleViewEventListener.php
    // eventsにafterLayoutイベントを追加
    public $events = ['rightOfToolbar', 'leftOfToolbar', 'afterLayout'];

    // 省略

    public function afterLayout($event) {

        $view = $event->getSubject();
        // 画面全体のhtmlを取得
        $contents = $view->fetch('content');

        $html = new HtmlHelper($view);
        $link = '<a href="/">' . $html->image('BcPluginSample.bassy.png', ['width' => '24px']) . '</a>';

        // bodyが欲しいので切り出し
        $bodyStart = strpos($contents, '<body');
        $bodyEnd = strpos($contents, '</body>') + strlen('</body>');
        $head = mb_strcut($contents, 0, $bodyStart);
        $body = mb_strcut($contents, $bodyStart, $bodyEnd-$bodyStart);
        $foot = mb_strcut($contents, $bodyEnd);
 
        // 雑だが「<」をタグとみなして挿入位置をランダムで決定
        $count = mb_substr_count($body, '<');
        $idx = mt_rand(0, $count-1);

        // 挿入位置にべっしーを追加
        $replacedBody = preg_replace('/((.*?>){' . $idx . '})(.+)/s', '$1' . $link . '$3', $body);

        // べっしー入りのcontentで上書き
        $view->assign('content', $head . $replacedBody . $foot);
    }

```

これで表示してみましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3946212/283936f5-c49e-4046-2669-93c52eca89d6.png "見出しに入り込むべっしー")

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3946212/7d2ec9b4-418f-ce72-53c7-87c7cbe02cdd.png "ウィジェットに入り込むべっしー")

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3946212/6412c0dd-7042-6c5f-8ccc-10abd2802454.png "グローバルメニューに入り込むべっしー")

べっしーをクリックしたり、ページを更新するたびにべっしーの位置が変わります。

ただ雑な挿入処理なので表示が崩れたり、見えない位置に挿入されるので、
そこはご容赦ください。

## おわりに
今回はbaserCMS5系に入っているサンプルプラグインのビューイベントリスナーに
コールバック関数を追加して遊んでみました。

今回はビューに関するイベントのみ触れましたが、他の種類のイベントもあるので
興味があれば試してみてはいかがでしょうか。

ただ、呼び出されるタイミングとか引数として渡されるデータなどが分かりづらいので、
トライ＆エラーになることも多いです。根気強くチャレンジしましょう:pensive: