今年のQiita Advent Calendarに投稿予定です(CakePHPとDjango)。
いずれも12/20ですので、興味があればご覧ください。

CakePHP Django

さて、今回はCakePHPに関する記事です。
結論から言うと、PRがマージされましたというお話です。

背景

私は自作アプリのログイン・ログアウトにGoの外部API(これも自作したやつです)を使っており、 それぞれ以下のように処理しています。

ログイン

  1. アプリ:ユーザ・パスワードで認証APIをコール(POSTメソッド)
  2. API:処理成功時、ステータスコード200とアクセストークン返却
  3. アプリ:アクセストークンを利用してユーザ取得APIをコール(GETメソッド)
  4. API:処理成功時、ステータスコード200とユーザ情報を返却
  5. アプリ:取得したユーザ情報をセッションに格納してログイン成功

ログアウト

  1. アプリ:アクセストークンを利用して認証解除APIをコール(DELETEメソッド)
  2. API:処理成功時、ステータスコード204を返却

ある時、CakePHP3を使ったアプリで、正常にログアウトした場合でもエラーログが出ていることに気づきました。

2017-11-23 20:31:41 Error:

「エラーのくせに詳細が何も出力されないだと…」

という衝撃を隠しきれませんでしたが(笑)、一旦落ち着いて発生箇所を調査することに。

原因

use Cake\Http\Client;

public function logout($data, $headers, $assoc)
{
    // 外部APIをコールして、認証解除を実施する
    $http = new Client();
    $response = $http->delete('http://api.example.com/logout', $data, $headers);
    $body = $response->getBody();

    // 処理成功時は 204 がセットされる
    $this->response = $this->response->withStatus($response->getStatusCode());

    // \Cake\Http\Client\Messsage には`200`~`202`の定義しかないため、
    // \Cake\Http\Client\Responseのこのメソッドは`204`をOKとしていない
    if ($response->isOk()) {
        return json_decode($body, $assoc);
    }

    // 失敗
    Log::error($body);
}

コメントに書いた通りなのですが、上記コードをもとに説明します。

  • ログアウト時の処理2でステータスコード204が返ってくる
  • isOk()の対象でないためif文に入らない
  • レスポンスボディもないため、CakePHP側16行目Log::error()で出力する$bodyも空

という流れで、何も情報が無いエラーログが出力されてしまっていたということです。
これだけなら「あえて204をOKしてないのかな」とも思えたのですが。

// IntegrationTestCase.php
public function assertResponseOk($message = null)
{
    if (empty($message)) {
        $message = 'Status code is not between 200 and 204';
    }
    $this->_assertStatus(200, 204, $message); // 200 ~ 204 までOKとみなす
}

CakePHP3側の基底テストケースではまさかのOK対象内。

修正~PR

CakePHP側のコード修正・テストコードの修正および実施を行い、 それらのPRを出したところ、5時間ほどで無事マージされました。

ドキュメントは以前PRがマージされたのですが、コード側は初めてです。
「PRは内容に問題なければサクッとマージしてもらえるんだな」ということがわかりました。

とはいえ、IssueやPR作成時の説明にもあるように、注意する点もいくつかありますので、詳細は以下をご覧ください。
CakePHP コミュニティセンター

それでは、良いCakePHPライフを。