placeholderGenerator = $placeholder_generator; } /** * {@inheritdoc} */ public function get(array $elements) { // @todo remove this check when https://www.drupal.org/node/2367555 lands. if (!$this->requestStack->getCurrentRequest()->isMethodSafe()) { return FALSE; } // When rendering placeholders, special case auto-placeholdered elements: // avoid retrieving them from cache again, or rendering them again. if (isset($elements['#create_placeholder']) && $elements['#create_placeholder'] === FALSE) { $cached_placeholder_result = $this->getFromPlaceholderResultsCache($elements); if ($cached_placeholder_result !== FALSE) { return $cached_placeholder_result; } } $cached_element = parent::get($elements); if ($cached_element === FALSE) { return FALSE; } else { if ($this->placeholderGenerator->canCreatePlaceholder($elements) && $this->placeholderGenerator->shouldAutomaticallyPlaceholder($cached_element)) { return $this->createPlaceholderAndRemember($cached_element, $elements); } return $cached_element; } } /** * {@inheritdoc} */ public function set(array &$elements, array $pre_bubbling_elements) { $result = parent::set($elements, $pre_bubbling_elements); // @todo remove this check when https://www.drupal.org/node/2367555 lands. if (!$this->requestStack->getCurrentRequest()->isMethodSafe()) { return FALSE; } if ($this->placeholderGenerator->canCreatePlaceholder($pre_bubbling_elements) && $this->placeholderGenerator->shouldAutomaticallyPlaceholder($elements)) { // Overwrite $elements with a placeholder. The Renderer (which called this // method) will update the context with the bubbleable metadata of the // overwritten $elements. $elements = $this->createPlaceholderAndRemember($this->getCacheableRenderArray($elements), $pre_bubbling_elements); } return $result; } /** * Create a placeholder for a renderable array and remember in a static cache. * * @param array $rendered_elements * A fully rendered renderable array. * @param array $pre_bubbling_elements * A renderable array corresponding to the state (in particular, the * cacheability metadata) of $rendered_elements prior to the beginning of * its rendering process, and therefore before any bubbling of child * information has taken place. Only the #cache property is used by this * function, so the caller may omit all other properties and children from * this array. * * @return array * Renderable array with placeholder markup and the attached placeholder * replacement metadata. */ protected function createPlaceholderAndRemember(array $rendered_elements, array $pre_bubbling_elements) { $placeholder_element = $this->placeholderGenerator->createPlaceholder($pre_bubbling_elements); // Remember the result for this placeholder to avoid double work. $placeholder = (string) $placeholder_element['#markup']; $this->placeholderResultsCache[$placeholder] = $rendered_elements; return $placeholder_element; } /** * Retrieves an auto-placeholdered renderable array from the static cache. * * @param array $elements * A renderable array. * * @return array|false * A renderable array, with the original element and all its children pre- * rendered, or FALSE if no cached copy of the element is available. */ protected function getFromPlaceholderResultsCache(array $elements) { $placeholder_element = $this->placeholderGenerator->createPlaceholder($elements); $placeholder = (string) $placeholder_element['#markup']; if (isset($this->placeholderResultsCache[$placeholder])) { return $this->placeholderResultsCache[$placeholder]; } return FALSE; } }