Skip to content

Added the documentation for the Cache component #6515

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 23 commits into from
Closed
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 116 additions & 0 deletions components/cache/cache_items.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
.. index::
single: Cache Item
single: Cache Expiration
single: Cache Exceptions

Cache Items
===========

Cache items are each of the information units stored in the cache as a key/value
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think "each of" can be removed?

pair. In the Cache component they are represented by the
:class:`Symfony\\Component\\Cache\\CacheItem` class.

Cache Item Keys and Values
--------------------------

The **key** of a cache item is a UTF-8 encoded string which acts as its
identifier, so it must be unique for each cache pool. You can freely choose the
keys, but they should only contain letters (A-Z, a-z), numbers (0-9) and the
``_`` and ``.`` symbols. Other common symbols (such as ``{``, ``}``, ``(``,
``)``, ``/``, ``\`` and ``@``) are reserved by the PSR-6 standard for future
uses.

The **value** of a cache item can be any data represented by a type which is
serializable by PHP, such as basic types (string, integer, float, boolean, null),
arrays and objects.

Creating Cache Items
--------------------

Cache items are created with the ``getItem($key)`` method of the cache pool. The
argument is the key of the item::

// $cache pool object was created before
$numProducts = $cache->getItem('stats.num_products');

Then, use the ``set($value)`` method to set the data stored in the cache item::
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's use an API link here


// storing a simple integer
$numProducts->set(4711);

// storing an array
$numProducts->set(array(
'category1' => 4711,
'category2' => 2387,
));

.. note::

Creating a cache item and setting its value is not enough to save it in the
cache. You must execute the ``save($cacheItem)`` method explicitly on the
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we don't put arguments in the parenthesis when refering to methods

cache pool.

The key and the value of any given cache item can be obtained with the
corresponding *getter* methods::

$cacheItem = $cache->getItem('exchange_rate');
// ...
$key = $cacheItem->getKey();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a difference between $key and 'logged_users'?

$value = $cacheItem->get();

Cache Item Expiration
~~~~~~~~~~~~~~~~~~~~~

By default cache items are stored permanently. In practice, this "permanent
storage" can vary greatly depending on the type of cache being used, as
explained in the :doc:`/components/cache/cache_pools` article.

However, in some applications it's common to use cache items with a shorter
lifespan. Consider for example an application which caches the latest news just
for one minute. In those cases, use the ``expiresAfter()`` method to set the
number of seconds to cache the item::

$latestNews = $cache->getItem('latest_news');
$latestNews->expiresAfter(60); // 60 seconds = 1 minute

// this method also accepts \DateInterval instances
$latestNews->expiresAfter(DateInterval::createFromDateString('1 hour'));

Cache items define another related method called ``expiresAt()`` to set the
exact date and time when the item will expire::

$mostPopularNews = $cache->getItem('popular_news');
$mostPopularNews->expiresAt(new \DateTime('tomorrow'));

Cache Item Hits and Misses
--------------------------

Using a cache mechanism is important to improve the application performance, but
it should not be required to make the application work. In fact, the Cache
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the "cache standard"?

standard states that caching errors should not result in application failures.

In practice this means that the ``getItem()`` method always returns an object
which implements the ``Psr\Cache\CacheItemInterface`` interface, even when the
cache item doesn't exist. Therefore, you don't have to deal with ``null`` return
values and you can safely store in the cache values such as ``false`` and ``null``.

In order to decide if the returned object is correct or not, caches use the
concept of hits and misses:

* **Cache Hits** occur when the requested item is found in the cache, its value
is not corrupted or invalid and it hasn't expired;
* **Cache Misses** are the opposite of hits, so they occur when the item is not
found in the cache, its value is corrupted or invalid for any reason or the
item has expired.

Cache item objects define a boolean ``isHit()`` method which returns ``true``
for cache hits::

$latestNews = $cache->getItem('latest_news');

if (!$latestNews->isHit()) {
$news = //... do some heavy computation
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the doc standard is:

// do some heavy computation
$news = ...;

$cache->save($latestNews->set($news));
} else {
$news = $latestNews->get();
}
248 changes: 248 additions & 0 deletions components/cache/cache_pools.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,248 @@
.. index::
single: Cache Pool
single: APC Cache, APCu Cache
single: Doctrine Cache
single: Redis Cache

Cache Pools
===========

Cache Pools are the logical repositories of cache items. They perform all the
common operations on items, such as saving them or looking for them. Cache pools
are independent from the actual cache implementation. Therefore, applications
can keep using the same cache pool even if the underlying cache mechanism
changes from a file system based cache to a Redis or database based cache.

Creating Cache Pools
--------------------

Cache Pools are created through the **cache adapters**, which are classes that
implement the :class:`Psr\\Cache\\CacheItemPoolInterface` interface. This
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"which" refers to "cache adapters", these implement AdapterInterface (which extends CacheItemPoolInterface).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand this comment. Please tell me how to reword this paragraph:

Cache Pools are created through the **cache adapters**, which are classes that
implement the :class:`Psr\\Cache\\CacheItemPoolInterface` interface. This
component provides several adapters ready to use in your applications.

Thanks.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the current situation, it seems like I need to implement CacheItemPoolInterface when I want to create a custom adapter. However, I have to to implement AdapterInterface (unless I'm wrong of course).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

true for symfony derivated adapters (AdapterInterface extends CacheItemPoolInterface)

component provides several adapters ready to use in your applications.

Array Cache Adapter
~~~~~~~~~~~~~~~~~~~

This adapter is only useful for testing purposes because contents are stored in
memory and not persisted in any way. Besides, some features explained later are
not available, such as the deferred saves::

use Symfony\Component\Cache\Adapter\ArrayAdapter;

$cache = new ArrayAdapter(
// in seconds; applied to cache items that don't define their own lifetime
// 0 means to store the cache items indefinitely (i.e. until the current PHP process finishes)
$defaultLifetime = 0,
// if ``true``, the values saved in the cache are serialized before storing them
$storeSerialized = true
);

Filesystem Cache Adapter
~~~~~~~~~~~~~~~~~~~~~~~~

This adapter is useful when you want to improve the application performance but
can't install tools like APC or Redis in the server. This adapter stores the
contents as regular files in a set of directories on the local file system::

use Symfony\Component\Cache\Adapter\FilesystemAdapter;

$cache = new FilesystemAdapter(
// the subdirectory of the main cache directory where cache items are stored
$namespace = '',
// in seconds; applied to cache items that don't define their own lifetime
// 0 means to store the cache items indefinitely (i.e. until the files are deleted)
$defaultLifetime = 0,
// the main cache directory (the application needs read-write permissions on it)
// if none is specified, a directory is created inside the system temporary directory
$directory = null
);

APCu Cache Adapter
~~~~~~~~~~~~~~~~~~

This adapter can increase the application performance very significantly,
because contents are cached in the shared memory of your server, which is much
faster than the file system. It requires to have installed and enabled the PHP
APCu extension. It's not recommended to use it when performing lots of write and
delete operations because it produces fragmentation in the APCu memory that can
degrade performance significantly::

use Symfony\Component\Cache\Adapter\ApcuAdapter;

$cache = new ApcuAdapter(
// the string prefixed to the keys of the items stored in this cache
$namespace = '',
// in seconds; applied to cache items that don't define their own lifetime
// 0 means to store the cache items indefinitely (i.e. until the APC memory is deleted)
$defaultLifetime = 0,
// if present, this string is added to the namespace to simplify the
// invalidation of the entire cache (e.g. when deploying the application)
$version = null
);

Redis Cache Adapter
~~~~~~~~~~~~~~~~~~~

This adapter stores the contents in the memory of the server. Unlike the APCu
adapter, it's not limited to the shared memory of the current server, so you can
store contents in a cluster of servers if needed.

It requires to have installed Redis and have created a connection that implements
the ``\Redis``, ``\RedisArray``, ``\RedisCluster`` or ``\Predis`` classes::

use Symfony\Component\Cache\Adapter\RedisAdapter;

$cache = new RedisAdapter(
// the object that stores a valid connection to your Redis system
\Redis $redisConnection,
// the string prefixed to the keys of the items stored in this cache
$namespace = '',
// in seconds; applied to cache items that don't define their own lifetime
// 0 means to store the cache items indefinitely (i.e. until the Redis memory is deleted)
$defaultLifetime = 0
);

Chain Cache Adapter
~~~~~~~~~~~~~~~~~~~

This adapter allows to combine any number of the previous adapters. Cache items
are fetched from the first adapter which contains them. Besides, cache items are
saved in all the given adapters, so this is a simple way of creating a cache
replication::

use Symfony\Component\Cache\Adapter\ApcuAdapter;
use Symfony\Component\Cache\Adapter\ChainAdapter;
use Symfony\Component\Cache\Adapter\FilesystemAdapter;

$apcCache = new ApcuAdapter();
$fileCache = new FilesystemAdapter();

$cache = new ChainAdapter(array($apcCache, $fileCache));

when an item is not found in the first adapters but is found in the next ones,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"When [...]"

the ``ChainAdapter`` ensures that the fetched item is saved in all the adapters
where it was missing. Since it's not possible to know the expiry date and time
of a cache item, the second optional argument of ``ChainAdapter`` is the default
lifetime applied to those cache items (by default it's ``0``).

Proxy Cache Adapter
~~~~~~~~~~~~~~~~~~~

This adapter is useful to integrate in your application cache pools not created
with the Symfony Cache component. As long as those cache pools implement the
``CacheItemPoolInterface`` interface, this adapter allows you to get items from
that external cache and save them in the Symfony cache of your application::

use Symfony\Component\Cache\Adapter\ProxyAdapter;

// ... create $nonSymfonyCache somehow
$cache = new ProxyAdapter($nonSymfonyCache);

The adapter accepts two additional optional arguments: the namespace (``''`` by
default) and the default lifetime (``0`` by default).

Another use case for this adapter is to get statistics and metrics about the
cache hits and misses thanks to the ``getHits()`` and ``getMisses()`` methods.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"thanks to [...]" can be removed imo


Doctrine Cache Adapter
~~~~~~~~~~~~~~~~~~~~~~

This adapter wraps any `Doctrine Cache`_ provider so you can use them in your
application as if they were Symfony Cache adapters::

use Doctrine\Common\Cache\SQLite3Cache;
use Symfony\Component\Cache\Adapter\DoctrineAdapter;

$doctrineCache = new SQLite3(__DIR__.'/cache/data.sqlite');
$symfonyCache = new DoctrineAdapter($doctrineCache);

This adapter also defines two optional arguments called ``namespace`` (default:
``''``) and ``defaultLifetime`` (default: ``0``) and adapts them to make them
work in the underlying Doctrine cache.

Looking for Cache Items
-----------------------

Cache Pools define three methods to look for cache items. The most common method
is ``getItem($key)``, which returns the cache item identified by the given key::

use Symfony\Component\Cache\Adapter\FilesystemAdapter;

$cache = new FilesystemAdapter('app.cache')
$latestNews = $cache->getItem('latest_news');

If no item is defined for the given key, the method doesn't return a ``null``
value but an empty object which implements the :class:`Symfony\\Component\\Cache\\CacheItem`
class.

If you need to fetch several cache items simultaneously, use instead the
``getItems(array($key1, $key2, ...))`` method::

// ...
$stocks = $cache->getItems(array('AAPL', 'FB', 'GOOGL', 'MSFT'));

Again, if any of the keys doesn't represent a valid cache item, you won't get
a ``null`` value but an empty ``CacheItem`` object.

The last method related to fetching cache items is ``hasItem($key)``, which
returns ``true`` if there is a cache item identified by the given key::

// ...
$hasBadges = $cache->hasItem('user_'.$userId.'_badges');

Saving Cache Items
------------------

The most common method to save cache items is ``save($item)``, which stores the
Copy link
Member

@wouterj wouterj Jun 14, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's use API links (same below for the other methods)

item in the cache immediately (it returns ``true`` if the item was saved or
``false`` if some error occurred)::

// ...
$userFriends = $cache->get('user_'.$userId.'_friends');
$userFriends->set($user->getFriends());
$isSaved = $cache->save($userFriends);

Sometimes you may prefer to not save the objects immediately in order to
increase the application performance. In those cases, use the
``saveDeferred($item)`` method to mark cache items as "ready to be persisted"
and then call to ``commit()`` method when you are ready to persist them all::

// ...
$isQueued = $cache->saveDeferred($userFriends);
// ...
$isQueued = $cache->saveDeferred($userPreferences);
// ...
$isQueued = $cache->saveDeferred($userRecentProducts);
// ...
$isSaved = $cache->commit();

The ``saveDeferred()`` method returns ``true`` when the cache item has been
successfully added to the "persist queue" and ``false`` otherwise. The ``commit()``
method returns ``true`` when all the pending items are successfully saved or
``false`` otherwise.

Removing Cache Items
--------------------

Cache Pools include methods to delete a cache item, some of them or all of them.
The most common is ``deleteItem($key)``, which deletes the cache item identified
by the given key (it returns ``true`` when the item is successfully deleted or
doesn't exist and ``false`` otherwise)::

// ...
$isDeleted = $cache->deleteItem('user_'.$userId);

Use the ``deleteItems(array($key1, $key2, ...))`` method to delete several cache
items simultaneously (it returns ``true`` only if all the items have been deleted,
even when any or some of them don't exist)::

// ...
$areDeleted = $cache->deleteItems(array('category1', 'category2'));

Finally, to remove all the cache items stored in the pool, use the ``clear()``
method (which returns ``true`` when all items are successfully deleted)::

// ...
$cacheIsEmpty = $cache->clear();

.. _`Doctrine Cache`: https://github.com/doctrine/cache
9 changes: 9 additions & 0 deletions components/cache/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Cache
=====

.. toctree::
:maxdepth: 2

introduction
cache_items
cache_pools
Loading