Mercurial > hg > isophonics-drupal-site
view core/lib/Drupal/Core/Render/BubbleableMetadata.php @ 13:5fb285c0d0e3
Update Drupal core to 8.4.7 via Composer. Security update; I *think* we've
been lucky to get away with this so far, as we don't support self-registration
which seems to be used by the so-called "drupalgeddon 2" attack that 8.4.5
was vulnerable to.
author | Chris Cannam |
---|---|
date | Mon, 23 Apr 2018 09:33:26 +0100 |
parents | 4c8ae668cc8c |
children |
line wrap: on
line source
<?php 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([$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; } }