concrete5で、ログインユーザーがファイルをダウンロードすると、メールやChatworkで連絡が届く仕組み

ログインユーザーがファイルダウンロードするとお知らせが届いて、そのユーザーさんにアプローチを取るためにこんな仕組みを作ってみました。

## concrete5にはHook(フック)があるよ！

concrete5には、WordPressのフィルターフックのように、何かのタイミングで発火するHookがあります。

* 【参考】[Hooking into Application Events](https://documentation.concrete5.org/developers/framework/application-events/hooking-application-events)

このフックの中に`on_file_download`というイベントフックがあります。

* 【参考】[Full Event List](https://documentation.concrete5.org/developers/framework/application-events/full-event-list)

つまり、ファイルがダウンロードされたら実行されるフックが用意されているわけです。

## フックの書き方

concrete5には、ルートに`application`というディレクトリが標準で用意されています。何かカスタマイズする時は、このディレクトリにファイルを作成してコードを書きます。コアのオーバーライドもここで行います。

`application`配下には、`/application/bootstrap/app.php`というファイルが用意されています。WordPressでいうところの、functions.phpに近いファイルです。

アプリケーションレベルで機能を追加したい場合に、その処理を書くところで、ちょっとしたカスタマイズをぺろっと書くのに丁度良い仕組みです。

今回は、パッケージ化などはせず、この`/application/bootstarp.app.php`にカスタマイズを書きたいと思います。

```/application/bootstrap/app.php
\Events::addListener('on_file_download', function() {
  \Log::info('ファイルがダウンロードされました！');
}
```

こう書くと、concrete5のログに「ファイルがダウンロードされました！」と記録されます。（ちなみに、concrete5のログの確認の仕方は、管理画面→レポート→ログ、で確認できます。）

まあ、ただし、これだけではどこの誰が何のファイルをダウンロードしたのか分かりませんし、メールも送信されません。

## concrete5にログインしているユーザーの情報を取得する

```/application/bootstrap/app.php
$u = new User();
```

ユーザー情報の取得は、上記の通りです。ここから発展させて…


```/application/bootstrap/app.php
$u = new User();

$ui = \UserInfo::getByID($u->getUserID());
$name = $ui->getAttribute('user_name'); // user_nameというハンドルの属性が作られている前提ですが、名前を取得します。
$email = $ui->getUserEmail(); // ユーザーのメールアドレスを取得します。
$company = $ui->getAttribute('user_company'); // user_companyというハンドルの属性が作られている前提ですが、ユーザーの企業名を取得します。
$phone = $ui->getAttribute('user_phone'); // user_phoneというハンドルの属性が作られている前提ですが、ユーザーの電話番号を取得します。
```
こういった感じで、ユーザーオブジェクトから、ユーザーの情報を取り出しておきます。

## concrete5でメールの送信は、メールヘルパーを使う

PHPでメール送信と言うと、`mb_send_mail()`とかを連想する方も多いと思いますが、メールヘッダの処理とか結構めんどくさいですよね。

concrete5は、多言語で運用する前提のCMSなので、その辺まるっといい感じに処理してくれるメールヘルパーというものが用意されています。

```/application/bootstrap/app.php
$mh = \Core::make('mail'); // メールヘルパーの呼び出し
$mh->setTesting(false); // メール送信のログを残すかどうか。trueで残さないようになる。
```

メールヘルパーの呼び出しはこんな感じです。

実際に、メールを送信する処理を書いていきます。

```/application/bootstrap/app.php
// メール本文を定義。PHPでメールを送るときによくある感じですね。
$mail_body = '関係者各位';
$mail_body .= $name . '様がファイルをダウンロードしました。';
$mail_body .= "\n";
$mail_body .= '----------------------------------------';
$mail_body .= "\n";
$mail_body .= '【お名前】' . $name;
$mail_body .= "\n";
$mail_body .= '【企業団体名】' . $company;
$mail_body .= "\n";
$mail_body .= '【E-mail】' . $email;
$mail_body .= "\n";
$mail_body .= '【電話番号】' . $phone;
$mail_body .= "\n";
$mail_body .= '【ファイル取得日時】' . date("Y年m月j日 H:i:s");
$mail_body .= "\n";
$mail_body .= '----------------------------------------';
$mail_body .= "\n";

$mh->setBody($mail_body); // 定義したメール本文を、ヘルパーを使ってセットします。

$mh->from('noreply@example.com', '株式会社サンプル（送信専用）'); // 差出人情報をセットします。

$mh->to('me@example.com'); // メールの送信先を設定します。カンマ区切りで複数設定も可
// $mh->cc('hoge@example.com'); // ←CCの場合
// $mh->bcc('hoge@example.com'); // ←BCCの場合

$mh->sendMail(); // メールを送信！
```

こんな感じ。ほら、簡単ですよね。

## ダウンロードされたファイル名も教えて欲しい…

上記ソースコードだと、どこの誰がいつダウンロードしたかまでしか分かりません。

ファイルを複数ダウンロードできるようにしている場合、どのファイルをダウンロードしたかも知りたいですよね。

```/application/bootstrap/app.php
\Events::addListener('on_file_download', function($event) {

  $file_name = $event->getFileVersionObject()->getTitle(); // ファイルネーム取得

}
```
簡単ですね。

## Chatworkにも飛ばしたい！

Chatworkに送信するには、こちらの記事を参考にしました。

* 【参考】[PHPからchatwork API v2を叩くサンプル](https://qiita.com/masato1230/items/236be41d611001ca538c)

SDKもあるようですが、単にPOSTするだけなので、そこまでは良いかな、と…

結果、こういうソースコードでChatworkにPOSTできるようです。

>
```/application/bootstrap/app.php
$chatToken = '{chatwork apiのトークン}';
$chatGroupId = '{投稿したいグループのID}';
$message = "This is test.\nMy name is test.";
>
$headers = [
    'X-ChatWorkToken: '.$chatToken
];
>
$option = [
    'body' => $message
];
>
$ch = curl_init( 'https://api.chatwork.com/v2/rooms/'.$chatGroupId.'/messages' );
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($option));
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
>
$response = curl_exec($ch);
curl_close($ch);
```

なるほどですね。

## 全部まとめて、こんなコードになりました。
最終的にMixed-UPされたコードです。

```/application/bootstarp/app.php

// ChatworkのAPIトークンと、Chatworkに飛ばしたいRoomIDを定数化
define('CW_TOKEN', 'xxxxxxxxxxxxxxxxxxxxxxxxxxx');
define('RID', '1234567890');

// ChatworkへのPOSTを関数化
function cw_post($payload, $cw_token, $rid) {
  
  // Chatwork initialize
  $headers = [
    'X-ChatWorkToken: '.$cw_token
  ];

  $option = [
    'body' => $payload
  ];

  $ch = curl_init( 'https://api.chatwork.com/v2/rooms/'.$rid.'/messages' );
  curl_setopt($ch, CURLOPT_POST, true);
  curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($option));
  curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

  $response = curl_exec($ch);
  \Log::info($response);
  curl_close($ch);
}

// ファイルダウンロードのイベントフック
\Events::addListener('on_file_download', function($event) {
  // ユーザー情報の取得
  $u = new User();
  $ug = $u->getUserGroups(); //ユーザーが所属しているユーザーグループの取得

  if(in_array('4', $ug)) { // 特定のユーザーグループに所属しているユーザーのみ、ダウンロード通知が発生してほしい。今回はユーザーグループIDが4の場合。

    $ui = \UserInfo::getByID($u->getUserID());
    $name = $ui->getAttribute('user_name');
    $furigana = $ui->getAttribute('user_furigana');
    $company = $ui->getAttribute('user_company');
    $email = $ui->getUserEmail();
    $phone = $ui->getAttribute('user_phone');
    $sex = $ui->getAttribute('user_sex');
    
    $file_name = $event->getFileVersionObject()->getTitle();

    $date = date("Y年m月j日 H:i:s"); // ダウンロード時刻を取得

    // メールヘルパー呼び出し
    $mh = Core::make('mail');
    $mh->setTesting(false);
    
    // メール本文
    $mt = '関係者各位';
    $mt .= "\n\n";
    $mt .= $name . '様が「' . $file_name . '」をダウンロードしました。';
    $mt .= "\n";
    $mt .= '----------------------------------------';
    $mt .= "\n";
    $mt .= '【お名前】' . $name;
    $mt .= "\n";
    $mt .= '【企業団体名】' . $company;
    $mt .= "\n";
    $mt .= '【E-mail】' . $email;
    $mt .= "\n";
    $mt .= '【電話番号】' . $phone;
    $mt .= "\n";
    $mt .= '【性別】' . $sex;
    $mt .= "\n";
    $mt .= '【ファイル取得日時】' . $date;
    $mt .= "\n";
    $mt .= '----------------------------------------';
    $mt .= "\n";

    $mh->setBody($mt);

    // メールの題名を設定
    $mh->setSubject($name . '（' . $company . '）様が、' . $file_name . 'をダウンロードしました');
      
    // メールの差出人情報を設定
    $mh->from('noreply@example.com', '株式会社サンプル（送信専用）');

    // メールの送信先を設定
    $mh->to('me@example.com');
    
    // メールを送信！
    $mh->sendMail();
　　 
    // チャットワークへ送信。内容はメール本文と同じ
    cw_post($mt, CW_TOKEN, RID);
    
    // 念のため、concrete5のログにも記録を残しておく
    if($u->getUserID() !== NULL) { // ログインユーザーの場合のみ記録
      \Log::info($name . 'さん（【企業団体名】' . $company . ' 【e-mail】' . $email . ' 【TEL】' . $phone . '）が、「' . $file_name . '」をダウンロードしました。' );
    }
  }
});
```

以上、こういう感じです。

## 結果
👇メールの受信内容
![スクリーンショット 2020-12-13 23.50.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116223/3ea07070-0766-2296-8ecd-84f8ee3cb18a.png)

👇Chatworkのメッセージ内容
![スクリーンショット 2020-12-14 0.00.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116223/6a9d6246-4894-daad-58bc-96e5811aa700.png)

はい、うまく送信されましたね。

## 他にも 
ChatworkはAPIを使っているので、他のAPIが用意されているサービスであれば、他にもいろいろ送信先は考えられますね。

* Slack
* Microsoft Teams
* Google スプレッドシート
* kintone
* Backlog
* Trello

などなど。実際には、Googleスプレッドシートにも転記するようにしています。スプレッドシートにダウンロード履歴を蓄積することによって、履歴として追えるようにもしています。（Googleスプレッドシート との連携は結構めんどくさかったので、また機会があればご紹介します）

また、kintoneやBacklogにも通知すると面白いんじゃないでしょうか。kintoneであれば社内インフラ的に使っているところもあるでしょうし、営業さんとの連携もスムーズかと思います。Backlogの課題やTrelloのカードとして登録していき、登録された順番でコールしていくのも面白そうです。

## まとめ：concrete5にはHookがあって、Hookのタイミングでメール送信したりAPI連携したり、色々なことができるよ！

* concrete5にはHookがある
* Hookには、`on_file_download`というイベントがある
* Hookの発火タイミングでメールを送信するのはconcrete5だと、とっても簡単
* Chatwork APIもシンプルなので、チャットワークに通知するのも簡単
* Hookを使えば、いろいろな可能性が広がるね！

という記事でした。

諸氏のご参考になれば、幸いです。