タイトル通りです。
以下詳細です。

Wunderlistとは

WunderlistとはPC、スマホ問わず使用できるタスク管理アプリです。
お洒落なデザインと軽快な動作。機能面もタスクの共有、期限設定、リマインダー機能、担当者設定、サブタスクの設定などなど、痒いところに手が届くようになっており、ちょっとした買い物リストから簡単なプロジェクトのタスク管理にも使えてしまう超万能なタスク管理アプリです。

作成のきっかけ

家事をする人の全国共通な悩み、もちろん色んなものがあるかとは思いますが、
中でも誰もが一度は直面する悩み…それは「今夜の夕飯どうしよう」問題です。
かく言う我が家でも、妻からよく聞かれるリストBest5に入るのが「今日(明日)の晩御飯何食べたい?」です。
献立を考える側も「毎日献立を考えるのも大変だわ」って思っているし、
この質問に答える側も「毎日同じ質問をされて面倒だな…」と思っています。(少なくとも自分は)
というわけで、今回はWunderlistを使って、毎日献立を決めてくれるbotを作りたいと思います。

Wunderlist API

Wunderlistはアプリだけでもすごーく便利なのですが、
さらにWebAPIまで用意してくれています。
なんという至れり尽くせり…
もうここまでされると好きになっちゃいますね。
僕はWunderlistが大好きです。
皆Wunderlist使いましょう!(宣伝)

ちなみにWunderlist APIのドキュメントはこちら

設計てきなもの

Wunderlistはテーマ毎にタスクのリストが作成できます。
分かりやすくイメージ化すると下記の感じ。

  • 買い物リスト
    • トイレットペーパー
    • 醤油
    • 味噌
  • 勉強
    • 数学
    • 国語
    • 英語

なのでこれを利用して、
・夕飯献立
・過去の夕飯献立履歴
の二つのリストを作成します。

「夕飯献立」にはその名の通り、献立となるメニューを登録しておきます。
「過去の夕飯献立履歴」はリストを作成しておくだけで、基本的に触りません。

毎日決まった時刻になると、スクリプトが「夕飯献立」リストからメニューを一つ抽選し、
今日のメニューを選びます。
その際に何が今日のメニューなのか分かるように、選ばれたメニューにはスターをつけ、期限を今日に設定します。

メニューを選ぶ際、直近で作られたメニューがまた選ばれてしまうと
「おいおい、また肉じゃが?勘弁してくれよ…」な感じになってしまうので、
肉じゃがを愛してやまない人は除く
抽選から直近で選ばれたメニューは除かれます。
直近メニューの確認を行う為に、過去の献立履歴が必要となる為、「過去の夕飯献立履歴」なるリストを用意します。

「過去の夕飯献立履歴」に履歴が追加される条件は、「夕飯献立」リストにて、スクリプト実行時点で、
「完了」状態となっている「献立」を「過去の夕飯献立履歴」に追加します。

大まかな運用の流れ

  1. 本日の献立が選ばれる
  2. 「夕飯献立」リストで作った「献立」を「完了」状態にする
  3. 翌日、前日作った「献立」が履歴に入る
  4. 履歴を参照して、その日の「献立」が選ばれる
  5. 「完了」状態になった「献立」を「未完了」状態に戻る
  6. 「夕飯献立」リストで作った「献立」を「完了」状態にする
  7. 翌日、前日作った「献立」が履歴に入る

...以後繰り返し

気づいた人もいるかと思いますが、履歴に追加される「献立」は必ずしも、前日に抽選された「献立」ではないです。
あくまで「完了」状態にした「実際に作った献立」です。
また昨日作った献立は複数になる可能性もあります。
こうしたのは理由があって、「いつもより多く作っちゃった♪」とか
「せっかく選んでもらったけど、今日はこっちが食べたい!」な我儘な欲求に応える為です。
人間は気まぐれな生き物なのです。

実装

というわけで実装していきます。
実装に当たっては、僕はCakePHP3が得意(というか他にフレームワーク触ったことがない)なので、
CakeのShell機能を使って実装します。
作ったShellはCronで毎日実行することにします。

WunderlistAPIの認証

まずはAPIの認証から始めていきます。
認証方法については、こちらに記載してあります。
WunderlistはOAuth2を使用しているようです。
一般に公開するアプリであれば、ユーザー毎にOAuth認証してもらって、個々の情報にアクセスするわけですが、
今回は個人で使うだけなので、AccessTokenを返すサイトURLがありません。
よって、ここから取得できるClientIDとAccessTokenを直接リクエストヘッダーに仕込んで認証を行います。
ちなみにOAuth認証についてはこちらがすごく分かりやすいです。

認証情報の取得手順は、リンク先から

  1. 「CREATE APP」をクリックし、APP登録する。
  2. 「CREATE ACCESS TOKEN」をクリックし、AccessTokenを作る。
  3. 「CLIENT ID」と「Your access token for MyHomeDinnerSelectApp is:」以降のAccessTokenをメモる。

で完了です。
API叩く際はこの二つの情報を使っていきます。
APP登録の際に、URLに関しては入力必須となりますが、適当に入力してしまってもAPP登録はできます。

APIをどうやって叩くか

コマンドラインであれば、curlを叩けば済む話ですが、PHPでAPIを叩く際にどうするかというお話です。
調べてみるとPHP自体にもcurl関数というものが用意されていますし、file_get_contentsでもAPIが叩ける様子。
しかし、おおよそこういう一般的にやりたいことに関してはフレームワーク側で機能が用意されているはず。
Cakeのドキュメント探して、「おお、やっぱあるやないかーい」って感じで見つけたのが、HttpClient機能です。

use Cake\Http\Client;

$http = new Client();

// 単純な GET
$response = $http->get('http://example.com/test.html');

// クエリー文字列を使用した単純な GET
$response = $http->get('http://example.com/search', ['q' => 'widget']);

// クエリー文字列と追加ヘッダーを使用した単純な GET
$response = $http->get('http://example.com/search', ['q' => 'widget'], [
  'headers' => ['X-Requested-With' => 'XMLHttpRequest']
]);

おおー、すごく簡単に叩ける。素晴らしい!
さて今度はWunderlistAPIをどう叩くかですが、ドキュメントによると叩き方は下記のような感じらしいです。

As an example, in curl you can set the Authorization header like this:

curl -H "X-Access-Token: OAUTH-TOKEN" -H "X-Client-ID: CLIENT-ID" https://a.wunderlist.com/api/v1/user

上記はcurlを使用して、コマンドラインからAPIを叩いた例です。
よってこれをPHPのプログラム上から叩いてやります。

今回利用するAPIはほぼ下記な感じで使用できました。

// 1. まずはHttpClientを使えるようにuseする
use Cake\Http\Client;

// 2. HTTPClientの用意。newする際、認証に必要な情報をheaderにセット
$httpClient = new Client([
    'headers' => [
        'X-Client-ID' => CLIENT_ID,
        'X-Access-Token' => ACCESS_TOKEN,
    ]
]);

// 3. あとは欲しい情報のURLに調整して、リクエスストBodyをセットし、GET/POST/PATCHを使い分ける。下記はGETの例
$response = $httpClient->get(
    URL.'tasks',
    ['list_id' => $listId, 'completed' => $completed]
);

// 4. 返ってきたレスポンスのコードで正常なら結果をreturn
if ($response->isOk()) {
    $taskList = $response->json ?? [];
    return $taskList;
}

処理の流れ

「設計てきなもの」で書いた流れを実現する為に下記のように処理を実装しました。

  1. まずは「夕飯献立」リストから「完了」状態の献立を取得
  2. 1で取得した献立の状態を「未完了」&「スター無し」&「期限無し」に戻す
  3. 1で取得した献立を「夕飯献立履歴」リストに追加する
  4. 「夕飯献立履歴」リストを取得する
  5. 「夕飯献立履歴」リストから直近の数件を取り出す
  6. 「夕飯献立」リストから「未完了」状態の献立を取得する
  7. 6で取得したリストから5で取得したものを取り除き、そこから本日の献立を抽選する
  8. 7で抽選して決定した「本日の献立」に「スター&コメント&期限」をつける
  9. 「本日の献立」をリストの一番上に移動する

実際のコードに関しては、ここに記載すると長くなるので、下で貼っておきます。
気になる方ご覧頂ければと思います。

Cronへの登録

作ったスクリプトは何かしらの方法で毎日実行してやります。
方法は前述した通りCronを使います。
Cronについて分からない方はググってみてください。
スクリプトをサーバー上に設置して、crontab -eして下記を登録します。
今回は毎日06:00に処理を実行してくれるに設定しました。

00 06 * * * /var/www/html/my_app/bin/cake [shell名]

完成形

下記はスクリプトを手動実行した際のサンプル動画です。

WunderlistDinnerBot.gif

ソース

以下ソース。
気軽にアドバイス等頂ければと思います。
https://gist.github.com/trewa-nek9585/1cd7fb893796fb24fb02ce6ba54e2ca4#file-php

以上です。閲覧ありがとうございました。

Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.