350 lines
12 KiB
Plaintext
350 lines
12 KiB
Plaintext
|
Doctrine provides cache drivers in the `Common` package for some of the most
|
||
|
popular caching implementations such as APC, Memcache and Xcache. We also provide
|
||
|
an `ArrayCache` driver which stores the data in a PHP array. Obviously, the cache
|
||
|
does not live between requests but this is useful for testing in a development
|
||
|
environment.
|
||
|
|
||
|
++ Cache Drivers
|
||
|
|
||
|
The cache drivers follow a simple interface that is defined in `Doctrine\Common\Cache\Cache`.
|
||
|
All the cache drivers extend a base class `Doctrine\Common\Cache\AbstractCache`
|
||
|
which implements the before mentioned interface.
|
||
|
|
||
|
The interface defines the following methods for you to publicly use.
|
||
|
|
||
|
* fetch($id) - Fetches an entry from the cache.
|
||
|
* contains($id) - Test if an entry exists in the cache.
|
||
|
* save($id, $data, $lifeTime = false) - Puts data into the cache.
|
||
|
* delete($id) - Deletes a cache entry.
|
||
|
|
||
|
Each driver extends the `AbstractCache` class which defines a few abstract
|
||
|
protected methods that each of the drivers must implement.
|
||
|
|
||
|
* _doFetch($id)
|
||
|
* _doContains($id)
|
||
|
* _doSave($id, $data, $lifeTime = false)
|
||
|
* _doDelete($id)
|
||
|
|
||
|
The public methods `fetch()`, `contains()`, etc. utilize the above protected methods
|
||
|
that are implemented by the drivers. The code is organized this way so that the
|
||
|
protected methods in the drivers do the raw interaction with the cache implementation
|
||
|
and the `AbstractCache` can build custom functionality on top of these methods.
|
||
|
|
||
|
+++ APC
|
||
|
|
||
|
In order to use the APC cache driver you must have it compiled and enabled in
|
||
|
your php.ini. You can read about APC [here](http://us2.php.net/apc) on the PHP
|
||
|
website. It will give you a little background information about what it is and
|
||
|
how you can use it as well as how to install it.
|
||
|
|
||
|
Below is a simple example of how you could use the APC cache driver by itself.
|
||
|
|
||
|
[php]
|
||
|
$cacheDriver = new \Doctrine\Common\Cache\ApcCache();
|
||
|
$cacheDriver->save('cache_id', 'my_data');
|
||
|
|
||
|
+++ Memcache
|
||
|
|
||
|
In order to use the Memcache cache driver you must have it compiled and enabled in
|
||
|
your php.ini. You can read about Memcache [here](http://us2.php.net/memcache) on
|
||
|
the PHP website. It will give you a little background information about what it is
|
||
|
and how you can use it as well as how to install it.
|
||
|
|
||
|
Below is a simple example of how you could use the Memcache cache driver by itself.
|
||
|
|
||
|
[php]
|
||
|
$memcache = new Memcache();
|
||
|
$memcache->connect('memcache_host', 11211);
|
||
|
|
||
|
$cacheDriver = new \Doctrine\Common\Cache\MemcacheCache();
|
||
|
$cacheDriver->setMemcache()
|
||
|
$cacheDriver->save('cache_id', 'my_data');
|
||
|
|
||
|
+++ Xcache
|
||
|
|
||
|
In order to use the Xcache cache driver you must have it compiled and enabled in
|
||
|
your php.ini. You can read about Xcache [here](http://xcache.lighttpd.net/). It
|
||
|
will give you a little background information about what it is and how you can
|
||
|
use it as well as how to install it.
|
||
|
|
||
|
Below is a simple example of how you could use the Xcache cache driver by itself.
|
||
|
|
||
|
[php]
|
||
|
$cacheDriver = new \Doctrine\Common\Cache\XcacheCache();
|
||
|
$cacheDriver->save('cache_id', 'my_data');
|
||
|
|
||
|
++ Using Cache Drivers
|
||
|
|
||
|
In this section we'll describe how you can fully utilize the API of the cache
|
||
|
drivers to save cache, check if some cache exists, fetch the cached data and
|
||
|
delete the cached data. We'll use the `ArrayCache` implementation as our
|
||
|
example here.
|
||
|
|
||
|
[php]
|
||
|
$cacheDriver = new \Doctrine\Common\Cache\ArrayCache();
|
||
|
|
||
|
+++ Saving
|
||
|
|
||
|
To save some data to the cache driver it is as simple as using the `save()` method.
|
||
|
|
||
|
[php]
|
||
|
$cacheDriver->save('cache_id', 'my_data');
|
||
|
|
||
|
The `save()` method accepts three arguments which are described below.
|
||
|
|
||
|
* `$id` - The cache id
|
||
|
* `$data` - The cache entry/data.
|
||
|
* `$lifeTime` - The lifetime. If != false, sets a specific lifetime for this cache entry (null => infinite lifeTime).
|
||
|
|
||
|
You can save any type of data whether it be a string, array, object, etc.
|
||
|
|
||
|
[php]
|
||
|
$array = array(
|
||
|
'key1' => 'value1',
|
||
|
'key2' => 'value2'
|
||
|
);
|
||
|
$cacheDriver->save('my_array', $array);
|
||
|
|
||
|
+++ Checking
|
||
|
|
||
|
Checking whether some cache exists is very simple, just use the `contains()` method.
|
||
|
It accepts a single argument which is the ID of the cache entry.
|
||
|
|
||
|
[php]
|
||
|
if ($cacheDriver->contains('cache_id')) {
|
||
|
echo 'cache exists';
|
||
|
} else {
|
||
|
echo 'cache does not exist';
|
||
|
}
|
||
|
|
||
|
+++ Fetching
|
||
|
|
||
|
Now if you want to retrieve some cache entry you can use the `fetch()` method. It
|
||
|
also accepts a single argument just like `contains()` which is the ID of the cache entry.
|
||
|
|
||
|
[php]
|
||
|
$array = $cacheDriver->fetch('my_array');
|
||
|
|
||
|
+++ Deleting
|
||
|
|
||
|
As you might guess, deleting is just as easy as saving, checking and fetching.
|
||
|
We have a few ways to delete cache entries. You can delete by an individual ID,
|
||
|
regular expression, prefix, suffix or you can delete all entries.
|
||
|
|
||
|
++++ By Cache ID
|
||
|
|
||
|
[php]
|
||
|
$cacheDriver->delete('my_array');
|
||
|
|
||
|
You can also pass wild cards to the `delete()` method and it will return an array
|
||
|
of IDs that were matched and deleted.
|
||
|
|
||
|
[php]
|
||
|
$deleted = $cacheDriver->delete('users_*');
|
||
|
|
||
|
++++ By Regular Expression
|
||
|
|
||
|
If you need a little more control than wild cards you can use a PHP regular
|
||
|
expression to delete cache entries.
|
||
|
|
||
|
[php]
|
||
|
$deleted = $cacheDriver->deleteByRegex('/users_.*/');
|
||
|
|
||
|
++++ By Prefix
|
||
|
|
||
|
Because regular expressions are kind of slow, if simply deleting by a prefix or
|
||
|
suffix is sufficient, it is recommended that you do that instead of using a regular
|
||
|
expression because it will be much faster if you have many cache entries.
|
||
|
|
||
|
[php]
|
||
|
$deleted = $cacheDriver->deleteByPrefix('users_');
|
||
|
|
||
|
++++ By Suffix
|
||
|
|
||
|
Just like we did above with the prefix you can do the same with a suffix.
|
||
|
|
||
|
[php]
|
||
|
$deleted = $cacheDriver->deleteBySuffix('_my_account');
|
||
|
|
||
|
++++ All
|
||
|
|
||
|
If you simply want to delete all cache entries you can do so with the `deleteAll()`
|
||
|
method.
|
||
|
|
||
|
[php]
|
||
|
$deleted = $cacheDriver->deleteAll();
|
||
|
|
||
|
+++ Counting
|
||
|
|
||
|
If you want to count how many entries are stored in the cache driver instance
|
||
|
you can use the `count()` method.
|
||
|
|
||
|
[php]
|
||
|
echo $cacheDriver->count();
|
||
|
|
||
|
> **NOTE**
|
||
|
> In order to use `deleteByRegex()`, `deleteByPrefix()`, `deleteBySuffix()`,
|
||
|
> `deleteAll()`, `count()` or `getIds()` you must enable an option for the cache
|
||
|
> driver to manage your cache IDs internally. This is necessary because APC,
|
||
|
> Memcache, etc. don't have any advanced functionality for fetching and deleting.
|
||
|
> We add some functionality on top of the cache drivers to maintain an index of
|
||
|
> all the IDs stored in the cache driver so that we can allow more granular deleting
|
||
|
> operations.
|
||
|
>
|
||
|
> [php]
|
||
|
> $cacheDriver->setManageCacheIds(true);
|
||
|
|
||
|
+++ Namespaces
|
||
|
|
||
|
If you heavily use caching in your application and utilize it in multiple parts
|
||
|
of your application, or use it in different applications on the same server you
|
||
|
may have issues with cache naming collisions. This can be worked around by using
|
||
|
namespaces. You can set the namespace a cache driver should use by using the
|
||
|
`setNamespace()` method.
|
||
|
|
||
|
[php]
|
||
|
$cacheDriver->setNamespace('my_namespace_');
|
||
|
|
||
|
++ Integrating with the ORM
|
||
|
|
||
|
The Doctrine ORM package is tightly integrated with the cache drivers to allow
|
||
|
you to improve performance of various aspects of Doctrine by just simply making
|
||
|
some additional configurations and method calls.
|
||
|
|
||
|
+++ Query Cache
|
||
|
|
||
|
It is highly recommended that in a production environment you cache the
|
||
|
transformation of a DQL query to its SQL counterpart. It doesn't make sense to
|
||
|
do this parsing multiple times as it doesn't change unless you alter the DQL
|
||
|
query.
|
||
|
|
||
|
This can be done by configuring the query cache implementation to use on your ORM
|
||
|
configuration.
|
||
|
|
||
|
[php]
|
||
|
$config = new \Doctrine\ORM\Configuration();
|
||
|
$config->setQueryCacheImpl(new \Doctrine\Common\Cache\ApcCache());
|
||
|
|
||
|
+++ Result Cache
|
||
|
|
||
|
The result cache can be used to cache the results of your queries so that we
|
||
|
don't have to query the database or hydrate the data again after the first time.
|
||
|
You just need to configure the result cache implementation.
|
||
|
|
||
|
[php]
|
||
|
$config->setResultCacheImpl(new \Doctrine\Common\Cache\ApcCache());
|
||
|
|
||
|
Now when you're executing DQL queries you can configure them to use the result cache.
|
||
|
|
||
|
[php]
|
||
|
$query = $em->createQuery('select u from \Entities\User u');
|
||
|
$query->useResultCache(true);
|
||
|
|
||
|
You can also configure an individual query to use a different result cache driver.
|
||
|
|
||
|
[php]
|
||
|
$query->setResultCacheDriver(new \Doctrine\Common\Cache\ApcCache());
|
||
|
|
||
|
> **NOTE**
|
||
|
> Setting the result cache driver on the query will automatically enable the
|
||
|
> result cache for the query. If you want to disable it pass false to
|
||
|
> `useResultCache()`.
|
||
|
>
|
||
|
> [php]
|
||
|
> $query->useResultCache(false);
|
||
|
|
||
|
If you want to set the time the cache has to live you can use the `setResultCacheLifetime()`
|
||
|
method.
|
||
|
|
||
|
[php]
|
||
|
$query->setResultCacheLifetime(3600);
|
||
|
|
||
|
The ID used to store the result set cache is a hash which is automatically generated
|
||
|
for you if you don't set a custom ID yourself with the `setResultCacheId()` method.
|
||
|
|
||
|
[php]
|
||
|
$query->setResultCacheId('my_custom_id');
|
||
|
|
||
|
You can also set the lifetime and cache ID by passing the values as the second
|
||
|
and third argument to `useResultCache()`.
|
||
|
|
||
|
[php]
|
||
|
$query->useResultCache(true, 3600, 'my_custom_id');
|
||
|
|
||
|
+++ Metadata Cache
|
||
|
|
||
|
Your class metadata can be parsed from a few different sources like YAML, XML,
|
||
|
Annotations, etc. Instead of parsing this information on each request we should
|
||
|
cache it using one of the cache drivers.
|
||
|
|
||
|
Just like the query and result cache we need to configure it first.
|
||
|
|
||
|
[php]
|
||
|
$config->setMetadataCacheImpl(new \Doctrine\Common\Cache\ApcCache());
|
||
|
|
||
|
Now the metadata information will only be parsed once and stored in the cache
|
||
|
driver.
|
||
|
|
||
|
++ Clearing the Cache
|
||
|
|
||
|
We've already shown you previously how you can use the API of the cache drivers
|
||
|
to manually delete cache entries. For your convenience we offer a command line task
|
||
|
for you to help you with clearing the query, result and metadata cache.
|
||
|
|
||
|
From the Doctrine command line you can run the following command.
|
||
|
|
||
|
$ ./doctrine clear-cache
|
||
|
|
||
|
Running this task with no arguments will clear all the cache for all the configured
|
||
|
drivers. If you want to be more specific about what you clear you can use the
|
||
|
following options.
|
||
|
|
||
|
To clear the query cache use the `--query` option.
|
||
|
|
||
|
$ ./doctrine clear-cache --query
|
||
|
|
||
|
To clear the metadata cache use the `--metadata` option.
|
||
|
|
||
|
$ ./doctrine clear-cache --metadata
|
||
|
|
||
|
To clear the result cache use the `--result` option.
|
||
|
|
||
|
$ ./doctrine clear-cache --result
|
||
|
|
||
|
When you use the `--result` option you can use some other options to be more
|
||
|
specific about what queries result sets you want to clear.
|
||
|
|
||
|
Just like the API of the cache drivers you can clear based on an ID, regular
|
||
|
expression, prefix or suffix.
|
||
|
|
||
|
$ ./doctrine clear-cache --result --id=cache_id
|
||
|
|
||
|
Or if you want to clear based on a regular expressions.
|
||
|
|
||
|
$ ./doctrine clear-cache --result --regex=users_.*
|
||
|
|
||
|
Or with a prefix.
|
||
|
|
||
|
$ ./doctrine clear-cache --result --prefix=users_
|
||
|
|
||
|
And finally with a suffix.
|
||
|
|
||
|
$ ./doctrine clear-cache --result --suffix=_my_account
|
||
|
|
||
|
> **NOTE**
|
||
|
> Using the `--id`, `--regex`, etc. options with the `--query` and `--metadata`
|
||
|
> are not allowed as it is not necessary to be specific about what you clear.
|
||
|
> You only ever need to completely clear the cache to remove stale entries.
|
||
|
|
||
|
++ Cache Slams
|
||
|
|
||
|
Something to be careful of when utilizing the cache drivers is cache slams. If
|
||
|
you have a heavily trafficked website with some code that checks for the existence
|
||
|
of a cache record and if it does not exist it generates the information and saves
|
||
|
it to the cache. Now if 100 requests were issued all at the same time and each one
|
||
|
sees the cache does not exist and they all try and insert the same cache entry
|
||
|
it could lock up APC, Xcache, etc. and cause problems. Ways exist to work around
|
||
|
this, like pre-populating your cache and not letting your users requests populate
|
||
|
the cache.
|
||
|
|
||
|
You can read more about cache slams [here](http://t3.dotgnu.info/blog/php/user-cache-timebomb).
|