Caching is a technique that can significantly improve the performance of an application by storing frequently accessed data in a faster storage medium, such as memory. This reduces the need to recalculate or fetch the data from a slower source, such as a database. By implementing a caching layer, the application can quickly retrieve the data from the cache instead of recalculating it or fetching it from the slower source, which can improve the overall response time and reduce the load on the slower source.
The spiral/cache
component in Spiral provides a streamlined method for storing and retrieving data. This component
aligns with the PSR-16 standard standard, making it a versatile choice for
developers familiar with PHP standards.
When we speak of Spiral's caching prowess, RoadRunner sits at its core. Here's what you should know about RoadRunner:
Written in Go: RoadRunner is all about speed and efficiency. Go is revered for its blistering performance metrics, making it a natural choice for high-octane operations.
Tailored for High Concurrency: It doesn't just perform; it performs in parallel. Designed to shoulder high-performance tasks, it can manage concurrent operations without a hiccup.
Diverse Storage Choices through the Key-Value Plugin: With RoadRunner's Key-Value plugin, you're spoilt for choice. Opt for household names like Redis Server and Memcached or go the server-less route with choices like in-memory storage.
No PHP Extensions Required: One of the standout features of using RoadRunner is the elimination of any PHP extensions for Redis or Memcache. Instead, you communicate directly with RoadRunner using RPC.
To enable the component, you just need to add Spiral\Cache\Bootloader\CacheBootloader
to the bootloader's list:
Warning
Make sure that you have the spiral/roadrunner-bridge package installed.
public function defineBootloaders(): array
{
return [
// ...
\Spiral\Cache\Bootloader\CacheBootloader::class,
\Spiral\RoadRunnerBridge\Bootloader\CacheBootloader::class,
// ...
];
}
Read more about bootloaders in the Framework — Bootloaders section.
Note
Thespiral/roadrunner-bridge
package allows you to use RoadRunner kv plugin with Spiral. This package provides RPC api for KV and a bootloader for your application.
To get started, place your configuration file at app/config/cache.php
. This file acts as your go-to place for
configuring storage options and setting your default storage.
Here's a sample of what your cache.php
configuration might look like:
use Spiral\Cache\Storage\ArrayStorage;
use Spiral\Cache\Storage\FileStorage;
return [
/**
* -------------------------------------------------------------------------
* Default storage
* -------------------------------------------------------------------------
*
* The key of one of the registered cache storages to use by default.
*/
'default' => env('CACHE_STORAGE', 'rr-redis'),
/**
* -------------------------------------------------------------------------
* Aliases
* -------------------------------------------------------------------------
*
* Aliases, if you want to use domain specific storages.
*/
'aliases' => [
'user-data' => 'rr-redis',
'blog-data' => [
'storage' => 'rr-redis',
'prefix' => 'blog_'
],
],
/**
* -------------------------------------------------------------------------
* Storages
* -------------------------------------------------------------------------
*
* Here you may define all of the cache "storages" for your application as well as their types.
*/
'storages' => [
'rr-redis' => [
'type' => 'roadrunner',
'driver' => 'redis',
],
'rr-local' => [
'type' => 'roadrunner',
'driver' => 'local',
],
'local' => [
'type' => 'array',
],
'file' => [
'type' => 'file',
'path' => directory('runtime') . 'cache',
],
],
/**
* -------------------------------------------------------------------------
* Aliases for storage types
* -------------------------------------------------------------------------
*/
'typeAliases' => [
'array' => ArrayStorage::class,
'file' => FileStorage::class,
],
];
Aliases are your shortcut to referencing cache storages. They simplify the code and make it more readable.
For example, you have a storage named rr-redis
and you'd prefer to reference it as user-data
in your application.
The aliases
section helps you do just that!
What's more, you can fetch cache storage using the Spiral\Cache\CacheStorageProviderInterface
by the alias name. It
then smartly maps to the actual storage, making your code neater and more manageable.
Prefixes play a pivotal role when working with cache aliases. They ensure that your cache keys remain unique,
safeguarding against any accidental overlaps or clashes. By attaching a prefix
to an alias, each cache key under that
alias automatically inherits this prefix. This results in a structured, organized, and clash-free cache system.
Incorporating prefixes into your cache.php is straightforward:
return [
// ...
'aliases' => [
'user-data' => [
'storage' => 'rr-redis',
'prefix' => 'user_'
],
],
];
In the example above, any cache key under the user-data
alias will automatically be prefixed with user_
. So, a cache
key like profile
would be stored as user_profile
.
And the configuration file for the RoadRunner KV plugin:
kv:
local:
driver: memory
config:
interval: 60
redis:
driver: redis
config:
addrs:
- localhost:6379
...
See more
Read more about the configuration of the RoadRunner KV plugin in the RoadRunner documentation.
Spiral's cache component allows you to work with the cache using two interfaces:
Psr\SimpleCache\CacheInterface
and Spiral\Cache\CacheStorageProviderInterface
.
See more
You can use thecache
andcacheManager
prototype properties. Read more about the prototypes in the The Basics — Prototyping section.
By using Psr\SimpleCache\CacheInterface
, you can access the default cache storage that is defined in the configuration
file. This can be injected into a class using dependency injection, as shown in the example below:
namespace App\Service;
use Psr\SimpleCache\CacheInterface;
final class UserService
{
public function __construct(
private readonly CacheInterface $cache,
) {
}
public function find(int $id): User
{
// ...
}
}
On the other hand, by using Spiral\Cache\CacheStorageProviderInterface
, you can get a specific storage by its string
key from the configuration file. This allows you to access the cache storage for a specific domain or use case.
namespace App\Service;
use Spiral\Cache\CacheStorageProviderInterface;
class UserService
{
private readonly CacheInterface $cache;
public function __construct(CacheStorageProviderInterface $provider)
{
$this->cache = $provider->storage('user-data');
}
public function find(int $id): User
{
//...
}
}
In the example provided, a domain-specific storage user-data
is injected into the UserService
class. This allows you
to access the cache storage that is specifically tailored to the needs of the user data, and use it throughout the
class to store, retrieve, and delete user data from the cache.
By using this approach, you can easily manage and maintain the cache data for different parts of the application, and easily switch between different storage options as needed.
To get an item from the cache, you can use the get
method. If the item doesn't exist, it'll return null
. You can
also specify a default value to be returned if the item doesn't exist.
$data = $this->cache->get('key');
$data = $this->cache->get('key', 'default');
If you need to get multiple items at once, you can use the getMultiple
method and pass in an array of keys.
$data = $this->cache->getMultiple(['key', 'other']);
If you want to check if an item exists in the cache, you can use the has
method. It'll return true
if the item
exists, and false
if it doesn't.
if ($this->cache->has('key')) {
// ...
}
To store an item in the cache, you can use the set
method.
$this->cache->set(
key: 'key',
value: ['some' => 'data'],
ttl: 3600
);
You can also specify how long the item should be stored for (TTL) by passing in the number of seconds
or a
DateInterval
or DateTimeInterface
object.
$this->cache->set(
key: 'key',
value: ['some' => 'data'],
ttl: \Carbon\Carbon::now()->addHour()
);
If no value is specified, the cache value will be stored indefinitely (or for as long as the underlying storage driver allows).
$this->cache->set(
key: 'key',
value: ['some' => 'data']
);
You can also store multiple items at once by using the setMultiple
method and passing in an array of key/value pairs.
$this->cache->setMultiple(
values: [
'key' => ['some' => 'data'],
'other' => ['foo' => 'bar']
],
ttl: 3600
);
If you want to remove an item from the cache, you can use the delete
method.
$this->cache->delete('key');
You can also remove multiple items at once by using the deleteMultiple
method and passing in an array of keys.
$this->cache->deleteMultiple(['key', 'other']);
To remove all items from the cache, you can use the clear
method.
$this->cache->clear();
The component allows for the integration of custom storage methods through configuration files, making it versatile and easy to use. So you can use any of the available PSR-16 implementations.
In order to use a custom storage you need to register it in the storages
section of the configuration file, and
specify the type of storage using the type
key, and any necessary configuration options for that storage.
You will also need to register the class in the typeAliases
section of the configuration file, so that Spiral knows
how to instantiate your custom storage.
Event | Description |
---|---|
Spiral\Cache\Event\CacheHit |
The Event will be fired when data is successfully retrieved from the cache. |
Spiral\Cache\Event\CacheMissed |
The Event will be fired if the requested data is not found in the cache. |
Spiral\Cache\Event\KeyDeleted |
The Event will be fired after the data is removed from the cache. |
Spiral\Cache\Event\KeyWritten |
The Event will be fired after the data is stored in the cache. |
Note
To learn more about dispatching events, see the Events section in our documentation.