Update to Drupal 8.0.0-beta15. For more information, see: https://www.drupal.org/node/2563023
This commit is contained in:
parent
2720a9ec4b
commit
f3791f1da3
1898 changed files with 54300 additions and 11481 deletions
|
@ -20,6 +20,8 @@ namespace Drupal\Core\Cache;
|
|||
* to ensure fast retrieval on the next request. On cache sets and deletes, both
|
||||
* backends will be invoked to ensure consistency.
|
||||
*
|
||||
* @see \Drupal\Core\Cache\ChainedFastBackend
|
||||
*
|
||||
* @ingroup cache
|
||||
*/
|
||||
|
||||
|
|
26
core/lib/Drupal/Core/Cache/CacheableJsonResponse.php
Normal file
26
core/lib/Drupal/Core/Cache/CacheableJsonResponse.php
Normal file
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Core\Cache\CacheableResponse.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\Cache;
|
||||
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
|
||||
/**
|
||||
* A JsonResponse that contains and can expose cacheability metadata.
|
||||
*
|
||||
* Supports Drupal's caching concepts: cache tags for invalidation and cache
|
||||
* contexts for variations.
|
||||
*
|
||||
* @see \Drupal\Core\Cache\Cache
|
||||
* @see \Drupal\Core\Cache\CacheableMetadata
|
||||
* @see \Drupal\Core\Cache\CacheableResponseTrait
|
||||
*/
|
||||
class CacheableJsonResponse extends JsonResponse implements CacheableResponseInterface {
|
||||
|
||||
use CacheableResponseTrait;
|
||||
|
||||
}
|
|
@ -11,50 +11,16 @@ namespace Drupal\Core\Cache;
|
|||
*
|
||||
* @ingroup cache
|
||||
*
|
||||
* @todo Use RefinableCacheableDependencyInterface and the corresponding trait in
|
||||
* https://www.drupal.org/node/2526326.
|
||||
*/
|
||||
class CacheableMetadata implements CacheableDependencyInterface {
|
||||
class CacheableMetadata implements RefinableCacheableDependencyInterface {
|
||||
|
||||
/**
|
||||
* Cache contexts.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
protected $contexts = [];
|
||||
|
||||
/**
|
||||
* Cache tags.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
protected $tags = [];
|
||||
|
||||
/**
|
||||
* Cache max-age.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $maxAge = Cache::PERMANENT;
|
||||
use RefinableCacheableDependencyTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheTags() {
|
||||
return $this->tags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds cache tags.
|
||||
*
|
||||
* @param string[] $cache_tags
|
||||
* The cache tags to be added.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function addCacheTags(array $cache_tags) {
|
||||
$this->tags = Cache::mergeTags($this->tags, $cache_tags);
|
||||
return $this;
|
||||
return $this->cacheTags;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -66,7 +32,7 @@ class CacheableMetadata implements CacheableDependencyInterface {
|
|||
* @return $this
|
||||
*/
|
||||
public function setCacheTags(array $cache_tags) {
|
||||
$this->tags = $cache_tags;
|
||||
$this->cacheTags = $cache_tags;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
@ -74,20 +40,7 @@ class CacheableMetadata implements CacheableDependencyInterface {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheContexts() {
|
||||
return $this->contexts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds cache contexts.
|
||||
*
|
||||
* @param string[] $cache_contexts
|
||||
* The cache contexts to be added.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function addCacheContexts(array $cache_contexts) {
|
||||
$this->contexts = Cache::mergeContexts($this->contexts, $cache_contexts);
|
||||
return $this;
|
||||
return $this->cacheContexts;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -99,7 +52,7 @@ class CacheableMetadata implements CacheableDependencyInterface {
|
|||
* @return $this
|
||||
*/
|
||||
public function setCacheContexts(array $cache_contexts) {
|
||||
$this->contexts = $cache_contexts;
|
||||
$this->cacheContexts = $cache_contexts;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
@ -107,7 +60,7 @@ class CacheableMetadata implements CacheableDependencyInterface {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheMaxAge() {
|
||||
return $this->maxAge;
|
||||
return $this->cacheMaxAge;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -128,36 +81,7 @@ class CacheableMetadata implements CacheableDependencyInterface {
|
|||
throw new \InvalidArgumentException('$max_age must be an integer');
|
||||
}
|
||||
|
||||
$this->maxAge = $max_age;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a dependency on an object: merges its cacheability metadata.
|
||||
*
|
||||
* @param \Drupal\Core\Cache\CacheableDependencyInterface|mixed $other_object
|
||||
* The dependency. If the object implements CacheableDependencyInterface,
|
||||
* then its cacheability metadata will be used. Otherwise, the passed in
|
||||
* object must be assumed to be uncacheable, so max-age 0 is set.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function addCacheableDependency($other_object) {
|
||||
if ($other_object instanceof CacheableDependencyInterface) {
|
||||
$this->addCacheTags($other_object->getCacheTags());
|
||||
$this->addCacheContexts($other_object->getCacheContexts());
|
||||
if ($this->maxAge === Cache::PERMANENT) {
|
||||
$this->maxAge = $other_object->getCacheMaxAge();
|
||||
}
|
||||
elseif (($max_age = $other_object->getCacheMaxAge()) && $max_age !== Cache::PERMANENT) {
|
||||
$this->maxAge = Cache::mergeMaxAges($this->maxAge, $max_age);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Not a cacheable dependency, this can not be cached.
|
||||
$this->maxAge = 0;
|
||||
}
|
||||
|
||||
$this->cacheMaxAge = $max_age;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
@ -175,34 +99,34 @@ class CacheableMetadata implements CacheableDependencyInterface {
|
|||
|
||||
// This is called many times per request, so avoid merging unless absolutely
|
||||
// necessary.
|
||||
if (empty($this->contexts)) {
|
||||
$result->contexts = $other->contexts;
|
||||
if (empty($this->cacheContexts)) {
|
||||
$result->cacheContexts = $other->cacheContexts;
|
||||
}
|
||||
elseif (empty($other->contexts)) {
|
||||
$result->contexts = $this->contexts;
|
||||
elseif (empty($other->cacheContexts)) {
|
||||
$result->cacheContexts = $this->cacheContexts;
|
||||
}
|
||||
else {
|
||||
$result->contexts = Cache::mergeContexts($this->contexts, $other->contexts);
|
||||
$result->cacheContexts = Cache::mergeContexts($this->cacheContexts, $other->cacheContexts);
|
||||
}
|
||||
|
||||
if (empty($this->tags)) {
|
||||
$result->tags = $other->tags;
|
||||
if (empty($this->cacheTags)) {
|
||||
$result->cacheTags = $other->cacheTags;
|
||||
}
|
||||
elseif (empty($other->tags)) {
|
||||
$result->tags = $this->tags;
|
||||
elseif (empty($other->cacheTags)) {
|
||||
$result->cacheTags = $this->cacheTags;
|
||||
}
|
||||
else {
|
||||
$result->tags = Cache::mergeTags($this->tags, $other->tags);
|
||||
$result->cacheTags = Cache::mergeTags($this->cacheTags, $other->cacheTags);
|
||||
}
|
||||
|
||||
if ($this->maxAge === Cache::PERMANENT) {
|
||||
$result->maxAge = $other->maxAge;
|
||||
if ($this->cacheMaxAge === Cache::PERMANENT) {
|
||||
$result->cacheMaxAge = $other->cacheMaxAge;
|
||||
}
|
||||
elseif ($other->maxAge === Cache::PERMANENT) {
|
||||
$result->maxAge = $this->maxAge;
|
||||
elseif ($other->cacheMaxAge === Cache::PERMANENT) {
|
||||
$result->cacheMaxAge = $this->cacheMaxAge;
|
||||
}
|
||||
else {
|
||||
$result->maxAge = Cache::mergeMaxAges($this->maxAge, $other->maxAge);
|
||||
$result->cacheMaxAge = Cache::mergeMaxAges($this->cacheMaxAge, $other->cacheMaxAge);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
@ -214,9 +138,9 @@ class CacheableMetadata implements CacheableDependencyInterface {
|
|||
* A render array.
|
||||
*/
|
||||
public function applyTo(array &$build) {
|
||||
$build['#cache']['contexts'] = $this->contexts;
|
||||
$build['#cache']['tags'] = $this->tags;
|
||||
$build['#cache']['max-age'] = $this->maxAge;
|
||||
$build['#cache']['contexts'] = $this->cacheContexts;
|
||||
$build['#cache']['tags'] = $this->cacheTags;
|
||||
$build['#cache']['max-age'] = $this->cacheMaxAge;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -229,9 +153,9 @@ class CacheableMetadata implements CacheableDependencyInterface {
|
|||
*/
|
||||
public static function createFromRenderArray(array $build) {
|
||||
$meta = new static();
|
||||
$meta->contexts = (isset($build['#cache']['contexts'])) ? $build['#cache']['contexts'] : [];
|
||||
$meta->tags = (isset($build['#cache']['tags'])) ? $build['#cache']['tags'] : [];
|
||||
$meta->maxAge = (isset($build['#cache']['max-age'])) ? $build['#cache']['max-age'] : Cache::PERMANENT;
|
||||
$meta->cacheContexts = (isset($build['#cache']['contexts'])) ? $build['#cache']['contexts'] : [];
|
||||
$meta->cacheTags = (isset($build['#cache']['tags'])) ? $build['#cache']['tags'] : [];
|
||||
$meta->cacheMaxAge = (isset($build['#cache']['max-age'])) ? $build['#cache']['max-age'] : Cache::PERMANENT;
|
||||
return $meta;
|
||||
}
|
||||
|
||||
|
@ -249,16 +173,16 @@ class CacheableMetadata implements CacheableDependencyInterface {
|
|||
public static function createFromObject($object) {
|
||||
if ($object instanceof CacheableDependencyInterface) {
|
||||
$meta = new static();
|
||||
$meta->contexts = $object->getCacheContexts();
|
||||
$meta->tags = $object->getCacheTags();
|
||||
$meta->maxAge = $object->getCacheMaxAge();
|
||||
$meta->cacheContexts = $object->getCacheContexts();
|
||||
$meta->cacheTags = $object->getCacheTags();
|
||||
$meta->cacheMaxAge = $object->getCacheMaxAge();
|
||||
return $meta;
|
||||
}
|
||||
|
||||
// Objects that don't implement CacheableDependencyInterface must be assumed
|
||||
// to be uncacheable, so set max-age 0.
|
||||
$meta = new static();
|
||||
$meta->maxAge = 0;
|
||||
$meta->cacheMaxAge = 0;
|
||||
return $meta;
|
||||
}
|
||||
|
||||
|
|
|
@ -39,6 +39,15 @@ namespace Drupal\Core\Cache;
|
|||
* Because this backend will mark all the cache entries in a bin as out-dated
|
||||
* for each write to a bin, it is best suited to bins with fewer changes.
|
||||
*
|
||||
* Note that this is designed specifically for combining a fast inconsistent
|
||||
* cache backend with a slower consistent cache back-end. To still function
|
||||
* correctly, it needs to do a consistency check (see the "last write timestamp"
|
||||
* logic). This contrasts with \Drupal\Core\Cache\BackendChain, which assumes
|
||||
* both chained cache backends are consistent, thus a consistency check being
|
||||
* pointless.
|
||||
*
|
||||
* @see \Drupal\Core\Cache\BackendChain
|
||||
*
|
||||
* @ingroup cache
|
||||
*/
|
||||
class ChainedFastBackend implements CacheBackendInterface, CacheTagsInvalidatorInterface {
|
||||
|
|
46
core/lib/Drupal/Core/Cache/Context/PathCacheContext.php
Normal file
46
core/lib/Drupal/Core/Cache/Context/PathCacheContext.php
Normal file
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Core\Cache\Context\PathCacheContext.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\Cache\Context;
|
||||
|
||||
use Drupal\Core\Cache\CacheableMetadata;
|
||||
|
||||
/**
|
||||
* Defines the PathCacheContext service, for "per URL path" caching.
|
||||
*
|
||||
* Cache context ID: 'url.path'.
|
||||
*
|
||||
* (This allows for caching relative URLs.)
|
||||
*
|
||||
* @see \Symfony\Component\HttpFoundation\Request::getBasePath()
|
||||
* @see \Symfony\Component\HttpFoundation\Request::getPathInfo()
|
||||
*/
|
||||
class PathCacheContext extends RequestStackCacheContextBase implements CacheContextInterface {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getLabel() {
|
||||
return t('Path');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getContext() {
|
||||
$request = $this->requestStack->getCurrentRequest();
|
||||
return $request->getBasePath() . $request->getPathInfo();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheableMetadata() {
|
||||
return new CacheableMetadata();
|
||||
}
|
||||
|
||||
}
|
|
@ -147,17 +147,26 @@ class DatabaseBackend implements CacheBackendInterface {
|
|||
}
|
||||
|
||||
/**
|
||||
* Implements Drupal\Core\Cache\CacheBackendInterface::set().
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function set($cid, $data, $expire = Cache::PERMANENT, array $tags = array()) {
|
||||
Cache::validateTags($tags);
|
||||
$tags = array_unique($tags);
|
||||
// Sort the cache tags so that they are stored consistently in the database.
|
||||
sort($tags);
|
||||
$this->setMultiple([
|
||||
$cid => [
|
||||
'data' => $data,
|
||||
'expire' => $expire,
|
||||
'tags' => $tags,
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setMultiple(array $items) {
|
||||
$try_again = FALSE;
|
||||
try {
|
||||
// The bin might not yet exist.
|
||||
$this->doSet($cid, $data, $expire, $tags);
|
||||
$this->doSetMultiple($items);
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
// If there was an exception, try to create the bins.
|
||||
|
@ -169,39 +178,19 @@ class DatabaseBackend implements CacheBackendInterface {
|
|||
}
|
||||
// Now that the bin has been created, try again if necessary.
|
||||
if ($try_again) {
|
||||
$this->doSet($cid, $data, $expire, $tags);
|
||||
$this->doSetMultiple($items);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Actually set the cache.
|
||||
* Stores multiple items in the persistent cache.
|
||||
*
|
||||
* @param array $items
|
||||
* An array of cache items, keyed by cid.
|
||||
*
|
||||
* @see \Drupal\Core\Cache\CacheBackendInterface::setMultiple()
|
||||
*/
|
||||
protected function doSet($cid, $data, $expire, $tags) {
|
||||
$fields = array(
|
||||
'created' => round(microtime(TRUE), 3),
|
||||
'expire' => $expire,
|
||||
'tags' => implode(' ', $tags),
|
||||
'checksum' => $this->checksumProvider->getCurrentChecksum($tags),
|
||||
);
|
||||
if (!is_string($data)) {
|
||||
$fields['data'] = serialize($data);
|
||||
$fields['serialized'] = 1;
|
||||
}
|
||||
else {
|
||||
$fields['data'] = $data;
|
||||
$fields['serialized'] = 0;
|
||||
}
|
||||
|
||||
$this->connection->merge($this->bin)
|
||||
->key('cid', $this->normalizeCid($cid))
|
||||
->fields($fields)
|
||||
->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setMultiple(array $items) {
|
||||
protected function doSetMultiple(array $items) {
|
||||
$values = array();
|
||||
|
||||
foreach ($items as $cid => $item) {
|
||||
|
@ -216,7 +205,7 @@ class DatabaseBackend implements CacheBackendInterface {
|
|||
sort($item['tags']);
|
||||
|
||||
$fields = array(
|
||||
'cid' => $cid,
|
||||
'cid' => $this->normalizeCid($cid),
|
||||
'expire' => $item['expire'],
|
||||
'created' => round(microtime(TRUE), 3),
|
||||
'tags' => implode(' ', $item['tags']),
|
||||
|
@ -234,34 +223,20 @@ class DatabaseBackend implements CacheBackendInterface {
|
|||
$values[] = $fields;
|
||||
}
|
||||
|
||||
// Use a transaction so that the database can write the changes in a single
|
||||
// commit. The transaction is started after calculating the tag checksums
|
||||
// since that can create a table and this causes an exception when using
|
||||
// PostgreSQL.
|
||||
$transaction = $this->connection->startTransaction();
|
||||
|
||||
try {
|
||||
// Delete all items first so we can do one insert. Rather than multiple
|
||||
// merge queries.
|
||||
$this->deleteMultiple(array_keys($items));
|
||||
|
||||
$query = $this->connection
|
||||
->insert($this->bin)
|
||||
->fields(array('cid', 'expire', 'created', 'tags', 'checksum', 'data', 'serialized'));
|
||||
foreach ($values as $fields) {
|
||||
// Only pass the values since the order of $fields matches the order of
|
||||
// the insert fields. This is a performance optimization to avoid
|
||||
// unnecessary loops within the method.
|
||||
$query->values(array_values($fields));
|
||||
}
|
||||
|
||||
$query->execute();
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
$transaction->rollback();
|
||||
// @todo Log something here or just re throw?
|
||||
throw $e;
|
||||
// Use an upsert query which is atomic and optimized for multiple-row
|
||||
// merges.
|
||||
$query = $this->connection
|
||||
->upsert($this->bin)
|
||||
->key('cid')
|
||||
->fields(array('cid', 'expire', 'created', 'tags', 'checksum', 'data', 'serialized'));
|
||||
foreach ($values as $fields) {
|
||||
// Only pass the values since the order of $fields matches the order of
|
||||
// the insert fields. This is a performance optimization to avoid
|
||||
// unnecessary loops within the method.
|
||||
$query->values(array_values($fields));
|
||||
}
|
||||
|
||||
$query->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -217,4 +217,13 @@ class MemoryBackend implements CacheBackendInterface, CacheTagsInvalidatorInterf
|
|||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset statically cached variables.
|
||||
*
|
||||
* This is only used by tests.
|
||||
*/
|
||||
public function reset() {
|
||||
$this->cache = [];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ trait RefinableCacheableDependencyTrait {
|
|||
}
|
||||
else {
|
||||
// Not a cacheable dependency, this can not be cached.
|
||||
$this->maxAge = 0;
|
||||
$this->cacheMaxAge = 0;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
@ -53,7 +53,9 @@ trait RefinableCacheableDependencyTrait {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function addCacheContexts(array $cache_contexts) {
|
||||
$this->cacheContexts = Cache::mergeContexts($this->cacheContexts, $cache_contexts);
|
||||
if ($cache_contexts) {
|
||||
$this->cacheContexts = Cache::mergeContexts($this->cacheContexts, $cache_contexts);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
@ -61,7 +63,9 @@ trait RefinableCacheableDependencyTrait {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function addCacheTags(array $cache_tags) {
|
||||
$this->cacheTags = Cache::mergeTags($this->cacheTags, $cache_tags);
|
||||
if ($cache_tags) {
|
||||
$this->cacheTags = Cache::mergeTags($this->cacheTags, $cache_tags);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
|
Reference in a new issue