2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Symfony ComponentAdvent Calendar 2022

Day 16

結果を一定期間保持する、"Cache"

Last updated at Posted at 2022-12-15

Symfony Component Advent Calendar 2022の16日目の記事です。

最初に

SymfonyはPHPのフレームワークのひとつです。しかし、公式サイトの説明文には

Symfony is a set of PHP Components, a Web Application framework, a Philosophy, and a Community — all working together in harmony.
(SymfonyはPHPコンポーネントのセットで、Webアプリケーションフレームワークで、哲学、そしてコミュニティです。それらがハーモニーを奏でながら動作しています。)

と書かれている通り、PHPコンポーネントのセットで、たくさんのコンポーネントを提供しており、それらを組み合わせてひとつのフレームワークとして動作しています。Symfonyのコンポーネントは、Symfony上だけで動作するのではなく、他のPHPフレームワークやアプリケーションでも動作している強力なものが揃っています。

今回はそれらの中から、役立ちそうなもの・お薦めしたいものを紹介していきたいと思います。

※記事内ではautoloadのインポートは省略します。

結果を一定期間保持する、"Cache"

Cacheは、処理結果を一定期間保持し、その値を返すことでパフォーマンス向上を行うコンポーネントです。

実はちゃんと使ったことがないコンポーネントです。が、ざっとドキュメントを読んでみると非常に魅力的なコンポーネントでした。

インストール

composer require symfony/cache

キャッシュの作成・利用

値をキャッシュするにはCacheオブジェクトを使います。get()メソッドで、取得するためのキーと取得できなかった場合の処理(= キャッシュする値)を記述します。

SampleCommand.php

use Symfony\Contracts\Cache\ItemInterface;

class SompleCommand extends Command
{
    public function __construct(private readonly CacheInterface $cache)
    {
        parent::__construct();
    }

    public function execute(InputInterface $input, OutputInterface $output): int
    {
        // キャッシュの作成・利用
        $value = $this->cache->get('my_value', function (ItemInterface $item) {
            $randomValue = rand(0, 100); // ランダムな値

            $item->expiresAfter(30); // 30秒間キャッシュ

            return $randomValue;
        });

        // 最初のランダムな値が28だった場合、30秒間はコマンドを何度実行しても28が出力される。
        $io->success($value);
    }
}

ItemInterfaceはキャッシュの設定が行えるアイテムクラスです。各キーごとにオブジェクトが生成されます。

キャッシュの設定

通常、キャッシュはvar/cacheにファイルとして保存されますが、他にもいくつかの保存先が利用でき、設定ファイルでアダプター(&プロバイダー)を設定することで切り替えができます。

config/packages/cache.yaml
framework:
    cache:
        app: cache.adapter.filesystem
        system: cache.adapter.system

framework.cache.appはアプリケーション側(= 自分達が作るコード側)のプール設定、framework.cache.systemはSymfony側のプール設定になります。基本はapp側のみさわることになると思います。用意されているアダプターは以下の通りです。

設定名 保存先
cache.adapter.apcu APC User Cache
cache.adapter.array メモリー内(1プロセス内のみ生きることができる)
cache.adapter.filesystem ファイル(var/cache)
cache.adapter.memcached Memcached
cache.adapter.pdo DB
cache.adapter.psr6 PSR6準拠 
cache.adapter.redis Redis
cache.adapter.redis_tag_aware Redis(タグベース)
cache.adapter.system Symfony用、appでは使わない

プロバイダーの設定が必要な場合は、別途設定を追記します。

config/packages/cache.yaml
framework:
    cache:
        app: cache.adapter.filesystem
        system: cache.adapter.system

        default_redis_provider: 'redis://localhost'

また、app, system以外のプールも用意することができ、プール名のキャメルケースにした引数をコンストラクタに持つことでオートワイヤリングできます。

config/packages/cache.yaml
framework:
    cache:
        pools:
            my_great.cache:
                adapter: cache.adapter.redis
SomeService.php
class SomeService
{
    public function __construct(CacheInterface $myGreatCache)
    {
    }
}

HTTPレスポンスのキャッシュ

HTTPレスポンスのキャッシュはまた別の設定・記述が必要です。まず、framework.yamlでキャッシュを有効化します。

service/packages/framework.yaml
framework:
    http_cache: true

そして、出力するレスポンスオブジェクトでsetPublic(), setMaxAge()メソッドを呼び出します。

ItemController.php
class ItemController extends AbstractController
{
    public function index(ItemRepository $itemRepository): Response
    {
        $items = $itemRepository->findBy(['isPublished' => true]);
        $response = $this->render('item/index.html.twig', [
            'items' => $items,
        ]);
        
        $response
            ->setPublic() // "Cache-Control"に"public"追加
            ->setMaxAge(60) // "Cache-Control"に"maxage=60"追加

        return $response;
    }
}

これにより、レスポンスヘッダにCache-Controle: public, maxage=60が追加され、60秒間はコンテンツがキャッシュされます。

Symfony6.2から! アトリビュート設定

Symfony6.2ではアトリビュートで指定できるようになり、さらに設定がしやすくなります。

ItemController.php
+ use Symfony\Component\HttpKernel\Attribute\Cache;

class ItemController extends AbstractController
{

+    #[Cache(public: true, maxage: 60)]
    public function index(ItemRepository $itemRepository): Response
    {
        $items = $itemRepository->findBy(['isPublished' => true]);
+        return $this->render('item/index.html.twig', [
-        $response =  $this->render('item/index.html.twig', [
            'items' => $items,
        ]);
-
-        $response
-            ->setPublic() // "Cache-Control"に"public"追加
-            ->setMaxAge(60) // "Cache-Control"に"maxage=60"追加
-
-        return $response;
    }
}

まとめ

今回はCacheを紹介しました。キャッシュは扱いがとても難しいですが、ちゃんと使っていくとパフォーマンスが飛躍的に向上します。
特にSymfony6.2からはアトリビュートでの指定ができるので、トライ&エラーが非常にやりやすくなるので、試してみる価値大かなと思います。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?