concrete5のフォームの項目に、ユーザー情報を自動挿入するブロック

[concrete5 Japan Advent Calendar](https://adventar.org/calendars/2481) 25日目の記事です。

concrete5(ホームページ作成・運用ソフトウェア、CMS) には標準でフォーム機能が用意されています。また、サードパーティ製のフォーム作成アドオンもあります。

## フォームにユーザーの属性を自動挿入したい
ホームページ上のフォームには、名前やメールアドレスを入力する欄があることが多いですね。そのようなフォームに、ログインしているユーザーが入力する場合を考えてみます。ウェブサービスなら、ごく普通に生じるケースだと思われます。

ユーザーに、自分の名前やメールアドレスをフォームに入力してもらう、という方法はどうでしょうか。ユーザーに手間をかけてしまいますし、記入ミスする可能性もあります。この方法は手間がかかる上に効率が悪そうです。
では、ユーザーの情報は自動挿入するようにしたらどうでしょうか。ユーザーに手間をかけませんし、メールアドレスの記入ミスも防げます(最初の入力時に記入ミスしていれば別ですが)。ユーザーエクスペリエンスの観点からは、この方法が好ましいと思います。

## フォームのコードは直接改変しないようにする

concrete5フォームのコードを改変すれば、ユーザーの属性を自動挿入できます。しかし、この方法は、フォームのコードを改変する手間がかかります。標準のフォーム以外も使うのであれば、それぞれのフォームを改変する必要があります。
この方法は、かなり手間がかかりそうです。

ユーザーの利便性が向上する施策であっても、管理運営側の手間がすごく増えるので実行されない、となってしまったら、悲しいですね。このため、フォームのコードを直接改変しなくても様々なフォームに対応させる方法を工夫しました。

## ユーザー属性を挿入するJavaScriptを作る

フォームを直接改変しないですむように、

1. ユーザーがログインしているか判定し、ログインしていればユーザー属性を取得する
2. ユーザー属性をデータに含むJavaScript(jQuery)を生成する
3. ページ読み込み時に、JavaScript(jQuery)を実行して、フォームに挿入する

というステップにしました。実装は、concrete5 の任意のフォームと Mautic を連携させるアドオン [My Mitsu Mautic](https://www.concrete5.org/marketplace/addons/my-mitsu-mautic) に近いです。

### ユーザーがログインしているか判定し、ログインしていればユーザー属性を取得する
ここはconcrete5の機能です。

    $u = new User(); // 現在のユーザーを取得
    if ($u->isLoggedIn()) : // ログインしているかどうかをチェックする
    ...
    echo h($u->getUserName()); // ユーザー名(アカウント名)を出力
    echo h($ui->getUserEmail()); // メールアドレスを出力
    ...
    $ui = UserInfo::getByID($u->getUserID()); // ユーザーIDから情報を取得
    echo h($ui->getAttribute($option1j)); // ユーザーの属性を取得
    ...
    endif;

Userクラスを呼び出すと、現在のユーザーが取得できて、ログインしているか判定したり、ユーザー名を取得したりできます。
ユーザーの情報は、UserInfoクラスから呼び出すようになっているので注意してください。データベースのテーブル上でも、ユーザーID、ユーザー名、メールアドレスなどはUsersテーブル上にありますが、属性は別のテーブルで管理されています。
※2018年1月10日修正：メールアドレスも$ui->getUserEmail()のように、UserInfoクラスから取得します。以前のコードは間違っていました。すいません。

### ユーザー属性をデータに含むJavaScript(jQuery)を生成する
以下のようなコードを出力します。

    var option1 = '<?php echo h($ui->getAttribute($option1j)); ?>';
    $('<?php echo h($option1m);?>').val(option1);

option1jやoption1mは、管理者が管理画面から入力するデータです。concrete5は管理者権限があると、管理画面でトラッキングコードなどJavaScriptを書き込みできるので、それと同等のセキュリティ水準を想定して作成しています。管理画面の説明は後述します。

なおデータを入力する時には以下のようなバリデーションを行っています。

        $allowed_string_attr = 'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-_[]';
        if (strlen($item) === strspn($item,$allowed_string_attr) ) {
            return true;
        } else {
            return false;
        }

### ページ読み込み時に、JavaScript(jQuery)を実行して、フォームに挿入する
実際に出力されるコードは、

    $(document).ready(function (e) {
        var option1 = 'レスキューワーク株式会社';
        $('#companyname').val(option1);
    });

のようになります。フォームの項目で id="companyname" があれば、その値に、レスキューワーク株式会社 が自動挿入されます。

## 管理画面で設定する
『どの項目にどのユーザー属性を挿入するか』を管理画面から設定できます。設定画面は、下の画像のようになっています。

![my_mitsu_autofill.png](https://qiita-image-store.s3.amazonaws.com/0/31643/2f50b388-5dfe-e95b-91c4-acf5c84060dc.png)

NAME(アカウント名)、EMAIL(メールアドレス)は、concrete5 のユーザーは必ず持っている情報です。この2つは、出力先のフォーム項目を指定するだけで設定完了です。

その他の項目は、出力先のフォーム項目と、ユーザー属性のハンドル名とを組にして設定します。
画像の例では、ユーザー属性yourcompanyの値を、id="companyname"のフォーム項目に関連付ける設定をしています。

全体のコードは、https://github.com/ounziw/my_mitsu_autofill で公開しています。

## 採用例
このアドオンは、[イベント協賛の見積例](https://my-mitsu.com/sample/event)や[セミナー講師向けホームページ作成](https://www.seminar-portal.org/services/homepage) で採用しています。この他、自動見積フォーム「マイ見積」オンプレミスプランで、ログインしたユーザーが見積書を作成する場合は、本アドオンを用いて、ユーザー情報を自動挿入しています。

## 注意点
このアドオンには、以下のような注意点があります。

* JavaScriptが有効になっていることが前提
* 自動挿入された項目をユーザーが書き換え可能

元々このアドオンは、マイ見積用に作成しました。マイ見積では、JavaScriptで自動計算を行うため、JavaScriptでの自動挿入で問題無いのですが、他の案件では要件を満たさない可能性がありますのでご注意ください。
また、ユーザーの手間を省くのが主目的のため、自動挿入されたデータをユーザーが書き換えることを制限していません。ユーザーによる不正を防ぐ目的ではありませんので、ご注意ください。