DrupalのViewsにUIから変更可能なカスタムのオプションを追加する方法


やりたいこと

  • DrupalのViewsにこんなオプションを追加したい
    • 単純な真偽値を保存できる
    • UIから変更可

やり方

ディスプレイエクステンダーというプラグインを作成します。

まずはmy_module/src/Plugin/views/display_extender/MyFlagDisplayExtender.phpを作成します。必要なファイルはこれだけです。

ファイルの中身は以下のように編集していきます。

まず通常のプラグインと同様にアノテーションにメタ情報を書き込みます。クラスはDisplayExtenderPluginBaseを継承します。


<?php

namespace Drupal\my_module\Plugin\views\display_extender;

use Drupal\views\Plugin\views\display_extender\DisplayExtenderPluginBase;
use Drupal\Core\Form\FormStateInterface;

/**
 * Myフラグのオプションを追加する.
 *
 * @ingroup views_display_extender_plugins
 *
 * @ViewsDisplayExtender(
 *   id = "my_flag",
 *   title = @Translation("Myフラグ"),
 *   help = @Translation("Myフラグの設定を行います。"),
 * )
 */
class MyFlagDisplayExtender extends DisplayExtenderPluginBase {

この時点で/admin/structure/views/settings/advancedの画面下部「ディスプレイエクステンダー」の項目に自分のディスプレイエクステンダーが追加されているはずなので、チェックして保存します。

オプションのデフォルト値を定義します。今回はオプション名はvalueとします。$optionsはこのプラグイン内だけの値なので汎用的な名前で大丈夫です。ちなみに、このオプションは強制的に全てのディスプレイに追加されるので、デフォルト値は全てのディスプレイに適用しても問題ない値にしましょう。


  /**
   * {@inheritdoc}
   */
  public function defineOptions() {
    $options['value'] = ['default' => TRUE];
    return $options;
  }

ビューのUIにカスタムオプションの項目を追加します。


 /**
   * {@inheritdoc}
   */
  public function optionsSummary(&$categories, &$options) {
    // 新しいカテゴリーを作る.
    $categories['my_category'] = [
      'title' => 'Myカテゴリー ',
      'column' => 'second',
    ];

    // オプションを追加する.
    $options['my_flag'] = [
      'category' => 'my_category',
      'title' => 'Myフラグ',
      'des' => 'Myフラグの設定を行います。',
      // Myフラグのオン・オフを設定画面へのリンクテキストに使用する.
      'value' => $this->options['value'] ? 'オン' : 'オフ',
    ];
  }

これによりビューの設定画面ではこのように表示されます。

さきほど追加したオプションの設定フォームを定義します。ここは通常のForm APIの書き方と変わりません。$form_state->get('section') === 'my_flag'の部分を抜くと全部のオプションでこのフォームが表示されるので注意してください。ちなみにこのmy_flagoptionsSummaryで設定したオプションのキーと同一にする必要があります。(ややこしい)


  /**
   * {@inheritdoc}
   */
  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
    if ($form_state->get('section') === 'my_flag') {
      $form['value'] = [
        '#type' => 'checkbox',
        '#title' => 'Myフラグ',
        '#default_value' => $this->options['value'],
        '#description' => 'Myフラグをオンにする場合はチェックを入れてください。',
      ];
    }
  }

これによりさきほどの設定画面の「オン」の文字クリックでこのようなフォームが開きます。

設定フォーム保存時の処理を書きます。


  /**
   * {@inheritdoc}
   */
  public function submitOptionsForm(&$form, FormStateInterface $form_state) {
    if ($form_state->get('section') === 'my_flag') {
      $this->options['value'] = $form_state->getValue(['value']);
    }
  }

}

全部つなげるとこのようになります。


<?php

namespace Drupal\my_module\Plugin\views\display_extender;

use Drupal\views\Plugin\views\display_extender\DisplayExtenderPluginBase;
use Drupal\Core\Form\FormStateInterface;

/**
 * Myフラグのオプションを追加する.
 *
 * @ingroup views_display_extender_plugins
 *
 * @ViewsDisplayExtender(
 *   id = "my_flag",
 *   title = @Translation("Myフラグ"),
 *   help = @Translation("Myフラグの設定を行います。"),
 * )
 */
class MyFlagDisplayExtender extends DisplayExtenderPluginBase {

  /**
   * {@inheritdoc}
   */
  public function defineOptions() {
    $options['value'] = ['default' => TRUE];
    return $options;
  }

  /**
   * {@inheritdoc}
   */
  public function optionsSummary(&$categories, &$options) {
    // 新しいカテゴリーを作る.
    $categories['my_category'] = [
      'title' => 'Myカテゴリー ',
      'column' => 'second',
    ];

    // オプションを追加する.
    $options['my_flag'] = [
      'category' => 'my_category',
      'title' => 'Myフラグ',
      'des' => 'Myフラグの設定を行います。',
      // Myフラグのオン・オフを設定画面へのリンクテキストに使用する.
      'value' => $this->options['value'] ? 'オン' : 'オフ',
    ];
  }

  /**
   * {@inheritdoc}
   */
  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
    if ($form_state->get('section') === 'my_flag') {
      $form['value'] = [
        '#type' => 'checkbox',
        '#title' => 'Myフラグ',
        '#default_value' => $this->options['value'],
        '#description' => 'Myフラグをオンにする場合はチェックを入れてください。',
      ];
    }
  }

  /**
   * {@inheritdoc}
   */
  public function submitOptionsForm(&$form, FormStateInterface $form_state) {
    if ($form_state->get('section') === 'my_flag') {
      $this->options['value'] = $form_state->getValue(['value']);
    }
  }

}

使い方

オプションの値はDisplayPluginBaseオブジェクトのdisplayというパラメーターに格納されています。hook_views_query_alterで使うならこんな感じです。

/**
 * Implements hook_views_query_alter().
 */
function my_module_views_query_alter(ViewExecutable $view, QueryPluginBase $query) {
  // ディスプレイを取得.
  $display = $view->getDisplay()->display;

  // Myフラグの値を取得.
  if (isset($display['display_options']['display_extenders']['my_flag'])) {
    $my_flag = $display['display_options']['display_extenders']['my_flag']['value'];
    // Do something.
  }
}

$display['display_options']['display_extenders']['my_flag']my_flagはプラグインIDです。

Viewsのカスタマイズ方は本当にいろいろあるので、また何か面白いネタがあれば共有したいと思います。