FORSMILE
JA
Symfony2021/04/08

How to Use Doctrine Result Cache [Symfony]

This is a memo regarding a project using the EC-CUBE e-commerce framework, where I re-evaluated the caching mechanisms.

Back to Blog

This is a memo regarding a project using the EC-CUBE e-commerce framework, where I re-evaluated the caching mechanisms.

The starting point was that `deleteByPrefix`, which was used to delete caches by prefix in Doctrine 1.x, was no longer available.

Here's a summary of the changes related to caching (English text as is):

javascript
## Cache Changes
  
- Renamed old AbstractCache to CacheProvider

- Dropped the support to the following functions of all cache providers:
  - CacheProvider::deleteByWildcard
  - CacheProvider::deleteByRegEx
  - CacheProvider::deleteByPrefix
  - CacheProvider::deleteBySuffix

- CacheProvider::deleteAll will not remove ALL entries, it will only mark them as invalid
- CacheProvider::flushAll will remove ALL entries, namespaced or not
- Added support to MemcachedCache
- Added support to WincacheCache

So, the `deleteByXXX` functions were all removed.

This means that when using Result Cache, the method of managing IDs with prefixes for forward-matching deletion is no longer usable.

Well, it means we should manage caches properly using namespaces instead of just IDs.

You can clear caches (`deleteAll`) for each namespace.

This time, I'd like to explain how to use Result Cache. For information on other caches, please refer to the following:

Official(English)::doctrine-project -- Caching

SETTING UP RESULT CACHE IN SYMFONY

Official(English)::Configuration Reference -- Cache Driver

While various customizations are possible, I'll use the example from GitHub as is.

text
doctrine:
    orm:
        auto_generate_proxy_classes: false
        metadata_cache_driver:
            type: pool
            pool: doctrine.system_cache_pool
        query_cache_driver:
            type: pool
            pool: doctrine.system_cache_pool
        result_cache_driver:
            type: pool
            pool: doctrine.result_cache_pool

framework:
    cache:
        pools:
            doctrine.result_cache_pool:
                adapter: cache.app
            doctrine.system_cache_pool:
                adapter: cache.system

Once the above is added to `doctrine.yaml`, the configuration is complete.

USING RESULT CACHE

Result Cache can cache the results of DQL queries. By creating a DQL query, related methods become available.

php
// Case Repository (extends ServiceEntityRepository)

$qb = $this->createQueryBuilder('user')
    ->where('user.id = :id')
    ->setParameter('id', $userId);    
$qb->getQuery()
    ->useResultCache(true, 600, 'UserInfo')
    ->getResult();

After the DQL query is created with `getQuery()`, related methods become available.

We use `useResultCache` to store data in the Result Cache.

https://doctrine2.readthedocs.io/en/latest/reference/caching.html

Since we haven't specified a namespace yet, caches without a namespace will be created.

For example, if `deleteAll` is executed without specifying a namespace, all caches without a namespace will be deleted.

DELETING RESULT CACHE

Here's how to delete Result Cache. There are `delete($id)` and `deleteAll` methods.

javascript
// Case Repository (extends ServiceEntityRepository)

$qb = $this->getEntityManager()->createQuery();

$cacheDriver = $qb->getResultCacheDriver();
$cacheDriver->delete('UserInfo');

In the example above, the cache with the ID 'UserInfo' will be deleted. It's simple, isn't it?

Now, let's look at my main topic for this article: how to collectively delete only specific caches.

In Doctrine 1.x, we used to add a prefix to the ID and delete caches by forward-matching using `deleteByPrefix()`.

Since that method is no longer available, we'll manage caches using namespaces.

MANAGING RESULT CACHE USING NAMESPACES

Simply put, it's about creating a 'box' called a namespace and storing caches within it.

This is useful when you have multiple projects, or want to categorize caches, such as for 'User' or 'Admin'.

javascript
// Case Repository (extends ServiceEntityRepository)

// use ResultCashe in namespace "User"
$qb = $this->createQueryBuilder('user')
    ->where('user.id = :id')
    ->setParameter('id', $userId)
    ->getQuery();

$cacheDriver = $qb->getResultCacheDriver();
$cacheDriver->setNamespace('User');

$result = $qb->useResultCache(true, 600, 'UserInfo')
    ->getResult();

// DeleteAll namespace "User"
$qb = $this->getEntityManager()->createQuery();
$cacheDriver = $qb->getResultCacheDriver();
$cacheDriver->setNamespace('User');
$cacheDriver->deleteAll();

We call the cache driver and set a namespace for the DQL query using `setNamespace()`.

If `deleteAll` is executed with the code above, all caches within the 'User' namespace will be deleted.

This concludes a brief overview of how to use Result Cache and set up namespaces.

For more detailed information, I recommend checking the URLs mentioned in the article.

Recommended Symfony Books

There aren't many varieties, and the framework itself has a vast amount of information, so even introductory books can be quite substantial reads.

📦
Amazon で関連書籍・ツールを検索
Symfony PHP framework book
Amazonで探す →(アソシエイトリンク)