Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
Total | |
0.00% |
0 / 1 |
|
66.67% |
4 / 6 |
CRAP | |
86.11% |
31 / 36 |
BubbleableMetadata | |
0.00% |
0 / 1 |
|
66.67% |
4 / 6 |
18.87 | |
86.11% |
31 / 36 |
merge | |
0.00% |
0 / 1 |
4.03 | |
87.50% |
7 / 8 |
|||
applyTo | |
100.00% |
1 / 1 |
1 | |
100.00% |
3 / 3 |
|||
createFromRenderArray | |
100.00% |
1 / 1 |
2 | |
100.00% |
3 / 3 |
|||
createFromObject | |
100.00% |
1 / 1 |
2 | |
100.00% |
4 / 4 |
|||
addCacheableDependency | |
100.00% |
1 / 1 |
2 | |
100.00% |
4 / 4 |
|||
mergeAttachments | |
0.00% |
0 / 1 |
8.14 | |
71.43% |
10 / 14 |
<?php | |
/** | |
* @file | |
* Contains \Drupal\Core\Render\BubbleableMetadata. | |
*/ | |
namespace Drupal\Core\Render; | |
use Drupal\Component\Utility\NestedArray; | |
use Drupal\Core\Cache\CacheableMetadata; | |
/** | |
* Value object used for bubbleable rendering metadata. | |
* | |
* @see \Drupal\Core\Render\RendererInterface::render() | |
*/ | |
class BubbleableMetadata extends CacheableMetadata implements AttachmentsInterface { | |
use AttachmentsTrait; | |
/** | |
* Merges the values of another bubbleable metadata object with this one. | |
* | |
* @param \Drupal\Core\Cache\CacheableMetadata $other | |
* The other bubbleable metadata object. | |
* | |
* @return static | |
* A new bubbleable metadata object, with the merged data. | |
*/ | |
public function merge(CacheableMetadata $other) { | |
$result = parent::merge($other); | |
// This is called many times per request, so avoid merging unless absolutely | |
// necessary. | |
if ($other instanceof BubbleableMetadata) { | |
if (empty($this->attachments)) { | |
$result->attachments = $other->attachments; | |
} | |
elseif (empty($other->attachments)) { | |
$result->attachments = $this->attachments; | |
} | |
else { | |
$result->attachments = static::mergeAttachments($this->attachments, $other->attachments); | |
} | |
} | |
return $result; | |
} | |
/** | |
* Applies the values of this bubbleable metadata object to a render array. | |
* | |
* @param array &$build | |
* A render array. | |
*/ | |
public function applyTo(array &$build) { | |
parent::applyTo($build); | |
$build['#attached'] = $this->attachments; | |
} | |
/** | |
* Creates a bubbleable metadata object with values taken from a render array. | |
* | |
* @param array $build | |
* A render array. | |
* | |
* @return static | |
*/ | |
public static function createFromRenderArray(array $build) { | |
$meta = parent::createFromRenderArray($build); | |
$meta->attachments = (isset($build['#attached'])) ? $build['#attached'] : []; | |
return $meta; | |
} | |
/** | |
* Creates a bubbleable metadata object from a depended object. | |
* | |
* @param \Drupal\Core\Cache\CacheableDependencyInterface|mixed $object | |
* The object whose cacheability metadata to retrieve. If it implements | |
* CacheableDependencyInterface, its cacheability metadata will be used, | |
* otherwise, the passed in object must be assumed to be uncacheable, so | |
* max-age 0 is set. | |
* | |
* @return static | |
*/ | |
public static function createFromObject($object) { | |
$meta = parent::createFromObject($object); | |
if ($object instanceof AttachmentsInterface) { | |
$meta->attachments = $object->getAttachments(); | |
} | |
return $meta; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function addCacheableDependency($other_object) { | |
parent::addCacheableDependency($other_object); | |
if ($other_object instanceof AttachmentsInterface) { | |
$this->addAttachments($other_object->getAttachments()); | |
} | |
return $this; | |
} | |
/** | |
* Merges two attachments arrays (which live under the '#attached' key). | |
* | |
* The values under the 'drupalSettings' key are merged in a special way, to | |
* match the behavior of: | |
* | |
* @code | |
* jQuery.extend(true, {}, $settings_items[0], $settings_items[1], ...) | |
* @endcode | |
* | |
* This means integer indices are preserved just like string indices are, | |
* rather than re-indexed as is common in PHP array merging. | |
* | |
* Example: | |
* @code | |
* function module1_page_attachments(&$page) { | |
* $page['a']['#attached']['drupalSettings']['foo'] = ['a', 'b', 'c']; | |
* } | |
* function module2_page_attachments(&$page) { | |
* $page['#attached']['drupalSettings']['foo'] = ['d']; | |
* } | |
* // When the page is rendered after the above code, and the browser runs the | |
* // resulting <SCRIPT> tags, the value of drupalSettings.foo is | |
* // ['d', 'b', 'c'], not ['a', 'b', 'c', 'd']. | |
* @endcode | |
* | |
* By following jQuery.extend() merge logic rather than common PHP array merge | |
* logic, the following are ensured: | |
* - Attaching JavaScript settings is idempotent: attaching the same settings | |
* twice does not change the output sent to the browser. | |
* - If pieces of the page are rendered in separate PHP requests and the | |
* returned settings are merged by JavaScript, the resulting settings are | |
* the same as if rendered in one PHP request and merged by PHP. | |
* | |
* @param array $a | |
* An attachments array. | |
* @param array $b | |
* Another attachments array. | |
* | |
* @return array | |
* The merged attachments array. | |
*/ | |
public static function mergeAttachments(array $a, array $b) { | |
// If both #attached arrays contain drupalSettings, then merge them | |
// correctly; adding the same settings multiple times needs to behave | |
// idempotently. | |
if (!empty($a['drupalSettings']) && !empty($b['drupalSettings'])) { | |
$drupalSettings = NestedArray::mergeDeepArray(array($a['drupalSettings'], $b['drupalSettings']), TRUE); | |
// No need for re-merging them. | |
unset($a['drupalSettings']); | |
unset($b['drupalSettings']); | |
} | |
// Optimize merging of placeholders: no need for deep merging. | |
if (!empty($a['placeholders']) && !empty($b['placeholders'])) { | |
$placeholders = $a['placeholders'] + $b['placeholders']; | |
// No need for re-merging them. | |
unset($a['placeholders']); | |
unset($b['placeholders']); | |
} | |
// Apply the normal merge. | |
$a = array_merge_recursive($a, $b); | |
if (isset($drupalSettings)) { | |
// Save the custom merge for the drupalSettings. | |
$a['drupalSettings'] = $drupalSettings; | |
} | |
if (isset($placeholders)) { | |
// Save the custom merge for the placeholders. | |
$a['placeholders'] = $placeholders; | |
} | |
return $a; | |
} | |
} |