2014-08-10

Laravelのキャッシュが消えない!

こんにちは。
ちょうど今、珍しく私の住んでいる地域に台風が直撃しているようです。
みなさんもくれぐれもお気をつけ下さいね。

さてさて、今回は数日前にリニューアル公開したインフォブログランキングの作業中に起こった「Laravelのキャッシュが消えない現象」についてご紹介しようと思います。

(はい。最近Laravel漬けになっています。知れば知るほど「すごいなー」とつぶやいています^^)





[最終結論: バグではないけど、別の仕様を追加してほしい]


まず、私に起こった問題は以下のようなものでした。


日付が変わると新しいデータをDBから取得して、それをまたキャッシュとして保存する。

↓↓↓

でもキャッシュが削除されず同じデータのまま。


つまり、その日ごとにデータを表示したかったのでその都度DBにアクセスをせずキャッシュを利用した、ということです。

実際のプログラムは以下。

if(Cache::has('key')) {

    return Cache::get('key');

}

// DBからデータを取得

$dt = Carbon::tomorrow();    // 明日の日付を取得
Cache::put('key', $value, $dt);
return $value;


前回紹介したCarbonを使っています。
※現在はより便利なCache::remember() を使っています。


一見問題なさそうなのですが、、、?
実はこれではキャッシュが消えなくなる(可能性を持っている)のです。


なぜなら、元々Laravelのキャッシュの有効期限はタイムスタンプではなく、「分」を使っているから

なのです。

つまり、上の例でいうと、

1.Laravelは、$dt を使って明日が始まる時間まで何分かを取得。
2.その分数を有効期限とするキャッシュを作成

???

やっぱり問題ないのでは、、、?

これが大有りなんです。


なぜなら、Carbon(dateTime)から分を取得するとき intval() で数字が切り下げになってしまう

のです。

そう!
つまり、キャッシュはまだ日付が変わっていないのに有効期限が切れて削除され、そしてその当日のデータ(すでに保存されているものと同じデータ)をまた新しく保存してしまうというものです。

インフォブログランキングは手前味噌ですが、なかなかページビューが多いサイトなのでこの僅かな時間に新しいアクセスがあり、キャッシュがうまく更新されていないという状況でした。


???

でも、新しいキャッシュができたとしてもまた、明日までの有効期限だからすぐに新しいデータに置き換わるのでは???


実は、これもそうでもないんです。

結論からいうと、

分数がゼロの時はキャッシュは永遠に保存されてしまう

からなのです。
つまり、分がintval()で切り下げられてキャッシュを保存し、そのキャッシュが削除ときには残り時間は予定の時間まで1分未満になります。

その1分未満はintval() でゼロに変換されてキャッシュが消えない状態になってしまうということですね。

ということで、インフォブログランキングをよろしく Laravelでキャッシュを使用する時にはお気をつけ下さい。^-^

※おそらく間違いはないと思っていますが、自信がない部分もありますのでこの記事に修正が必要でしたらぜひ教えてください。よろしくお願いいたします。m_ _m

ではでは〜。




2014-08-07

PHPで日付を扱うなら Carbonライブラリが便利すぎる!!

個人的にまた災難が起こってしまった後、はじめての投稿になります。
みなさんもお体にはくれぐれもお気をつけ下さい(汗)

さて、今回はPHPの日付に関する記事になります。
というのも、最近ハマっているPHPフレームワーク「Laravel 4」には Carbonが標準搭載されているようで、これを使ったらもう昔には戻れない!と思ったのでぜひ紹介&備忘録としてその使い方を公開したいと思います。




[最終結論] 直感的に使えるのでとても便利です!なんならLaravel以外での開発でも使っていこうと思いました。


では、使い方に行く前に注意点を少し。
Laravel での使用を想定しているので、基本的に static な使い方で書いてます。
必要に応じて new Carbon(); してインスタンスを作ってくださいね。
あと、PHPは5.3以上必要です。

また、よく使うだろうというものだけで、全てのメソッドは網羅していません。詳しくはCarbon(英語) を確認してください。


1.基本的な使い方。


・今の時間は?

 Carbon::now();

・今日が始まる時間を知りたい

 Carbon::today(); // (例)2014-08-07 00:00:00

・じゃあ、昨日は?

 Carbon::yesterday(); // (例)2014-08-06 00:00:00

・明日も教えて。

 Carbon::tomorrow(); // (例) 2014-08-08 00:00:00

・タイムスタンプがほしいんだけど?

 Carbon::today()->timestamp; // (例) 1407337200



2.足したり引いたりする使い方。


・今からちょうど一日後/前の時間は?

 Carbon::now()->addDay();
 Carbon::now()->subDay();

・3日後/前

 Carbon::now()->addDays(3);
 Carbon::now()->subDays(3);

 ※その他にも

 秒: second(s)
 分: minute(s)
 時間: hour(s)
 年: year(s)
 月: month(s)

 でも同様のメソッドが用意されています。

 例) addSecond(), subYears(5)


3.文字列から指定する使い方。

・次の水曜日は?
 
 new Carbon('next wednesday');

・今週の木曜日は?

 new Carbon('this thursday');

 ※この辺は英語の知識が必要になりますね。昔学校で習ったはずですが、、、(笑)


4.各種データを取得する使いかた。

 $dt = Carbon::now();
   
 $dt->year;
 $dt->month;
 $dt->day;
 $dt->hour;
 $dt->minute;
 $dt->second;
 $dt->daysInMonth;

 ※いつものごとく、月($dt->month)の数字はゼロから始まるので+1が現在の月のようです。
 ※逆に上記に数字を代入することで時間をセットすることもできるようです。便利!


5.多分必要になった時にとても感謝するだろう使い方。


・年齢

 Carbon::createFromDate(1980, 1, 1)->age;

・週末?

 if (Carbon::now()->isWeekend()) {

  echo 'パーティ!'; // 本家のサンプルにこう有ります(笑)

 }

・もう過ぎた?まだ?

 $dt = Carbon::now()->subDay();
 
 if ($dt->isPast()) {

  echo 'もう過ぎた!';

 }


 $dt = Carbon::now()->addDay();
 
 if ($dt->isFuture()) {

  echo 'まだ!';

 }

・タイムゾーンが知りたい

 Carbon::now()->timezoneName;


6.アロー演算子「->」の使い方。

 $dt = Carbon::now();
   
 echo $dt->year(1975)
     ->month(5)
     ->day(21)
     ->hour(22)
     ->minute(32)
     ->second(5);

 ※Laravelのように一気にかけるのはコードがスッキリして好きです。^^


と、ざっとこんな感じですね。
あとは日付の比較やBetween を使った便利なものもありますが、すこし複雑になるので気になった方は本家のCarbonのGitHubページをご覧ください。

それにしても技術は確実に進歩していっています。
より簡単に高度なプログラムが、しかも直感的に使えるようになってきていますね。

なお、Carbon はMITライセンスなので、開発者にはホントにありがたいです。
Brian Nesbittさん、ありがとうございます。


ということで以上です。
お疲れ様でした!