Chronosを1.2へバージョンアップしよう

標準

composer require cakephp/chronos:^1.2
  • setTestNow()メソッドがクラスを横断して時刻セットできるようなった!

CakePHP 3.2以降、時刻操作クラスとして cakephp/chronos が採用されています。
CakePHP内ではChronosを継承した \Cake\I18n\FrozenTime, \Cake\I18n\Time, \Cake\I18n\FrozenDate, \Cake\I18n\Date を使用でき、データベースの時刻系のフィールドはこれらのクラスへマッピングされます。

また、Chronosにはテストを容易にするためにsetTestNow()というメソッドがあり、各クラスの現在時刻を指定の時間へ固定することができます。

use \Cake\I18n\FrozenTime;
FrozenTime::setTestNow('1975-08-08 11:22:33');
$time = new FrozenTime('1 hour ago'); // 1975-08-08 12:22:33
$now = FrozenTime::now();
FrozenTime::setTestNow($now);
sleep(10); // 10秒待つ
$currentTime = FrozenTime::now(); // 固定されているので $currentTime == $now

Chronos 1.1 までの問題

しかし、Chronos 1.1 までは、setTestNow()は各クラスごとにセットしなければなりませんでした。
以下のようにFrozenTime::setTestNowTimeクラスへ影響しません。

use \Cake\I18n\FrozenTime;
use \Cake\I18n\Time;
FrozenTime::setTestNow('1975-08-08 11:22:33');
$time = new FrozenTime('1 hour ago'); // 1975-08-08 12:22:33
$time = new Time('1 hour ago'); // 現在時刻の1時間後

CakePHP 3.2以降のデフォルトでは、時刻系のフィールドは FrozenTime で処理されるようになっています。
通常は FrozenTime::setTestNow で時刻セットを行えばよいのですが、1ヶ所だけ Time が使われる部分があります。

TimestampBehavior の内部では、Timeが使用されています。ですので、テスト時に FrozenTime のみ時刻を固定した状態で created などの TimestampBehavior によりセットされる時刻フィールドをみると、固定した時刻ではなく実行時の時刻が入っていることになります。

これに対処するには、FrozenTime, Time の双方にテスト時刻をセットすればよいのですが、冗長な記述となっていました。

Chronos 1.2 ではこの問題が改善された

Chronos 1.2以降、setTestNowでの設定はすべてのChronosのサブクラスへ伝播するようになりました。

use \Cake\I18n\FrozenTime;
use \Cake\I18n\Time;
FrozenTime::setTestNow('1975-08-08 11:22:33');
$time = new FrozenTime('1 hour ago'); // 1975-08-08 12:22:33
$time = new Time('1 hour ago'); // 1975-08-08 12:22:33

これにより、各時刻クラスへのsetTestNowの漏れがなくなり重複した記述を減らせるので、今すぐChronos 1.2以降へバージョンアップすることをお勧めします。

コメントを残す

Page optimized by WP Minify WordPress Plugin