設定
Laravelは読み書きしやすい、多くのキャッシュシステムに対する統一したAPIを提供します。キャッシュの設定は、config/cache.php
で指定します。アプリケーション全体のデフォルトとして使用するキャッシュドライバをこのファイルの中で指定します。MemcachedやRedisなど、人気のあるキャッシュシステムをLaravelは最初からサポートしています。
キャッシュ設定ファイルは、様々な他のオプションも含んでいます。コメントで説明してありますので、よく読んで確認してください。Laravelのデフォルトとして、file
キャッシュドライバが設定されています。ファイルシステムへオブジェクトをシリアライズして保存します。大きなアプリケーションではMemecachedやAPCのような、より堅牢なドライバを使うことをおすすめします。複数のドライバを使用するキャッシュ設定も可能です。
ドライバ事前要件
データベース
データベースをキャッシュドライバに使用する場合、キャッシュアイテムを構成するテーブルを用意する必要があります。このテーブルの「スキーマ」を定義するサンプルを見てください。
Schema::create('cache', function ($table) {
$table->string('key')->unique();
$table->text('value');
$table->integer('expiration');
});
Tip!! 正確なスキーマのマイグレーションを生成するために、
php artisan cache:table
Artisanコマンドを使用することもできます。
Memcached
Memcachedキャッシュを使用する場合は、Memcached
PECLパッケージをインストールする必要があります。全Memcachedサーバは、config/cache.php
設定ファイルにリストしてください。
'memcached' => [
[
'host' => '127.0.0.1',
'port' => 11211,
'weight' => 100
],
],
さらに、UNIXソケットパスへ、host
オプションを設定することもできます。これを行うにはport
オプションに0
を指定してください。
'memcached' => [
[
'host' => '/var/run/memcached/memcached.sock',
'port' => 0,
'weight' => 100
],
],
Redis
LaravelでRedisを使う前に、Composerでpredis/predis
パッケージ(~1.0)、もしくはPECLでPhpRedis
PHP拡張のどちらかをインストールしておく必要があります。
Redisの設定についての詳細は、Laravelドキュメントページを読んでください。
キャッシュの使用法
キャッシュインスタンスの取得
Illuminate\Contracts\Cache\Factory
とIlluminate\Contracts\Cache\Repository
契約は、Laravelのキャッシュサービスへのアクセスを提供します。Factory
契約は、アプリケーションで定義している全キャッシュドライバへのアクセスを提供します。Repository
契約は通常、cache
設定ファイルで指定している、アプリケーションのデフォルトキャッシュドライバの実装です。
しかし、このドキュメント全体で使用している、Cache
ファサードも利用できます。Cache
ファサードは裏で動作している、Laravelキャッシュ契約の実装への便利で簡潔なアクセスを提供しています。
<?php
namespace App\Http\Controllers;
use Illuminate\Support\Facades\Cache;
class UserController extends Controller
{
/**
* アプリケーションの全ユーザーリストの表示
*
* @return Response
*/
public function index()
{
$value = Cache::get('key');
//
}
}
複数のキャッシュ保存先へのアクセス
Cache
ファサードのstore
メソッドを使い、様々なキャッシュ保存域へアクセスできます。store
メソッドに渡すキーは、cache
設定ファイルのstores
設定配列にリストしている保存域の一つです。
$value = Cache::store('file')->get('foo');
Cache::store('redis')->put('bar', 'baz', 600); // 10 Minutes
キャッシュからアイテム取得
Cache
ファサードのget
メソッドは、キャッシュからアイテムを取得するために使用します。アイテムがキャッシュに存在していない場合は、null
が返されます。アイテムが存在していない時に返したい、カスタムデフォルト値をget
メソッドの第2引数として渡すこともできます。
$value = Cache::get('key');
$value = Cache::get('key', 'default');
デフォルト値として「クロージャ」を渡すこともできます。キャッシュに指定したアイテムが存在していない場合、「クロージャ」の結果が返されます。クロージャを渡すことで、データベースや外部サービスからデフォルト値を取得するのを遅らせることができます。
$value = Cache::get('key', function () {
return DB::table(...)->get();
});
アイテムの存在確認
has
メソッドで、キャッシュにアイテムが存在しているかを調べることができます。このメソッドは、値がnull
の場合、false
を返します。
if (Cache::has('key')) {
//
}
値の増減
increment
とdecrement
メソッドはキャッシュの整数アイテムの値を調整するために使用します。両方のメソッドともそのアイテムの値をどのくらい増減させるかの増分をオプションの第2引数に指定できます。
Cache::increment('key');
Cache::increment('key', $amount);
Cache::decrement('key');
Cache::decrement('key', $amount);
取得不可時更新
キャッシュからアイテムを取得しようとして、指定したアイテムが存在しない場合は、デフォルト値を保存したい場合もあるでしょう。たとえば、全ユーザーをキャッシュから取得しようとし、存在していない場合はデータベースから取得しキャッシュへ追加したい場合です。Cache::remember
メソッドを使用します。
$value = Cache::remember('users', $seconds, function () {
return DB::table('users')->get();
});
キャッシュに存在しない場合、remember
メソッドに渡された「クロージャ」が実行され、結果がキャッシュに保存されます。
rememberForever
メソッドでアイテムをキャッシュから取得するか、できない場合は永久に保存できます。
$value = Cache::rememberForever('users', function () {
return DB::table('users')->get();
});
取得後削除
キャッシュからアイテムを取得した後に削除したい場合は、pull
メソッドを使用します。get
メソッドと同様にキャッシュにアイテムが存在していない場合は、null
が返ります。
$value = Cache::pull('key');
キャッシュへアイテム保存
Cache
ファサードのput
メソッドにより、キャッシュにアイテムを保存できます。
Cache::put('key', 'value', $seconds);
put
メソッドに保存期間を渡さない場合、そのアイテムは無期限に保存されます。
Cache::put('key', 'value');
どのくらいでアイテムが無効になるかを秒数で指定する代わりに、キャッシュされたアイテムの有効期限を示すDateTime
インスタンスを渡すこともできます。
Cache::put('key', 'value', now()->addMinutes(10));
非存在時保存
add
メソッドはキャッシュに保存されていない場合のみ、そのアイテムを保存します。キャッシュに実際にアイテムが追加された場合はtrue
が返ってきます。そうでなければfalse
が返されます。
Cache::add('key', 'value', $seconds);
アイテムを永遠に保存
forever
メソッドはそのアイテムをキャッシュへ永遠に保存します。こうした値は有効期限が切れないため、forget
メソッドを使用し、削除する必要があります。
Cache::forever('key', 'value');
Tip!! Memcachedドライバーを使用する場合、キャッシュが最大値に達すると、"forever"を指定したアイテムも削除されます。
キャッシュからのアイテム削除
forget
メソッドでキャッシュからアイテムを削除します。
Cache::forget('key');
0か負数を指定し、アイテムを削除することもできます。
Cache::put('key', 'value', 0);
Cache::put('key', 'value', -5);
キャッシュ全体をクリアしたい場合はflush
メソッドを使います。
Cache::flush();
Note:
flush
メソッドは、キャッシュのプレフィックスを考慮せずに、キャッシュから全アイテムを削除します。他のアプリケーションと共有するキャッシュを削除するときは、利用を熟考してください。
アトミックロック
Note: この機能を利用するには、アプリケーションのデフォルトキャッシュドライバに、
memcached
かdynamodb
、redis
ドライバを使用する必要があります。さらに、全てのサーバが同じ中央キャッシュサーバに接続する必要があります。
アトミックロックにより競合状態を心配することなく、分散型のロック操作を実現できます。たとえば、Laravel
Forgeでは、一度に1つのリモートタスクを1つのサーバで実行するために、アトミックロックを使用しています。ロックを生成し、管理するにはCache::lock
メソッドを使用します。
use Illuminate\Support\Facades\Cache;
$lock = Cache::lock('foo', 10);
if ($lock->get()) {
// 10秒間ロックを獲得する
$lock->release();
}
get
メソッドは、クロージャも引数に取ります。クロージャ実行後、Laravelは自動的にロックを解除します。
Cache::lock('foo')->get(function () {
// 無期限のロックを獲得し、自動的に開放する
});
リクエスト時にロックが獲得できないときに、指定秒数待機するようにLaravelに指示できます。指定制限時間内にロックが獲得できなかった場合は、Illuminate\Contracts\Cache\LockTimeoutException
が投げられます。
use Illuminate\Contracts\Cache\LockTimeoutException;
$lock = Cache::lock('foo', 10);
try {
$lock->block(5);
// 最大5秒待機し、ロックを獲得
} catch (LockTimeoutException $e) {
// ロックを獲得できなかった
} finally {
optional($lock)->release();
}
Cache::lock('foo', 10)->block(5, function () {
// 最大5秒待機し、ロックを獲得
});
プロセス間のロック管理
あるプロセスでロックを獲得し、他のプロセスで開放したい場合もあります。たとえば、Webリクエストでロックを獲得し、そのリクエストから起動したキュー済みジョブの最後で、ロックを開放したい場合です。そのようなシナリオでは、ジョブで渡されたトークンを使い、ロックを再インスタンス化できるように、ロックを限定する「所有者(owner)のトークン」をキューするジョブへ渡す必要があります。
// コントローラ側
$podcast = Podcast::find($id);
$lock = Cache::lock('foo', 120);
if ($result = $lock->get()) {
ProcessPodcast::dispatch($podcast, $lock->owner());
}
// ProcessPodcastジョブ側
Cache::restoreLock('foo', $this->owner)->release();
現在の所有者にかかわらず、ロックを開放したい場合は、forceRelease
メソッドを使用します。
Cache::lock('foo')->forceRelease();
cacheヘルパ
Cache
ファサードとCache契約に付け加え、キャッシュからのデータ取得/保存を行う、グローバルcache
関数も使用できます。cache
関数を文字列引数一つで呼び出す場合、指定したキーの値を返します。
$value = cache('key');
キー/値ペアの配列と、有効期間を関数へ渡す場合、指定期間の間、値をキャッシュへ保存します。
cache(['key' => 'value'], $seconds);
cache(['key' => 'value'], now()->addMinutes(10));
cache
関数を引数なしで呼び出すと、Illuminate\Contracts\Cache\Factory
を実装したインスタンスが返ってきます。これを使い、他のキャッシュメソッドを呼び出せます。
cache()->remember('users', $seconds, function () {
return DB::table('users')->get();
});
グローバル
cache
関数への呼び出しをテストする場合、ファサードのテストと同様に、Cache::shouldReceive
メソッドを使います。
キャッシュタグ
Note:
file
とdatabase
キャッシュドライバ使用時、キャッシュタグはサポートされません。また、"forever"を使い、複数のタグをつけたキャッシュを使用する場合、古いレコードを自動的にパージするmemcached
のようなドライバがパフォーマンス的に最適です。
タグ付けキャッシュアイテムの保存
キャッシュタグにより、キャッシュ中の関連するアイテムへタグ付けできます。その後、指定したタグがつけられたキャッシュの値を全部削除できます。タグを順番に指定する配列を渡すことで、タグ付けしたキャッシュへアクセスできます。例としてタグ付けしたキャッシュにアクセスし、キャッシュへ値をput
してみましょう。
Cache::tags(['people', 'artists'])->put('John', $john, $seconds);
Cache::tags(['people', 'authors'])->put('Anne', $anne, $seconds);
タグ付けキャッシュアイテムへのアクセス
タグ付けしたキャッシュアイテムを取得するには、tags
メソッドに同じ順序でタグのリストを渡し、続けてget
メソッドで取得したいキーを指定します。
$john = Cache::tags(['people', 'artists'])->get('John');
$anne = Cache::tags(['people', 'authors'])->get('Anne');
タグ付けキャッシュアイテムの削除
タグ一つ、もしくはタグのリストに結びついた全アイテムを一度に消去することができます。たとえば、次の実行文はpeople
かauthors
のどちらか、または両方にタグ付けされたキャッシュを全部削除します。ですから、Anne
とJohn
は両方共キャッシュから削除されます。
Cache::tags(['people', 'authors'])->flush();
対照的に、次の実行分ではauthors
にタグ付けしたキャッシュのみ削除されますので、Anne
が削除され、John
は残ります。
Cache::tags('authors')->flush();
カスタムキャッシュドライバの追加
ドライバープログラミング
カスタムキャッシュドライバを作成するには、Illuminate\Contracts\Cache\Store
契約を最初に実装する必要があります。そのため、MongoDBキャッシュドライバは、以下のような実装になるでしょう。
<?php
namespace App\Extensions;
use Illuminate\Contracts\Cache\Store;
class MongoStore implements Store
{
public function get($key) {}
public function many(array $keys) {}
public function put($key, $value, $seconds) {}
public function putMany(array $values, $seconds) {}
public function increment($key, $value = 1) {}
public function decrement($key, $value = 1) {}
public function forever($key, $value) {}
public function forget($key) {}
public function flush() {}
public function getPrefix() {}
}
これらのメソッドをMongoDB接続を用い、実装するだけです。各メソッドをどのように実装するかの例は、フレームワークのIlluminate\Cache\MemcachedStore
のソースコードを参照してください。実装を完了したら、ドライバを登録します。
Cache::extend('mongo', function ($app) {
return Cache::repository(new MongoStore);
});
Tip!! カスタムキャッシュドライバーをどこに設置するか迷っているなら、
app
ディレクトリ下にExtensions
の名前空間で作成できます。しかし、Laravelはアプリケーション構造を強制していませんので、自分の好みに合わせてアプリケーションを自由に構築できることを忘れないでください。
ドライバ登録
Laravelにカスタムキャッシュドライバを登録するには、Cache
ファサードのextend
メソッドを使います。新しくインストールしたLaravelに含まれている、デフォルトのApp\Providers\AppServiceProvider
のboot
メソッドで、Cache::extend
を呼び出せます。もしくは、拡張を設置するために自身のサービスプロバイダを作成することもできます。config/app.php
プロバイダ配列に、そのプロバイダを登録し忘れないようにしてください。
<?php
namespace App\Providers;
use App\Extensions\MongoStore;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\ServiceProvider;
class CacheServiceProvider extends ServiceProvider
{
/**
* コンテナ結合の登録
*
* @return void
*/
public function register()
{
//
}
/**
* 全アプリケーションサービスの初期起動
*
* @return void
*/
public function boot()
{
Cache::extend('mongo', function ($app) {
return Cache::repository(new MongoStore);
});
}
}
extend
メソッドの最初の引数はドライバ名です。これはconfig/cache.php
設定ファイルの、driver
オプションと対応します。第2引数は、Illuminate\Cache\Repository
インスタンスを返すクロージャです。クロージャには、サービスコンテナインスタンスの$app
インスタンスが渡されます。
拡張を登録したら、config/cache.php
設定ファイルのdriver
オプションへ、拡張の名前を登録してください。
イベント
全キャッシュ操作に対してコードを実行するには、キャッシュが発行するイベントを購読する必要があります。通常、イベントリスナはEventServiceProvider
の中へ設置します。
/**
* アプリケーションのイベントリスナ
*
* @var array
*/
protected $listen = [
'Illuminate\Cache\Events\CacheHit' => [
'App\Listeners\LogCacheHit',
],
'Illuminate\Cache\Events\CacheMissed' => [
'App\Listeners\LogCacheMissed',
],
'Illuminate\Cache\Events\KeyForgotten' => [
'App\Listeners\LogKeyForgotten',
],
'Illuminate\Cache\Events\KeyWritten' => [
'App\Listeners\LogKeyWritten',
],
];