core/lib/Drupal/Core/Entity/EntityViewBuilder.php | 18 +- .../lib/Drupal/system/Tests/Common/RenderTest.php | 448 ++++++++++----------- 2 files changed, 227 insertions(+), 239 deletions(-) diff --git a/core/lib/Drupal/Core/Entity/EntityViewBuilder.php b/core/lib/Drupal/Core/Entity/EntityViewBuilder.php index a2efcb4..09208a2 100644 --- a/core/lib/Drupal/Core/Entity/EntityViewBuilder.php +++ b/core/lib/Drupal/Core/Entity/EntityViewBuilder.php @@ -15,7 +15,6 @@ use Drupal\Core\Language\LanguageManagerInterface; use Drupal\Core\TypedData\TranslatableInterface; use Drupal\entity\Entity\EntityViewDisplay; -use Drupal\Component\Utility\NestedArray; use Symfony\Component\DependencyInjection\ContainerInterface; /** @@ -92,9 +91,6 @@ public static function createInstance(ContainerInterface $container, EntityTypeI public function buildContent(array &$build, array $entities, array $displays, $view_mode, $langcode = NULL) { $entities_by_bundle = array(); foreach ($entities as $id => $entity) { - $build += array( - '#view_mode' => $view_mode, - ); // Initialize the field item attributes for the fields being displayed. // The entity can include fields that are not displayed, and the display // can include components that are not fields, so we want to act on the @@ -119,7 +115,7 @@ public function buildContent(array &$build, array $entities, array $displays, $v foreach ($entities_by_bundle as $bundle => $bundle_entities) { $display_build = $displays[$bundle]->buildMultiple($bundle_entities); foreach ($bundle_entities as $id => $entity) { - $build[$id] = NestedArray::mergeDeepArray(array($build[$id], array('#view_mode' => $view_mode), $display_build[$id]), TRUE); + $build[$id] = array_merge($build[$id], $display_build[$id]); } } } @@ -145,6 +141,7 @@ protected function getBuildDefaults(EntityInterface $entity, $view_mode, $langco $return = array( '#theme' => $this->entityTypeId, '#pre_render' => array(array($this, 'entityViewBuilderBuildView')), + '#entity' => $entity, "#{$this->entityTypeId}" => $entity, '#view_mode' => $view_mode, '#langcode' => $langcode, @@ -265,23 +262,16 @@ public function viewMultiple(array $entities = array(), $view_mode = 'full', $la $langcode = $this->languageManager->getCurrentLanguage(Language::TYPE_CONTENT)->id; } - // Build the view modes and display objects. $build = array('#sorted' => TRUE); $weight = 0; - foreach ($entities as $key => $entity) { - $entityType = "{$this->entityTypeId}"; // Ensure that from now on we are dealing with the proper translation // object. $entity = $this->entityManager->getTranslationFromContext($entity, $langcode); - $entities[$key] = $entity; - - $build[$key] = array( - '#entity' => $entity - ); // Set defaults for #pre_render. - $build[$key] += $this->getBuildDefaults($entity, $view_mode, $langcode); + $build[$key] = $this->getBuildDefaults($entity, $view_mode, $langcode); + $entityType = "{$this->entityTypeId}"; \Drupal::moduleHandler()->alter(array($entityType . '_defaults', 'entity_defaults'), $build[$key], $entity, $view_mode, $langcode); $build[$key]['#weight'] = $weight++; diff --git a/core/modules/system/lib/Drupal/system/Tests/Common/RenderTest.php b/core/modules/system/lib/Drupal/system/Tests/Common/RenderTest.php index 7e0b782..5bb7b0b 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Common/RenderTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Common/RenderTest.php @@ -543,6 +543,229 @@ function testDrupalRenderPostRenderCache() { } /** + * Tests post-render cache callbacks functionality in children elements. + */ + function testDrupalRenderChildrenPostRenderCache() { + // The cache system is turned off for POST requests. + $request_method = \Drupal::request()->getMethod(); + \Drupal::request()->setMethod('GET'); + + // Test case 1. + // Create an element with a child and subchild. Each element has the same + // #post_render_cache callback, but with different contexts. + drupal_static_reset('_drupal_add_js'); + $context_1 = array('foo' => $this->randomContextValue()); + $context_2 = array('bar' => $this->randomContextValue()); + $context_3 = array('baz' => $this->randomContextValue()); + $test_element = array( + '#type' => 'details', + '#open' => TRUE, + '#cache' => array( + 'keys' => array('simpletest', 'drupal_render', 'children_post_render_cache'), + ), + '#post_render_cache' => array( + 'common_test_post_render_cache' => array($context_1) + ), + '#title' => 'Parent', + '#attached' => array( + 'js' => array( + array('type' => 'setting', 'data' => array('foo' => 'bar')) + ), + ), + ); + $test_element['child'] = array( + '#type' => 'details', + '#open' => TRUE, + '#post_render_cache' => array( + 'common_test_post_render_cache' => array($context_2) + ), + '#title' => 'Child', + ); + $test_element['child']['subchild'] = array( + '#post_render_cache' => array( + 'common_test_post_render_cache' => array($context_3) + ), + '#markup' => 'Subchild', + ); + $element = $test_element; + $output = drupal_render($element); + $this->assertIdentical($output, '

overridden

', 'Output is overridden.'); + $this->assertTrue(isset($element['#printed']), 'No cache hit'); + $this->assertIdentical($element['#markup'], '

overridden

', '#markup is overridden.'); + $settings = $this->parseDrupalSettings(drupal_get_js()); + $expected_settings = $context_1 + $context_2 + $context_3; + $this->assertIdentical($settings['foo'], 'bar', 'Original JavaScript setting is added to the page.'); + $this->assertIdentical($settings['common_test'], $expected_settings, '#attached is modified; JavaScript settings for each #post_render_cache callback are added to page.'); + + // GET request: validate cached data. + $element = array('#cache' => $element['#cache']); + $cached_element = \Drupal::cache('render')->get(drupal_render_cid_create($element))->data; + $expected_element = array( + '#attached' => array( + 'js' => array( + array('type' => 'setting', 'data' => array('foo' => 'bar')) + ), + 'library' => array( + 'core/drupal.collapse', + 'core/drupal.collapse', + ), + ), + '#post_render_cache' => array( + 'common_test_post_render_cache' => array( + $context_1, + $context_2, + $context_3, + ) + ), + '#cache' => array('tags' => array()), + ); + + $dom = Html::load($cached_element['#markup']); + $xpath = new \DOMXPath($dom); + $parent = $xpath->query('//details[@class="form-wrapper" and @open="open"]/summary[@role="button" and @aria-expanded and text()="Parent"]')->length; + $child = $xpath->query('//details[@class="form-wrapper" and @open="open"]/div[@class="details-wrapper"]/details[@class="form-wrapper" and @open="open"]/summary[@role="button" and @aria-expanded and text()="Child"]')->length; + $subchild = $xpath->query('//details[@class="form-wrapper" and @open="open"]/div[@class="details-wrapper"]/details[@class="form-wrapper" and @open="open"]/div [@class="details-wrapper" and text()="Subchild"]')->length; + $this->assertTrue($parent && $child && $subchild, 'The correct data is cached: the stored #markup is not affected by #post_render_cache callbacks.'); + + // Remove markup because it's compared above in the xpath. + unset($cached_element['#markup']); + $this->assertIdentical($cached_element, $expected_element, 'The correct data is cached: the stored #attached properties are not affected by #post_render_cache callbacks.'); + + // GET request: #cache enabled, cache hit. + drupal_static_reset('_drupal_add_js'); + $element = $test_element; + $output = drupal_render($element); + $this->assertIdentical($output, '

overridden

', 'Output is overridden.'); + $this->assertFalse(isset($element['#printed']), 'Cache hit'); + $settings = $this->parseDrupalSettings(drupal_get_js()); + $this->assertIdentical($settings['foo'], 'bar', 'Original JavaScript setting is added to the page.'); + $this->assertIdentical($settings['common_test'], $expected_settings, '#attached is modified; JavaScript settings for each #post_render_cache callback are added to page.'); + + // Test case 2. + // Use the exact same element, but now unset #cache. + drupal_static_reset('drupal_add_js'); + unset($test_element['#cache']); + $element = $test_element; + $output = drupal_render($element); + $this->assertIdentical($output, '

overridden

', 'Output is overridden.'); + $this->assertIdentical($element['#markup'], '

overridden

', '#markup is overridden.'); + $settings = $this->parseDrupalSettings(drupal_get_js()); + $expected_settings = $context_1 + $context_2 + $context_3; + $this->assertIdentical($settings['foo'], 'bar', 'Original JavaScript setting is added to the page.'); + $this->assertIdentical($settings['common_test'], $expected_settings, '#attached is modified; JavaScript settings for each #post_render_cache callback are added to page.'); + + // Test case 3. + // Create an element with a child and subchild. Each element has the same + // #post_render_cache callback, but with different contexts. Both the + // parent and the child elements have #cache set. The cached parent element + // must contain the pristine child element, i.e. unaffected by its + // #post_render_cache callbacks. I.e. the #post_render_cache callbacks may + // not yet have run, or otherwise the cached parent element would contain + // personalized data, thereby breaking the render cache. + drupal_static_reset('_drupal_add_js'); + $element = $test_element; + $element['#cache']['keys'] = array('simpletest', 'drupal_render', 'children_post_render_cache', 'nested_cache_parent'); + $element['child']['#cache']['keys'] = array('simpletest', 'drupal_render', 'children_post_render_cache', 'nested_cache_child'); + $output = drupal_render($element); + $this->assertIdentical($output, '

overridden

', 'Output is overridden.'); + $this->assertTrue(isset($element['#printed']), 'No cache hit'); + $this->assertIdentical($element['#markup'], '

overridden

', '#markup is overridden.'); + $settings = $this->parseDrupalSettings(drupal_get_js()); + $expected_settings = $context_1 + $context_2 + $context_3; + $this->assertIdentical($settings['foo'], 'bar', 'Original JavaScript setting is added to the page.'); + $this->assertIdentical($settings['common_test'], $expected_settings, '#attached is modified; JavaScript settings for each #post_render_cache callback are added to page.'); + + // GET request: validate cached data for both the parent and child. + $element = $test_element; + $element['#cache']['keys'] = array('simpletest', 'drupal_render', 'children_post_render_cache', 'nested_cache_parent'); + $element['child']['#cache']['keys'] = array('simpletest', 'drupal_render', 'children_post_render_cache', 'nested_cache_child'); + $cached_parent_element = \Drupal::cache('render')->get(drupal_render_cid_create($element))->data; + $cached_child_element = \Drupal::cache('render')->get(drupal_render_cid_create($element['child']))->data; + $expected_parent_element = array( + '#attached' => array( + 'js' => array( + array('type' => 'setting', 'data' => array('foo' => 'bar')) + ), + 'library' => array( + 'core/drupal.collapse', + 'core/drupal.collapse', + ), + ), + '#post_render_cache' => array( + 'common_test_post_render_cache' => array( + $context_1, + $context_2, + $context_3, + ) + ), + '#cache' => array('tags' => array()), + ); + + $dom = Html::load($cached_parent_element['#markup']); + $xpath = new \DOMXPath($dom); + $parent = $xpath->query('//details[@class="form-wrapper" and @open="open"]/summary[@role="button" and @aria-expanded and text()="Parent"]')->length; + $child = $xpath->query('//details[@class="form-wrapper" and @open="open"]/div[@class="details-wrapper"]/details[@class="form-wrapper" and @open="open"]/summary[@role="button" and @aria-expanded and text()="Child"]')->length; + $subchild = $xpath->query('//details[@class="form-wrapper" and @open="open"]/div[@class="details-wrapper"]/details[@class="form-wrapper" and @open="open"]/div [@class="details-wrapper" and text()="Subchild"]')->length; + $this->assertTrue($parent && $child && $subchild, 'The correct data is cached for the parent: the stored #markup is not affected by #post_render_cache callbacks.'); + + // Remove markup because it's compared above in the xpath. + unset($cached_parent_element['#markup']); + $this->assertIdentical($cached_parent_element, $expected_parent_element, 'The correct data is cached for the parent: the stored #attached properties are not affected by #post_render_cache callbacks.'); + + $expected_child_element = array( + '#attached' => array( + 'library' => array( + 'core/drupal.collapse', + ), + ), + '#post_render_cache' => array( + 'common_test_post_render_cache' => array( + $context_2, + $context_3, + ) + ), + '#cache' => array('tags' => array()), + ); + + $dom = Html::load($cached_child_element['#markup']); + $xpath = new \DOMXPath($dom); + $child = $xpath->query('//details[@class="form-wrapper" and @open="open"]/summary[@role="button" and @aria-expanded and text()="Child"]')->length; + $subchild = $xpath->query('//details[@class="form-wrapper" and @open="open"]/div [@class="details-wrapper" and text()="Subchild"]')->length; + $this->assertTrue($child && $subchild, 'The correct data is cached for the child: the stored #markup is not affected by #post_render_cache callbacks.'); + + // Remove markup because it's compared above in the xpath. + unset($cached_child_element['#markup']); + $this->assertIdentical($cached_child_element, $expected_child_element, 'The correct data is cached for the child: the stored #attached properties are not affected by #post_render_cache callbacks.'); + + // GET request: #cache enabled, cache hit, parent element. + drupal_static_reset('_drupal_add_js'); + $element = $test_element; + $element['#cache']['keys'] = array('simpletest', 'drupal_render', 'children_post_render_cache', 'nested_cache_parent'); + $output = drupal_render($element); + $this->assertIdentical($output, '

overridden

', 'Output is overridden.'); + $this->assertFalse(isset($element['#printed']), 'Cache hit'); + $settings = $this->parseDrupalSettings(drupal_get_js()); + $this->assertIdentical($settings['foo'], 'bar', 'Original JavaScript setting is added to the page.'); + $this->assertIdentical($settings['common_test'], $expected_settings, '#attached is modified; JavaScript settings for each #post_render_cache callback are added to page.'); + + // GET request: #cache enabled, cache hit, child element. + drupal_static_reset('_drupal_add_js'); + $element = $test_element; + $element['child']['#cache']['keys'] = array('simpletest', 'drupal_render', 'children_post_render_cache', 'nested_cache_child'); + $element = $element['child']; + $output = drupal_render($element); + $this->assertIdentical($output, '

overridden

', 'Output is overridden.'); + $this->assertFalse(isset($element['#printed']), 'Cache hit'); + $settings = $this->parseDrupalSettings(drupal_get_js()); + $expected_settings = $context_2 + $context_3; + $this->assertTrue(!isset($settings['foo']), 'Parent JavaScript setting is not added to the page.'); + $this->assertIdentical($settings['common_test'], $expected_settings, '#attached is modified; JavaScript settings for each #post_render_cache callback are added to page.'); + + // Restore the previous request method. + \Drupal::request()->setMethod($request_method); + } + + /** * Tests post-render cache-integrated 'render_cache_placeholder' element. */ function testDrupalRenderRenderCachePlaceholder() { @@ -697,7 +920,6 @@ function testDrupalRenderChildElementRenderCachePlaceholder() { if ($nodes->length) { $token = $nodes->item(0)->getAttribute('token'); } - debug(array($token, $expected_token,), 'tokens', TRUE); $this->assertIdentical($token, $expected_token, 'The tokens are identical for the child element'); // Verify the token is in the cached element. $expected_element = array( @@ -709,7 +931,6 @@ function testDrupalRenderChildElementRenderCachePlaceholder() { ), '#cache' => array('tags' => array()), ); - debug(array($cached_element, $expected_element,), '', TRUE); $this->assertIdentical($cached_element, $expected_element, 'The correct data is cached for the child element: the stored #markup and #attached properties are not affected by #post_render_cache callbacks.'); // GET request: validate cached data (for the parent/entire render array). @@ -785,229 +1006,6 @@ function testDrupalRenderChildElementRenderCachePlaceholder() { \Drupal::request()->setMethod($request_method); } - /** - * Tests post-render cache callbacks functionality in children elements. - */ - function testDrupalRenderChildrenPostRenderCache() { - // The cache system is turned off for POST requests. - $request_method = \Drupal::request()->getMethod(); - \Drupal::request()->setMethod('GET'); - - // Test case 1. - // Create an element with a child and subchild. Each element has the same - // #post_render_cache callback, but with different contexts. - drupal_static_reset('_drupal_add_js'); - $context_1 = array('foo' => $this->randomContextValue()); - $context_2 = array('bar' => $this->randomContextValue()); - $context_3 = array('baz' => $this->randomContextValue()); - $test_element = array( - '#type' => 'details', - '#open' => TRUE, - '#cache' => array( - 'keys' => array('simpletest', 'drupal_render', 'children_post_render_cache'), - ), - '#post_render_cache' => array( - 'common_test_post_render_cache' => array($context_1) - ), - '#title' => 'Parent', - '#attached' => array( - 'js' => array( - array('type' => 'setting', 'data' => array('foo' => 'bar')) - ), - ), - ); - $test_element['child'] = array( - '#type' => 'details', - '#open' => TRUE, - '#post_render_cache' => array( - 'common_test_post_render_cache' => array($context_2) - ), - '#title' => 'Child', - ); - $test_element['child']['subchild'] = array( - '#post_render_cache' => array( - 'common_test_post_render_cache' => array($context_3) - ), - '#markup' => 'Subchild', - ); - $element = $test_element; - $output = drupal_render($element); - $this->assertIdentical($output, '

overridden

', 'Output is overridden.'); - $this->assertTrue(isset($element['#printed']), 'No cache hit'); - $this->assertIdentical($element['#markup'], '

overridden

', '#markup is overridden.'); - $settings = $this->parseDrupalSettings(drupal_get_js()); - $expected_settings = $context_1 + $context_2 + $context_3; - $this->assertIdentical($settings['foo'], 'bar', 'Original JavaScript setting is added to the page.'); - $this->assertIdentical($settings['common_test'], $expected_settings, '#attached is modified; JavaScript settings for each #post_render_cache callback are added to page.'); - - // GET request: validate cached data. - $element = array('#cache' => $element['#cache']); - $cached_element = \Drupal::cache('render')->get(drupal_render_cid_create($element))->data; - $expected_element = array( - '#attached' => array( - 'js' => array( - array('type' => 'setting', 'data' => array('foo' => 'bar')) - ), - 'library' => array( - 'core/drupal.collapse', - 'core/drupal.collapse', - ), - ), - '#post_render_cache' => array( - 'common_test_post_render_cache' => array( - $context_1, - $context_2, - $context_3, - ) - ), - '#cache' => array('tags' => array()), - ); - - $dom = Html::load($cached_element['#markup']); - $xpath = new \DOMXPath($dom); - $parent = $xpath->query('//details[@class="form-wrapper" and @open="open"]/summary[@role="button" and @aria-expanded and text()="Parent"]')->length; - $child = $xpath->query('//details[@class="form-wrapper" and @open="open"]/div[@class="details-wrapper"]/details[@class="form-wrapper" and @open="open"]/summary[@role="button" and @aria-expanded and text()="Child"]')->length; - $subchild = $xpath->query('//details[@class="form-wrapper" and @open="open"]/div[@class="details-wrapper"]/details[@class="form-wrapper" and @open="open"]/div [@class="details-wrapper" and text()="Subchild"]')->length; - $this->assertTrue($parent && $child && $subchild, 'The correct data is cached: the stored #markup is not affected by #post_render_cache callbacks.'); - - // Remove markup because it's compared above in the xpath. - unset($cached_element['#markup']); - $this->assertIdentical($cached_element, $expected_element, 'The correct data is cached: the stored #attached properties are not affected by #post_render_cache callbacks.'); - - // GET request: #cache enabled, cache hit. - drupal_static_reset('_drupal_add_js'); - $element = $test_element; - $output = drupal_render($element); - $this->assertIdentical($output, '

overridden

', 'Output is overridden.'); - $this->assertFalse(isset($element['#printed']), 'Cache hit'); - $settings = $this->parseDrupalSettings(drupal_get_js()); - $this->assertIdentical($settings['foo'], 'bar', 'Original JavaScript setting is added to the page.'); - $this->assertIdentical($settings['common_test'], $expected_settings, '#attached is modified; JavaScript settings for each #post_render_cache callback are added to page.'); - - // Test case 2. - // Use the exact same element, but now unset #cache. - drupal_static_reset('drupal_add_js'); - unset($test_element['#cache']); - $element = $test_element; - $output = drupal_render($element); - $this->assertIdentical($output, '

overridden

', 'Output is overridden.'); - $this->assertIdentical($element['#markup'], '

overridden

', '#markup is overridden.'); - $settings = $this->parseDrupalSettings(drupal_get_js()); - $expected_settings = $context_1 + $context_2 + $context_3; - $this->assertIdentical($settings['foo'], 'bar', 'Original JavaScript setting is added to the page.'); - $this->assertIdentical($settings['common_test'], $expected_settings, '#attached is modified; JavaScript settings for each #post_render_cache callback are added to page.'); - - // Test case 3. - // Create an element with a child and subchild. Each element has the same - // #post_render_cache callback, but with different contexts. Both the - // parent and the child elements have #cache set. The cached parent element - // must contain the pristine child element, i.e. unaffected by its - // #post_render_cache callbacks. I.e. the #post_render_cache callbacks may - // not yet have run, or otherwise the cached parent element would contain - // personalized data, thereby breaking the render cache. - drupal_static_reset('_drupal_add_js'); - $element = $test_element; - $element['#cache']['keys'] = array('simpletest', 'drupal_render', 'children_post_render_cache', 'nested_cache_parent'); - $element['child']['#cache']['keys'] = array('simpletest', 'drupal_render', 'children_post_render_cache', 'nested_cache_child'); - $output = drupal_render($element); - $this->assertIdentical($output, '

overridden

', 'Output is overridden.'); - $this->assertTrue(isset($element['#printed']), 'No cache hit'); - $this->assertIdentical($element['#markup'], '

overridden

', '#markup is overridden.'); - $settings = $this->parseDrupalSettings(drupal_get_js()); - $expected_settings = $context_1 + $context_2 + $context_3; - $this->assertIdentical($settings['foo'], 'bar', 'Original JavaScript setting is added to the page.'); - $this->assertIdentical($settings['common_test'], $expected_settings, '#attached is modified; JavaScript settings for each #post_render_cache callback are added to page.'); - - // GET request: validate cached data for both the parent and child. - $element = $test_element; - $element['#cache']['keys'] = array('simpletest', 'drupal_render', 'children_post_render_cache', 'nested_cache_parent'); - $element['child']['#cache']['keys'] = array('simpletest', 'drupal_render', 'children_post_render_cache', 'nested_cache_child'); - $cached_parent_element = \Drupal::cache('render')->get(drupal_render_cid_create($element))->data; - $cached_child_element = \Drupal::cache('render')->get(drupal_render_cid_create($element['child']))->data; - $expected_parent_element = array( - '#attached' => array( - 'js' => array( - array('type' => 'setting', 'data' => array('foo' => 'bar')) - ), - 'library' => array( - 'core/drupal.collapse', - 'core/drupal.collapse', - ), - ), - '#post_render_cache' => array( - 'common_test_post_render_cache' => array( - $context_1, - $context_2, - $context_3, - ) - ), - '#cache' => array('tags' => array()), - ); - - $dom = Html::load($cached_parent_element['#markup']); - $xpath = new \DOMXPath($dom); - $parent = $xpath->query('//details[@class="form-wrapper" and @open="open"]/summary[@role="button" and @aria-expanded and text()="Parent"]')->length; - $child = $xpath->query('//details[@class="form-wrapper" and @open="open"]/div[@class="details-wrapper"]/details[@class="form-wrapper" and @open="open"]/summary[@role="button" and @aria-expanded and text()="Child"]')->length; - $subchild = $xpath->query('//details[@class="form-wrapper" and @open="open"]/div[@class="details-wrapper"]/details[@class="form-wrapper" and @open="open"]/div [@class="details-wrapper" and text()="Subchild"]')->length; - $this->assertTrue($parent && $child && $subchild, 'The correct data is cached for the parent: the stored #markup is not affected by #post_render_cache callbacks.'); - - // Remove markup because it's compared above in the xpath. - unset($cached_parent_element['#markup']); - $this->assertIdentical($cached_parent_element, $expected_parent_element, 'The correct data is cached for the parent: the stored #attached properties are not affected by #post_render_cache callbacks.'); - - $expected_child_element = array( - '#attached' => array( - 'library' => array( - 'core/drupal.collapse', - ), - ), - '#post_render_cache' => array( - 'common_test_post_render_cache' => array( - $context_2, - $context_3, - ) - ), - '#cache' => array('tags' => array()), - ); - - $dom = Html::load($cached_child_element['#markup']); - $xpath = new \DOMXPath($dom); - $child = $xpath->query('//details[@class="form-wrapper" and @open="open"]/summary[@role="button" and @aria-expanded and text()="Child"]')->length; - $subchild = $xpath->query('//details[@class="form-wrapper" and @open="open"]/div [@class="details-wrapper" and text()="Subchild"]')->length; - $this->assertTrue($child && $subchild, 'The correct data is cached for the child: the stored #markup is not affected by #post_render_cache callbacks.'); - - // Remove markup because it's compared above in the xpath. - unset($cached_child_element['#markup']); - $this->assertIdentical($cached_child_element, $expected_child_element, 'The correct data is cached for the child: the stored #attached properties are not affected by #post_render_cache callbacks.'); - - // GET request: #cache enabled, cache hit, parent element. - drupal_static_reset('_drupal_add_js'); - $element = $test_element; - $element['#cache']['keys'] = array('simpletest', 'drupal_render', 'children_post_render_cache', 'nested_cache_parent'); - $output = drupal_render($element); - $this->assertIdentical($output, '

overridden

', 'Output is overridden.'); - $this->assertFalse(isset($element['#printed']), 'Cache hit'); - $settings = $this->parseDrupalSettings(drupal_get_js()); - $this->assertIdentical($settings['foo'], 'bar', 'Original JavaScript setting is added to the page.'); - $this->assertIdentical($settings['common_test'], $expected_settings, '#attached is modified; JavaScript settings for each #post_render_cache callback are added to page.'); - - // GET request: #cache enabled, cache hit, child element. - drupal_static_reset('_drupal_add_js'); - $element = $test_element; - $element['child']['#cache']['keys'] = array('simpletest', 'drupal_render', 'children_post_render_cache', 'nested_cache_child'); - $element = $element['child']; - $output = drupal_render($element); - $this->assertIdentical($output, '

overridden

', 'Output is overridden.'); - $this->assertFalse(isset($element['#printed']), 'Cache hit'); - $settings = $this->parseDrupalSettings(drupal_get_js()); - $expected_settings = $context_2 + $context_3; - $this->assertTrue(!isset($settings['foo']), 'Parent JavaScript setting is not added to the page.'); - $this->assertIdentical($settings['common_test'], $expected_settings, '#attached is modified; JavaScript settings for each #post_render_cache callback are added to page.'); - - // Restore the previous request method. - \Drupal::request()->setMethod($request_method); - } - protected function parseDrupalSettings($html) { $startToken = 'drupalSettings = '; $endToken = '}';