CakePHP3を触ってみました 〜あれ、updatedは?〜

この記事はだいぶ前に書かれたものなので情報が古いかもしれません
腕時計はしないけど懐中時計は持ってたい派

この記事を三行にまとめると

次回辺り、どうでもいい記事を一度挟んどくか……
createする者と言えば創造主……つまり神だ!
createdとmodifiedの機能を逆にしておくことだってできちゃう
どもども、最近CakePHP3のことばっかり書いてるわたくしです。

あまり開発技術の記事ばかり続くのは嫌なんですけどね……だって、まるで俺が普段真面目にエンジニアとして活動しているみたいに誤解されちゃうじゃないか!

次回辺り、どうでもいい記事を一度挟んどくか……。



まあそれはさておき、えーと、今日はcreatedとmodifiedに関する話っす。

バージョン3に限らず、CakePHPを使っている人は、createdとかmodifiedっていうカラムをテーブルに作る機会があると思います。datetime型(date型でも良いんだっけ?)にしておくと、データをINSERTしたりUPDATEするときに、自動的に時間を入れてくれるので、まあ使い勝手は良いと思います。

でもこのcreatedやmodified、CakePHP3では、デフォルトでは自動で時間を入れてくれなくなりました。今までと同じようにsave()メソッドを使ってデータを入力してみると、時間が入ってないのが分かります。

boforeSave()で時間を入力する処理を自分で実装しても良いんでしょうが、自動入力を設定できる方法はあるから、せっかくなんでそれやってみましょう。



Behaviorを使う

やり方は簡単です。

CakePHP3にはTimestampというBehaviorが用意されているので、それを読み込んでおくだけです。

class AppTable extends Table {
  public function initialize(array $config) {
    $this->addBehavior('Timestamp');
  }
}

これだけです。createdやmodifiedに時間を入れたい各テーブルにこれを書けば、今までのように自動で時間が入力されるようになります。

全体的に共通化しておきたいなら、AppTableとか作って、そこに書いとけば良いと思います。

Behaviorの読み込み方も、CakePHP2の頃とはちょっと書き方が変わりましたかね。昔は、$actAsっていうメンバ変数で読み込んでました。

public AppModel extends Model {
  public $actAs = array('TimeStamp');
}

こんな感じで。まあでも、そんなややこしい仕様変更ではないと思うので、大丈夫だと思います。



設定をいじってみる

今までは、テーブルにcreatedやmodifiedがあれば、INSERTやUPDATEに応じて勝手に時間を対応するカラムに入れてくれていました。

createdは新規にレコードを入力するとき、modifiedは新規のときと更新のときに、時間がセットされる。自分でsave()メソッドをカスタマイズとかしない限りは、こういう風に挙動が決まっていましたね。

今回はその辺をBehaviorの設定で柔軟に変更することができるようです。

$this->addBehavior('Timestamp', [
  'events' => [
    'Model.beforeSave' => [
      'created' => 'new',
      'modified' => 'always'
    ]
  ]
]);

これがデフォルトの設定です。これだと今までと同じで、新規時はcreatedが、新規と更新時はmodifiedが更新されます。

じゃあ例えば、新規のときはcreatedだけに時間をセットし、modifiedは更新のときだけセットされるようにしたければ……。

$this->addBehavior('Timestamp', [
  'events' => [
    'Model.beforeSave' => [
      'created' => 'new',
      'modified' => 'existing'
    ]
  ]
]);

こうするとmodifiedの方は、INSERT文のときは時間が自動では入らなくなります。

TimeStampのBehaviorを見る限り、設定できる項目は「new」「existing」「always」の三つがあるようで、newは新規のときだけ、逆にexistingは更新のときだけ、そしてalwaysは新規のときも更新のときも常に時間が入るみたいです。

つまりcreatedもmodifiedも新規のときだけ時間が入るようにしたければ、両方ともnewにすれば良いってことですね。

$this->addBehavior('Timestamp', [
  'events' => [
    'Model.beforeSave' => [
      'created' => 'new',
      'modified' => 'new'
    ]
  ]
]);

まあ、こんなことをする意味はないでしょうが。



あれ、updatedは?

CakePHP2の頃は、更新用のカラムはmodifiedだけじゃなく、updatedというフィールド名でもオッケーでした。どっちかのカラムがあれば、Cakeさんが時間を入れてくれていた。

でも今回は、ただTimestampBehaviorを読み込んだだけだと、updatedでは機能してくれません。modifiedじゃないとダメ。

じゃあ、もしupdatedっていうカラムで更新時間を管理したい場合はどうするか。

$this->addBehavior('Timestamp', [
  'events' => [
    'Model.beforeSave' => [
      'created' => 'new',
      'updated' => 'always'
    ]
  ]
]);

こうです。早い話が、今回はcreatedやmodifiedに対応するカラム名を、自分で好きなように変更できるってことですね。便利なようなそうじゃないような……まあ、柔軟ではあるのかな。

全然何の脈絡もないカラムにすることだってできる。createする者と言えば創造主……つまり神だ!とか思うなら、カラム名をgodとかにすれば良いんじゃない? そんでもって、modifiedの方はgodを逆から読んでdogにしよう!とか思うなら、やってみても良いんじゃね?

$this->addBehavior('Timestamp', [
  'events' => [
    'Model.beforeSave' => [
      'god' => 'new',
      'dog' => 'always'
    ]
  ]
]);

同じプロジェクトの開発メンバーを撹乱するために、createdとmodifiedの機能を逆にしておくことだってできちゃう。

$this->addBehavior('Timestamp', [
  'events' => [
    'Model.beforeSave' => [
      'created' => 'always',
      'modified' => 'new'
    ]
  ]
]);



ちょいおまけ

CakePHP3では、date型やdatetime型のデータは、オブジェクトで返ってくるようになりました。

//CakePHP2
array(
  [created] => 2015-11-14 14:14:14
)

//CakePHP3
array(
  [created] => Cake\I18n\Time Object
    (
      [date] => 2015-11-14 14:14:14.000000
      [timezone_type] => 3
      [timezone] => Asia/Tokyo
    )
)

こんな感じです。まあ普通に「echo $data->created」で表示することはできるのですが、「date(‘Y-m-d’, $data->created)」みたいなことはできません。エラーになります。

その代わり、CakePHP3には「format()」というメソッドがあるみたいで、それを使えば、date()を使うのと同じことが実現できます。

//echo date('Y年m月d日', $timestamp)と同じ
echo $data->created->format('Y年m月d日');

些細な点ですが、いちいちdate()メソッドを使わなくて良いのは、ちょい便利かもですね。






今回はcreatedやmodified、datetime型に関するお話でした。

どうして自動入力のためにBehaviorを読み込むような仕様になったかは分かりませんが、まあ、カスタマイズがし易くなってるってのは、良いことなのでしょう。

createdとかmodified程度なら、そんな柔軟に開発できなくても、あまり問題なさそうだけど……。



その他のCakePHP3を触ってみましたの記事はこちら
まとめという名の箸休め
 もしかしたら何か関連しているかも? 
 質問や感想などお気軽にコメントしてください