Humhubのカスタムモジュールの作り方（既存モジュールの改造：Modelにフィールドを追加する）

# はじめに

Humhubのカスタムモジュールの開発について、今回は、既存モデル（モジュールのDB（ActiveRecord））にフィールドを追加して利用するカスタマイズを紹介する。今回の参考例は、スペースのデフォルト言語プロパティを整えることを目的に、「Space」モジュールを直接改造するカスタマイズだ。

# 事前準備

事前準備としては、計画立案と方法の調査・確認・検討を行うべきだろう。

##設計（構成の検討）
今回、”スペースのデフォルト言語”という設定項目にしたいので、既存のSpaceモジュールのアクセスするDBにフィールドを追加して扱えるようにしたい。追加するフィールド名をlanguageとし、文字列を扱えるデータ型にしておけばよいだろう。あとは、Spaceモジュールの動作をカスタマイズするかSpaceモジュールのModelsを通じて、ActiveRecordを扱う処理を作成する、という手順だ。

## 手法の調査
Humhubの[公式説明](https://docs.humhub.org/docs/develop/models)によると、まずは、humhubのルートディレクトリでコマンドを実行する必要があるようだ。そして、 protected/humhub/migrations に作成された the resulting migration をyour modules migration folder にコピーして、 スキーマの設定を書き加えよ、と。スキーマの設定に当たっては、Yii2の[MigrationGuide](https://www.yiiframework.com/doc/guide/2.0/en/db-migrations#creating-migrations)を読め、とある。

##手法の確認
ActiveRecordで直接作用してくれるような仕組みはない。開発者が手を動かすしかないのだ。事前準備は特になく、コマンドを打ち込む心構え、コードを書き切る気構えが必要だ。・・・事前調査資料をよく読んで何をするか考えるしかないっすね。

##手順の検討
以下の手順では、もしも作業中断してもシステム運用が停止しないように、念のため対応順序に配慮した。すなわち、**DB側フィールドの作成、ActiveRecordのルール・コントローラ作成、フィールドの呼び出しのビュー（フロントエンド）の順で作成する。こうすれば、ユーザー側ではフロンドエンドが適用されるまで操作に影響を生じないはずだ。**



# 作業実行

## DBへのフィールド追加
マイグレーション（=the resulting migration）の名前を add_xxx_column_to_yyy_table の形式とした場合、ファイルの内容は、 必要となる addColumn と dropColumn を含めてくれる。（ちょっとだけ自動）
(https://www.yiiframework.com/doc/guide/2.0/ja/db-migrations#karamuwo-zhui-jiasuru)

    php yii migrate/create add_language_column_to_space_table --fields=”language:vchar(5) DEFAULT NULL”
    ( ‘yes’ と答える )

    mv /var/www/html/humhub/protected/humhub/migrations/m~~~~~_add_language_column_to_space.php /var/www/html/humhub/protected/humhub/modules/space/migrations/
    ( ~~~~~の部分は、作成日時によって異なる数字 )

    php yii migrate/up --includeModuleMigrations=1
    ( Yii と humhub のバージョンの相性によってエラーが出ることがある。その場合は、エラーの指示に従って修正すること。)

DBにアクセスして、Spaceテーブルの構造を操作し、languageが加わったことを確認する。

|名前|データ型|照合順序|NULL|デフォルト値|
|---|---|---|---|---|---|
|language|varchar(5)|utf8mb4_unicode_ci|はい|NULL|

## MVCモデルの組み立て（Model：　ActiveRecordルールの設定）

ActiveRecordにルールを設定するメリットについては、[Yii2フレームワークの公式説明](https://www.yiiframework.com/doc/guide/2.0/ja/db-active-record)を読んでほしい。入力のバリデーションを行なってデータを適切に扱うことができるようにする仕組みだ。


    /var/www/html/humhub/protected/humhub/modules/space/models/Space.php

      function rules() にlanguageを加える。
      １３０行目付近
        ['language', 'in', 'range' => array_keys(Yii::$app->i18n->getAllowedLanguages())],

      function scenarios() にLanguageを加える。
        $scenarios[static::SCENARIO_EDIT] = ['name', 'color', 'description', 'tags', 'join_policy', 'visibility', 'default_content_visibility', 'url', 'language'];
        $scenarios[static::SCENARIO_CREATE] = ['name', 'color', 'description', 'join_policy', 'visibility', 'default_content_visiblity', 'language'];
        
      function attributeLabels()にLanguageを加える。
        'language' => Yii::t('SpaceModule.base', 'Language')

※　humhubの[internationalization機能](https://docs.humhub.org/docs/develop/i18n)に即して、Yii::t（）を用いている。上記コードブロックの最終行での　’Language’ が messages/ja/base.php に書き加えるキーになる。

## MVCモデルの組み立て（Controller: Controllerの扱うデータにlanguageを加える）

 
    /var/www/html/humhub/protected/humhub/modules
                                  /space/modules/manage/controllers/DefaultController.php
    function actionIndex() のreturn に、languageを加える。
       $languages = Yii::$app->i18n->getAllowedLanguages();
       $col = new \Collator(Yii::$app->language);
       $col->asort($languages);
       return $this->render('index', ['model' => $space, 'languages' => $languages]);

    /var/www/html/humhub/protected/humhub/modules/space/controllers/CreateController.php
    function actionCreate() に Language を加える。
    終盤付近
       $languages = Yii::$app->i18n->getAllowedLanguages();
       $col = new \Collator(Yii::$app->language);
       $col->asort($languages);
 
       return $this->renderAjax('create', ['model' => $model, 'visibilityOptions' => $visibilityOptions, 'joinPolicyOptions' => $joinPolicyOptions, 'languages' => $languages]);

## MVCモデルの組み立て（View：　表示部分）

    /var/www/html/humhub/protected/humhub/modules/space/modules/manage/views/default/index.php
    ３１行目付近　 language 選択のdropDownListを加える。
      <?php if (count($languages) > 1) : ?>
        <?= $form->field($model, 'language')->dropDownList($languages, ['data-ui-select2' => '']); ?>
      <?php endif; ?>

### internationalization処理対応
humhubのルートディレクトリで、次のコマンドを実行する。すると、モジュールのディレクトリの中にMessageフォルダが作成され、その中に各言語のリソースが作成される[humhub公式説明](https://docs.humhub.org/docs/develop/i18n)。Internationalization]HumhubVer.1.6以降では、既存のリソースを上書きすることなく、必要に応じた追記処理をおこなってくれるようだ。しかし、この動作は保証されたものではないので、事前に必要なメッセージリソースのバックアップを取っておくことをオススメしたい。

    php yii message/extract-module space


その後、リソースファイルを編集する。例えば、日本語メッセージリソースの編集は次のとおり。

    /var/www/html/humhub/protected/humhub/modules/space/messages/ja/base.php
    （ファイルを開き、配列の中から、'Language'キーを探して、対応する値を設定。）
       'Language' => '主な使用言語'

最後に、このlanguageデータを設定・編集する場所を作る。ただし、カスタムテーマを使用している場合は、当該テーマのViewに記載する必要がある。
humhubのdropDownListウィジェットを使用した記述を行なっている。詳細は別途、Qiita投稿することとしたい。

    /var/www/html/humhub/protected/humhub/modules/space/views/create/create.php
    ２５行目付近　 language 選択のdropDownListを加える。
      <?php if (count($languages) > 1) : ?>
          <?= $form->field($model, 'language')->dropDownList($languages, ['data-ui-select2' => '']); ?>
      <?php endif; ?>


##　動作確認
今回のカスタマイズ作業を完了すると、スペースを追加する操作において、次のように表示される。下段に、Languageのドロップダウンが表示されていることがわかるだろう。
![スクリーンショット 2020-11-22 17.43.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/699890/c37a7125-6683-a2c8-0fa2-6195efb0b631.png)

なお、日本語設定では、次のとおり。見出し部分が、日本語翻訳で表示されていることがわかる。
![スクリーンショット 2020-11-22 17.53.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/699890/210f5eea-2d0e-6721-17ff-72df52350c0e.png)

スペースを実際に作成して、DBをのぞいてみれば、languageフィールドに設定した言語情報が記録されていることがわかるだろう。（DBのフィールド情報の確認画面は割愛。）


# まとめ
今回は、既存Modelのカスタマイズの例として、プロパティを追加し、DB（ActiveRecord）にフィールドを追加して操作（新規追加）する例を取り上げた。あわせて、翻訳処理対応も解説したが、翻訳処理対応は今後も頻繁に出てくるので利用方法にはぜひ慣れておきたい。