Update to Drupal 8.0.0-beta15. For more information, see: https://www.drupal.org/node/2563023

This commit is contained in:
Pantheon Automation 2015-09-04 13:20:09 -07:00 committed by Greg Anderson
parent 2720a9ec4b
commit f3791f1da3
1898 changed files with 54300 additions and 11481 deletions

View file

@ -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
*/

View 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;
}

View file

@ -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;
}

View file

@ -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 {

View 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();
}
}

View file

@ -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();
}
/**

View file

@ -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 = [];
}
}

View file

@ -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;
}