/**
  * Test simple and editorial translation workflows.
  */
 function testWorkflows()
 {
     // Test workflows for the editor.
     $expected_status = ['edit' => 200, 'delete' => 200, 'overview' => 403, 'add_translation' => 403, 'edit_translation' => 403, 'delete_translation' => 403];
     $this->doTestWorkflows($this->editor, $expected_status);
     // Test workflows for the translator.
     $expected_status = ['edit' => 403, 'delete' => 403, 'overview' => 200, 'add_translation' => 200, 'edit_translation' => 200, 'delete_translation' => 200];
     $this->doTestWorkflows($this->translator, $expected_status);
     // Test workflows for the admin.
     $expected_status = ['edit' => 200, 'delete' => 200, 'overview' => 200, 'add_translation' => 200, 'edit_translation' => 403, 'delete_translation' => 403];
     $this->doTestWorkflows($this->administrator, $expected_status);
     // Check that translation permissions allow the associated operations.
     $ops = array('create' => t('Add'), 'update' => t('Edit'), 'delete' => t('Delete'));
     $translations_url = $this->entity->urlInfo('drupal:content-translation-overview');
     foreach ($ops as $current_op => $item) {
         $user = $this->drupalCreateUser(array($this->getTranslatePermission(), "{$current_op} content translations"));
         $this->drupalLogin($user);
         $this->drupalGet($translations_url);
         // Make sure that the user.permissions cache context and the cache tags
         // for the entity are present.
         $this->assertCacheContext('user.permissions');
         foreach ($this->entity->getCacheTags() as $cache_tag) {
             $this->assertCacheTag($cache_tag);
         }
         foreach ($ops as $op => $label) {
             if ($op != $current_op) {
                 $this->assertNoLink($label, format_string('No %op link found.', array('%op' => $label)));
             } else {
                 $this->assertLink($label, 0, format_string('%op link found.', array('%op' => $label)));
             }
         }
     }
 }
 /**
  * Tests the label formatter.
  */
 public function testLabelFormatter()
 {
     /** @var \Drupal\Core\Render\RendererInterface $renderer */
     $renderer = $this->container->get('renderer');
     $formatter = 'entity_reference_label';
     // The 'link' settings is TRUE by default.
     $build = $this->buildRenderArray([$this->referencedEntity, $this->unsavedReferencedEntity], $formatter);
     $expected_field_cacheability = ['contexts' => [], 'tags' => [], 'max-age' => Cache::PERMANENT];
     $this->assertEqual($build['#cache'], $expected_field_cacheability, 'The field render array contains the entity access cacheability metadata');
     $expected_item_1 = array('#type' => 'link', '#title' => $this->referencedEntity->label(), '#url' => $this->referencedEntity->urlInfo(), '#options' => $this->referencedEntity->urlInfo()->getOptions(), '#cache' => array('contexts' => ['user.permissions'], 'tags' => $this->referencedEntity->getCacheTags()));
     $this->assertEqual($renderer->renderRoot($build[0]), $renderer->renderRoot($expected_item_1), sprintf('The markup returned by the %s formatter is correct for an item with a saved entity.', $formatter));
     $this->assertEqual(CacheableMetadata::createFromRenderArray($build[0]), CacheableMetadata::createFromRenderArray($expected_item_1));
     // The second referenced entity is "autocreated", therefore not saved and
     // lacking any URL info.
     $expected_item_2 = array('#plain_text' => $this->unsavedReferencedEntity->label(), '#cache' => array('contexts' => ['user.permissions'], 'tags' => $this->unsavedReferencedEntity->getCacheTags(), 'max-age' => Cache::PERMANENT));
     $this->assertEqual($build[1], $expected_item_2, sprintf('The render array returned by the %s formatter is correct for an item with a unsaved entity.', $formatter));
     // Test with the 'link' setting set to FALSE.
     $build = $this->buildRenderArray([$this->referencedEntity, $this->unsavedReferencedEntity], $formatter, array('link' => FALSE));
     $this->assertEqual($build[0]['#plain_text'], $this->referencedEntity->label(), sprintf('The markup returned by the %s formatter is correct for an item with a saved entity.', $formatter));
     $this->assertEqual($build[1]['#plain_text'], $this->unsavedReferencedEntity->label(), sprintf('The markup returned by the %s formatter is correct for an item with a unsaved entity.', $formatter));
     // Test an entity type that doesn't have any link templates, which means
     // \Drupal\Core\Entity\EntityInterface::urlInfo() will throw an exception
     // and the label formatter will output only the label instead of a link.
     $field_storage_config = FieldStorageConfig::loadByName($this->entityType, $this->fieldName);
     $field_storage_config->setSetting('target_type', 'entity_test_label');
     $field_storage_config->save();
     $referenced_entity_with_no_link_template = EntityTestLabel::create(array('name' => $this->randomMachineName()));
     $referenced_entity_with_no_link_template->save();
     $build = $this->buildRenderArray([$referenced_entity_with_no_link_template], $formatter, array('link' => TRUE));
     $this->assertEqual($build[0]['#plain_text'], $referenced_entity_with_no_link_template->label(), sprintf('The markup returned by the %s formatter is correct for an entity type with no valid link template.', $formatter));
 }
    /**
     * Tests the entity formatter.
     */
    public function testEntityFormatter()
    {
        $formatter = 'entity_reference_entity_view';
        $field_name = $this->fieldName;
        // Create the entity that will have the entity reference field.
        $referencing_entity = entity_create($this->entityType, array('name' => $this->randomMachineName()));
        $referencing_entity->save();
        $referencing_entity->{$field_name}->entity = $this->referencedEntity;
        $referencing_entity->{$field_name}->access = TRUE;
        // Build the renderable array for the entity reference field.
        $items = $referencing_entity->get($field_name);
        $build = $items->view(array('type' => $formatter));
        $expected_rendered_name_field = '<div class="field field-entity-test--name field-name-name field-type-string field-label-hidden">
    <div class="field-items">
          <div class="field-item">' . $this->referencedEntity->label() . '</div>
      </div>
</div>
';
        $expected_rendered_body_field = '<div class="field field-entity-test--body field-name-body field-type-text field-label-above">
      <div class="field-label">Body</div>
    <div class="field-items">
          <div class="field-item"><p>Hello, world!</p></div>
      </div>
</div>
';
        drupal_render($build[0]);
        $this->assertEqual($build[0]['#markup'], 'default | ' . $this->referencedEntity->label() . $expected_rendered_name_field . $expected_rendered_body_field, format_string('The markup returned by the @formatter formatter is correct.', array('@formatter' => $formatter)));
        $expected_cache_tags = Cache::mergeTags(\Drupal::entityManager()->getViewBuilder($this->entityType)->getCacheTags(), $this->referencedEntity->getCacheTags(), FilterFormat::load('full_html')->getCacheTags());
        $this->assertEqual($build[0]['#cache']['tags'], $expected_cache_tags, format_string('The @formatter formatter has the expected cache tags.', array('@formatter' => $formatter)));
    }
 /**
  * Tests the label formatter.
  */
 public function testLabelFormatter()
 {
     $formatter = 'entity_reference_label';
     // The 'link' settings is TRUE by default.
     $build = $this->buildRenderArray([$this->referencedEntity, $this->unsavedReferencedEntity], $formatter);
     $expected_item_1 = array('#type' => 'link', '#title' => $this->referencedEntity->label(), '#url' => $this->referencedEntity->urlInfo(), '#options' => $this->referencedEntity->urlInfo()->getOptions(), '#cache' => array('tags' => $this->referencedEntity->getCacheTags()));
     $this->assertEqual(drupal_render($build[0]), drupal_render($expected_item_1), sprintf('The markup returned by the %s formatter is correct for an item with a saved entity.', $formatter));
     // The second referenced entity is "autocreated", therefore not saved and
     // lacking any URL info.
     $expected_item_2 = array('#markup' => $this->unsavedReferencedEntity->label(), '#cache' => array('tags' => $this->unsavedReferencedEntity->getCacheTags()));
     $this->assertEqual($build[1], $expected_item_2, sprintf('The markup returned by the %s formatter is correct for an item with a unsaved entity.', $formatter));
     // Test with the 'link' setting set to FALSE.
     $build = $this->buildRenderArray([$this->referencedEntity, $this->unsavedReferencedEntity], $formatter, array('link' => FALSE));
     $this->assertEqual($build[0]['#markup'], $this->referencedEntity->label(), sprintf('The markup returned by the %s formatter is correct for an item with a saved entity.', $formatter));
     $this->assertEqual($build[1]['#markup'], $this->unsavedReferencedEntity->label(), sprintf('The markup returned by the %s formatter is correct for an item with a unsaved entity.', $formatter));
     // Test an entity type that doesn't have any link templates, which means
     // \Drupal\Core\Entity\EntityInterface::urlInfo() will throw an exception
     // and the label formatter will output only the label instead of a link.
     $field_storage_config = FieldStorageConfig::loadByName($this->entityType, $this->fieldName);
     $field_storage_config->setSetting('target_type', 'entity_test_label');
     $field_storage_config->save();
     $referenced_entity_with_no_link_template = entity_create('entity_test_label', array('name' => $this->randomMachineName()));
     $referenced_entity_with_no_link_template->save();
     $build = $this->buildRenderArray([$referenced_entity_with_no_link_template], $formatter, array('link' => TRUE));
     $this->assertEqual($build[0]['#markup'], $referenced_entity_with_no_link_template->label(), sprintf('The markup returned by the %s formatter is correct for an entity type with no valid link template.', $formatter));
 }
 /**
  * {@inheritdoc}
  */
 protected function calculateXmlCacheTags()
 {
     // Add tags for the entity that this XML comes from.
     $entity_tags = $this->entity instanceof CacheableDependencyInterface ? $this->entity->getCacheTags() : array();
     // Also fetch the tags from the display configuration as that is where our
     // gallery-specific settings are stored (so changes there should also
     // invalidate the XML).
     $display = entity_get_display($this->entityType, $this->entity->bundle(), $this->displayName);
     $display_tags = array();
     if ($display instanceof CacheableDependencyInterface) {
         $display_tags = $display->getCacheTags();
         // If this is not a custom display then we need to also include the
         // default display cache tags as Drupal may reference this display
         // elsewhere by the "default" label.
         if (!$display->status() || $display->isNew()) {
             $display_default = entity_get_display($this->entityType, $this->entity->bundle(), 'default');
             if ($display_default instanceof CacheableDependencyInterface) {
                 $display_tags = Cache::mergeTags($display_tags, $display_default->getCacheTags());
             }
         }
     }
     return Cache::mergeTags($entity_tags, $display_tags);
 }
예제 #6
0
 /**
  * Tests cache tags presence and invalidation of the entity when referenced.
  *
  * Tests the following cache tags:
  * - entity type view cache tag: "<entity type>_view"
  * - entity cache tag: "<entity type>:<entity ID>"
  * - entity type list cache tag: "<entity type>_list"
  * - referencing entity type view cache tag: "<referencing entity type>_view"
  * - referencing entity type cache tag: "<referencing entity type>:<referencing entity ID>"
  */
 public function testReferencedEntity()
 {
     $entity_type = $this->entity->getEntityTypeId();
     $referencing_entity_url = $this->referencingEntity->urlInfo('canonical');
     $non_referencing_entity_url = $this->nonReferencingEntity->urlInfo('canonical');
     $listing_url = Url::fromRoute('entity.entity_test.collection_referencing_entities', ['entity_reference_field_name' => $entity_type . '_reference', 'referenced_entity_type' => $entity_type, 'referenced_entity_id' => $this->entity->id()]);
     $empty_entity_listing_url = Url::fromRoute('entity.entity_test.collection_empty', ['entity_type_id' => $entity_type]);
     $nonempty_entity_listing_url = Url::fromRoute('entity.entity_test.collection_labels_alphabetically', ['entity_type_id' => $entity_type]);
     // The default cache contexts for rendered entities.
     $default_cache_contexts = ['languages:' . LanguageInterface::TYPE_INTERFACE, 'theme', 'user.permissions'];
     $entity_cache_contexts = $default_cache_contexts;
     $page_cache_contexts = Cache::mergeContexts($default_cache_contexts, ['url.query_args:' . MainContentViewSubscriber::WRAPPER_FORMAT]);
     // Cache tags present on every rendered page.
     // 'user.permissions' is a required cache context, and responses that vary
     // by this cache context when requested by anonymous users automatically
     // also get this cache tag, to ensure correct invalidation.
     $page_cache_tags = Cache::mergeTags(['rendered'], ['config:user.role.anonymous']);
     // If the block module is used, the Block page display variant is used,
     // which adds the block config entity type's list cache tags.
     $page_cache_tags = Cache::mergeTags($page_cache_tags, \Drupal::moduleHandler()->moduleExists('block') ? ['config:block_list'] : []);
     $page_cache_tags_referencing_entity = in_array('user.permissions', $this->getAccessCacheContextsForEntity($this->referencingEntity)) ? ['config:user.role.anonymous'] : [];
     $view_cache_tag = array();
     if ($this->entity->getEntityType()->hasHandlerClass('view_builder')) {
         $view_cache_tag = \Drupal::entityManager()->getViewBuilder($entity_type)->getCacheTags();
     }
     $context_metadata = \Drupal::service('cache_contexts_manager')->convertTokensToKeys($entity_cache_contexts);
     $cache_context_tags = $context_metadata->getCacheTags();
     // Generate the cache tags for the (non) referencing entities.
     $referencing_entity_cache_tags = Cache::mergeTags($this->referencingEntity->getCacheTags(), \Drupal::entityManager()->getViewBuilder('entity_test')->getCacheTags());
     // Includes the main entity's cache tags, since this entity references it.
     $referencing_entity_cache_tags = Cache::mergeTags($referencing_entity_cache_tags, $this->entity->getCacheTags());
     $referencing_entity_cache_tags = Cache::mergeTags($referencing_entity_cache_tags, $this->getAdditionalCacheTagsForEntity($this->entity));
     $referencing_entity_cache_tags = Cache::mergeTags($referencing_entity_cache_tags, $view_cache_tag);
     $referencing_entity_cache_tags = Cache::mergeTags($referencing_entity_cache_tags, $cache_context_tags);
     $referencing_entity_cache_tags = Cache::mergeTags($referencing_entity_cache_tags, ['rendered']);
     $non_referencing_entity_cache_tags = Cache::mergeTags($this->nonReferencingEntity->getCacheTags(), \Drupal::entityManager()->getViewBuilder('entity_test')->getCacheTags());
     $non_referencing_entity_cache_tags = Cache::mergeTags($non_referencing_entity_cache_tags, ['rendered']);
     // Generate the cache tags for all two possible entity listing paths.
     // 1. list cache tag only (listing query has no match)
     // 2. list cache tag plus entity cache tag (listing query has a match)
     $empty_entity_listing_cache_tags = Cache::mergeTags($this->entity->getEntityType()->getListCacheTags(), $page_cache_tags);
     $nonempty_entity_listing_cache_tags = Cache::mergeTags($this->entity->getEntityType()->getListCacheTags(), $this->entity->getCacheTags());
     $nonempty_entity_listing_cache_tags = Cache::mergeTags($nonempty_entity_listing_cache_tags, $this->getAdditionalCacheTagsForEntityListing($this->entity));
     $nonempty_entity_listing_cache_tags = Cache::mergeTags($nonempty_entity_listing_cache_tags, $page_cache_tags);
     $this->pass("Test referencing entity.", 'Debug');
     $this->verifyPageCache($referencing_entity_url, 'MISS');
     // Verify a cache hit, but also the presence of the correct cache tags.
     $expected_tags = Cache::mergeTags($referencing_entity_cache_tags, $page_cache_tags);
     $expected_tags = Cache::mergeTags($expected_tags, $page_cache_tags_referencing_entity);
     $this->verifyPageCache($referencing_entity_url, 'HIT', $expected_tags);
     // Also verify the existence of an entity render cache entry.
     $cache_keys = ['entity_view', 'entity_test', $this->referencingEntity->id(), 'full'];
     $cid = $this->createCacheId($cache_keys, $entity_cache_contexts);
     $access_cache_contexts = $this->getAccessCacheContextsForEntity($this->entity);
     $additional_cache_contexts = $this->getAdditionalCacheContextsForEntity($this->referencingEntity);
     $redirected_cid = NULL;
     if (count($access_cache_contexts) || count($additional_cache_contexts)) {
         $cache_contexts = Cache::mergeContexts($entity_cache_contexts, $additional_cache_contexts);
         $cache_contexts = Cache::mergeContexts($cache_contexts, $access_cache_contexts);
         $redirected_cid = $this->createCacheId($cache_keys, $cache_contexts);
         $context_metadata = \Drupal::service('cache_contexts_manager')->convertTokensToKeys($cache_contexts);
         $referencing_entity_cache_tags = Cache::mergeTags($referencing_entity_cache_tags, $context_metadata->getCacheTags());
     }
     $this->verifyRenderCache($cid, $referencing_entity_cache_tags, $redirected_cid);
     $this->pass("Test non-referencing entity.", 'Debug');
     $this->verifyPageCache($non_referencing_entity_url, 'MISS');
     // Verify a cache hit, but also the presence of the correct cache tags.
     $this->verifyPageCache($non_referencing_entity_url, 'HIT', Cache::mergeTags($non_referencing_entity_cache_tags, $page_cache_tags));
     // Also verify the existence of an entity render cache entry.
     $cache_keys = ['entity_view', 'entity_test', $this->nonReferencingEntity->id(), 'full'];
     $cid = $this->createCacheId($cache_keys, $entity_cache_contexts);
     $this->verifyRenderCache($cid, $non_referencing_entity_cache_tags);
     $this->pass("Test listing of referencing entities.", 'Debug');
     // Prime the page cache for the listing of referencing entities.
     $this->verifyPageCache($listing_url, 'MISS');
     // Verify a cache hit, but also the presence of the correct cache tags.
     $expected_tags = Cache::mergeTags($referencing_entity_cache_tags, $page_cache_tags);
     $expected_tags = Cache::mergeTags($expected_tags, $page_cache_tags_referencing_entity);
     $this->verifyPageCache($listing_url, 'HIT', $expected_tags);
     $this->pass("Test empty listing.", 'Debug');
     // Prime the page cache for the empty listing.
     $this->verifyPageCache($empty_entity_listing_url, 'MISS');
     // Verify a cache hit, but also the presence of the correct cache tags.
     $this->verifyPageCache($empty_entity_listing_url, 'HIT', $empty_entity_listing_cache_tags);
     // Verify the entity type's list cache contexts are present.
     $contexts_in_header = $this->drupalGetHeader('X-Drupal-Cache-Contexts');
     $this->assertEqual(Cache::mergeContexts($page_cache_contexts, $this->getAdditionalCacheContextsForEntityListing()), empty($contexts_in_header) ? [] : explode(' ', $contexts_in_header));
     $this->pass("Test listing containing referenced entity.", 'Debug');
     // Prime the page cache for the listing containing the referenced entity.
     $this->verifyPageCache($nonempty_entity_listing_url, 'MISS', $nonempty_entity_listing_cache_tags);
     // Verify a cache hit, but also the presence of the correct cache tags.
     $this->verifyPageCache($nonempty_entity_listing_url, 'HIT', $nonempty_entity_listing_cache_tags);
     // Verify the entity type's list cache contexts are present.
     $contexts_in_header = $this->drupalGetHeader('X-Drupal-Cache-Contexts');
     $this->assertEqual(Cache::mergeContexts($page_cache_contexts, $this->getAdditionalCacheContextsForEntityListing()), empty($contexts_in_header) ? [] : explode(' ', $contexts_in_header));
     // Verify that after modifying the referenced entity, there is a cache miss
     // for every route except the one for the non-referencing entity.
     $this->pass("Test modification of referenced entity.", 'Debug');
     $this->entity->save();
     $this->verifyPageCache($referencing_entity_url, 'MISS');
     $this->verifyPageCache($listing_url, 'MISS');
     $this->verifyPageCache($empty_entity_listing_url, 'MISS');
     $this->verifyPageCache($nonempty_entity_listing_url, 'MISS');
     $this->verifyPageCache($non_referencing_entity_url, 'HIT');
     // Verify cache hits.
     $this->verifyPageCache($referencing_entity_url, 'HIT');
     $this->verifyPageCache($listing_url, 'HIT');
     $this->verifyPageCache($empty_entity_listing_url, 'HIT');
     $this->verifyPageCache($nonempty_entity_listing_url, 'HIT');
     // Verify that after modifying the referencing entity, there is a cache miss
     // for every route except the ones for the non-referencing entity and the
     // empty entity listing.
     $this->pass("Test modification of referencing entity.", 'Debug');
     $this->referencingEntity->save();
     $this->verifyPageCache($referencing_entity_url, 'MISS');
     $this->verifyPageCache($listing_url, 'MISS');
     $this->verifyPageCache($nonempty_entity_listing_url, 'HIT');
     $this->verifyPageCache($non_referencing_entity_url, 'HIT');
     $this->verifyPageCache($empty_entity_listing_url, 'HIT');
     // Verify cache hits.
     $this->verifyPageCache($referencing_entity_url, 'HIT');
     $this->verifyPageCache($listing_url, 'HIT');
     $this->verifyPageCache($nonempty_entity_listing_url, 'HIT');
     // Verify that after modifying the non-referencing entity, there is a cache
     // miss only for the non-referencing entity route.
     $this->pass("Test modification of non-referencing entity.", 'Debug');
     $this->nonReferencingEntity->save();
     $this->verifyPageCache($referencing_entity_url, 'HIT');
     $this->verifyPageCache($listing_url, 'HIT');
     $this->verifyPageCache($empty_entity_listing_url, 'HIT');
     $this->verifyPageCache($nonempty_entity_listing_url, 'HIT');
     $this->verifyPageCache($non_referencing_entity_url, 'MISS');
     // Verify cache hits.
     $this->verifyPageCache($non_referencing_entity_url, 'HIT');
     if ($this->entity->getEntityType()->hasHandlerClass('view_builder')) {
         // Verify that after modifying the entity's display, there is a cache miss
         // for both the referencing entity, and the listing of referencing
         // entities, but not for any other routes.
         $referenced_entity_view_mode = $this->selectViewMode($this->entity->getEntityTypeId());
         $this->pass("Test modification of referenced entity's '{$referenced_entity_view_mode}' display.", 'Debug');
         $entity_display = entity_get_display($entity_type, $this->entity->bundle(), $referenced_entity_view_mode);
         $entity_display->save();
         $this->verifyPageCache($referencing_entity_url, 'MISS');
         $this->verifyPageCache($listing_url, 'MISS');
         $this->verifyPageCache($non_referencing_entity_url, 'HIT');
         $this->verifyPageCache($empty_entity_listing_url, 'HIT');
         $this->verifyPageCache($nonempty_entity_listing_url, 'HIT');
         // Verify cache hits.
         $this->verifyPageCache($referencing_entity_url, 'HIT');
         $this->verifyPageCache($listing_url, 'HIT');
     }
     if ($bundle_entity_type_id = $this->entity->getEntityType()->getBundleEntityType()) {
         // Verify that after modifying the corresponding bundle entity, there is a
         // cache miss for both the referencing entity, and the listing of
         // referencing entities, but not for any other routes.
         $this->pass("Test modification of referenced entity's bundle entity.", 'Debug');
         $bundle_entity = entity_load($bundle_entity_type_id, $this->entity->bundle());
         $bundle_entity->save();
         $this->verifyPageCache($referencing_entity_url, 'MISS');
         $this->verifyPageCache($listing_url, 'MISS');
         $this->verifyPageCache($non_referencing_entity_url, 'HIT');
         // Special case: entity types may choose to use their bundle entity type
         // cache tags, to avoid having excessively granular invalidation.
         $is_special_case = $bundle_entity->getCacheTags() == $this->entity->getCacheTags() && $bundle_entity->getEntityType()->getListCacheTags() == $this->entity->getEntityType()->getListCacheTags();
         if ($is_special_case) {
             $this->verifyPageCache($empty_entity_listing_url, 'MISS');
             $this->verifyPageCache($nonempty_entity_listing_url, 'MISS');
         } else {
             $this->verifyPageCache($empty_entity_listing_url, 'HIT');
             $this->verifyPageCache($nonempty_entity_listing_url, 'HIT');
         }
         // Verify cache hits.
         $this->verifyPageCache($referencing_entity_url, 'HIT');
         $this->verifyPageCache($listing_url, 'HIT');
         if ($is_special_case) {
             $this->verifyPageCache($empty_entity_listing_url, 'HIT');
             $this->verifyPageCache($nonempty_entity_listing_url, 'HIT');
         }
     }
     if ($this->entity->getEntityType()->get('field_ui_base_route')) {
         // Verify that after modifying a configurable field on the entity, there
         // is a cache miss.
         $this->pass("Test modification of referenced entity's configurable field.", 'Debug');
         $field_storage_name = $this->entity->getEntityTypeId() . '.configurable_field';
         $field_storage = FieldStorageConfig::load($field_storage_name);
         $field_storage->save();
         $this->verifyPageCache($referencing_entity_url, 'MISS');
         $this->verifyPageCache($listing_url, 'MISS');
         $this->verifyPageCache($empty_entity_listing_url, 'HIT');
         $this->verifyPageCache($nonempty_entity_listing_url, 'HIT');
         $this->verifyPageCache($non_referencing_entity_url, 'HIT');
         // Verify cache hits.
         $this->verifyPageCache($referencing_entity_url, 'HIT');
         $this->verifyPageCache($listing_url, 'HIT');
         // Verify that after modifying a configurable field on the entity, there
         // is a cache miss.
         $this->pass("Test modification of referenced entity's configurable field.", 'Debug');
         $field_name = $this->entity->getEntityTypeId() . '.' . $this->entity->bundle() . '.configurable_field';
         $field = FieldConfig::load($field_name);
         $field->save();
         $this->verifyPageCache($referencing_entity_url, 'MISS');
         $this->verifyPageCache($listing_url, 'MISS');
         $this->verifyPageCache($empty_entity_listing_url, 'HIT');
         $this->verifyPageCache($nonempty_entity_listing_url, 'HIT');
         $this->verifyPageCache($non_referencing_entity_url, 'HIT');
         // Verify cache hits.
         $this->verifyPageCache($referencing_entity_url, 'HIT');
         $this->verifyPageCache($listing_url, 'HIT');
     }
     // Verify that after invalidating the entity's cache tag directly, there is
     // a cache miss for every route except the ones for the non-referencing
     // entity and the empty entity listing.
     $this->pass("Test invalidation of referenced entity's cache tag.", 'Debug');
     Cache::invalidateTags($this->entity->getCacheTagsToInvalidate());
     $this->verifyPageCache($referencing_entity_url, 'MISS');
     $this->verifyPageCache($listing_url, 'MISS');
     $this->verifyPageCache($nonempty_entity_listing_url, 'MISS');
     $this->verifyPageCache($non_referencing_entity_url, 'HIT');
     $this->verifyPageCache($empty_entity_listing_url, 'HIT');
     // Verify cache hits.
     $this->verifyPageCache($referencing_entity_url, 'HIT');
     $this->verifyPageCache($listing_url, 'HIT');
     $this->verifyPageCache($nonempty_entity_listing_url, 'HIT');
     // Verify that after invalidating the entity's list cache tag directly,
     // there is a cache miss for both the empty entity listing and the non-empty
     // entity listing routes, but not for other routes.
     $this->pass("Test invalidation of referenced entity's list cache tag.", 'Debug');
     Cache::invalidateTags($this->entity->getEntityType()->getListCacheTags());
     $this->verifyPageCache($empty_entity_listing_url, 'MISS');
     $this->verifyPageCache($nonempty_entity_listing_url, 'MISS');
     $this->verifyPageCache($referencing_entity_url, 'HIT');
     $this->verifyPageCache($non_referencing_entity_url, 'HIT');
     $this->verifyPageCache($listing_url, 'HIT');
     // Verify cache hits.
     $this->verifyPageCache($empty_entity_listing_url, 'HIT');
     $this->verifyPageCache($nonempty_entity_listing_url, 'HIT');
     if (!empty($view_cache_tag)) {
         // Verify that after invalidating the generic entity type's view cache tag
         // directly, there is a cache miss for both the referencing entity, and the
         // listing of referencing entities, but not for other routes.
         $this->pass("Test invalidation of referenced entity's 'view' cache tag.", 'Debug');
         Cache::invalidateTags($view_cache_tag);
         $this->verifyPageCache($referencing_entity_url, 'MISS');
         $this->verifyPageCache($listing_url, 'MISS');
         $this->verifyPageCache($non_referencing_entity_url, 'HIT');
         $this->verifyPageCache($empty_entity_listing_url, 'HIT');
         $this->verifyPageCache($nonempty_entity_listing_url, 'HIT');
         // Verify cache hits.
         $this->verifyPageCache($referencing_entity_url, 'HIT');
         $this->verifyPageCache($listing_url, 'HIT');
     }
     // Verify that after deleting the entity, there is a cache miss for every
     // route except for the non-referencing entity one.
     $this->pass('Test deletion of referenced entity.', 'Debug');
     $this->entity->delete();
     $this->verifyPageCache($referencing_entity_url, 'MISS');
     $this->verifyPageCache($listing_url, 'MISS');
     $this->verifyPageCache($empty_entity_listing_url, 'MISS');
     $this->verifyPageCache($nonempty_entity_listing_url, 'MISS');
     $this->verifyPageCache($non_referencing_entity_url, 'HIT');
     // Verify cache hits.
     $referencing_entity_cache_tags = Cache::mergeTags($this->referencingEntity->getCacheTags(), \Drupal::entityManager()->getViewBuilder('entity_test')->getCacheTags());
     $referencing_entity_cache_tags = Cache::mergeTags($referencing_entity_cache_tags, ['rendered']);
     $nonempty_entity_listing_cache_tags = Cache::mergeTags($this->entity->getEntityType()->getListCacheTags(), $this->getAdditionalCacheTagsForEntityListing());
     $nonempty_entity_listing_cache_tags = Cache::mergeTags($nonempty_entity_listing_cache_tags, $page_cache_tags);
     $this->verifyPageCache($referencing_entity_url, 'HIT', Cache::mergeTags($referencing_entity_cache_tags, $page_cache_tags));
     $this->verifyPageCache($listing_url, 'HIT', $page_cache_tags);
     $this->verifyPageCache($empty_entity_listing_url, 'HIT', $empty_entity_listing_cache_tags);
     $this->verifyPageCache($nonempty_entity_listing_url, 'HIT', $nonempty_entity_listing_cache_tags);
 }
예제 #7
0
 /**
  * Convenience method, adds the entity's cache tag.
  *
  * @param \Drupal\Core\Entity\EntityInterface $entity
  *   The entity whose cache tag to set on the access result.
  *
  * @return $this
  */
 public function cacheUntilEntityChanges(EntityInterface $entity)
 {
     $this->addCacheTags($entity->getCacheTags());
     return $this;
 }
 /**
  * Tests cache tags presence and invalidation of the entity when referenced.
  *
  * Tests the following cache tags:
  * - entity type view cache tag: "<entity type>_view"
  * - entity cache tag: "<entity type>:<entity ID>"
  * - entity type list cache tag: "<entity type>_list"
  * - referencing entity type view cache tag: "<referencing entity type>_view"
  * - referencing entity type cache tag: "<referencing entity type>:<referencing entity ID>"
  */
 public function testReferencedEntity()
 {
     $entity_type = $this->entity->getEntityTypeId();
     $referencing_entity_path = $this->referencing_entity->getSystemPath();
     $non_referencing_entity_path = $this->non_referencing_entity->getSystemPath();
     $listing_path = 'entity_test/list/' . $entity_type . '_reference/' . $entity_type . '/' . $this->entity->id();
     $empty_entity_listing_path = 'entity_test/list_empty/' . $entity_type;
     $nonempty_entity_listing_path = 'entity_test/list_labels_alphabetically/' . $entity_type;
     $render_cache_tags = array('rendered');
     $theme_cache_tags = array('theme:stark', 'theme_global_settings');
     $view_cache_tag = array();
     if ($this->entity->getEntityType()->hasHandlerClass('view_builder')) {
         $view_cache_tag = \Drupal::entityManager()->getViewBuilder($entity_type)->getCacheTags();
     }
     // Generate the cache tags for the (non) referencing entities.
     $referencing_entity_cache_tags = Cache::mergeTags($this->referencing_entity->getCacheTags(), \Drupal::entityManager()->getViewBuilder('entity_test')->getCacheTags(), $this->entity->getCacheTags(), $this->getAdditionalCacheTagsForEntity($this->entity), $view_cache_tag);
     $non_referencing_entity_cache_tags = Cache::mergeTags($this->non_referencing_entity->getCacheTags(), \Drupal::entityManager()->getViewBuilder('entity_test')->getCacheTags());
     // Generate the cache tags for all two possible entity listing paths.
     // 1. list cache tag only (listing query has no match)
     // 2. list cache tag plus entity cache tag (listing query has a match)
     $empty_entity_listing_cache_tags = Cache::mergeTags($this->entity->getEntityType()->getListCacheTags(), $theme_cache_tags, $render_cache_tags);
     $nonempty_entity_listing_cache_tags = Cache::mergeTags($this->entity->getEntityType()->getListCacheTags(), $this->entity->getCacheTags(), $this->getAdditionalCacheTagsForEntityListing($this->entity), $theme_cache_tags, $render_cache_tags);
     $this->pass("Test referencing entity.", 'Debug');
     $this->verifyPageCache($referencing_entity_path, 'MISS');
     // Verify a cache hit, but also the presence of the correct cache tags.
     $tags = Cache::mergeTags($render_cache_tags, $theme_cache_tags, $referencing_entity_cache_tags);
     $this->verifyPageCache($referencing_entity_path, 'HIT', $tags);
     // Also verify the existence of an entity render cache entry.
     $cid = 'entity_view:entity_test:' . $this->referencing_entity->id() . ':full:stark:r.anonymous:' . date_default_timezone_get();
     $tags = Cache::mergeTags($render_cache_tags, $referencing_entity_cache_tags);
     $this->verifyRenderCache($cid, $tags);
     $this->pass("Test non-referencing entity.", 'Debug');
     $this->verifyPageCache($non_referencing_entity_path, 'MISS');
     // Verify a cache hit, but also the presence of the correct cache tags.
     $tags = Cache::mergeTags($render_cache_tags, $theme_cache_tags, $non_referencing_entity_cache_tags);
     $this->verifyPageCache($non_referencing_entity_path, 'HIT', $tags);
     // Also verify the existence of an entity render cache entry.
     $cid = 'entity_view:entity_test:' . $this->non_referencing_entity->id() . ':full:stark:r.anonymous:' . date_default_timezone_get();
     $tags = Cache::mergeTags($render_cache_tags, $non_referencing_entity_cache_tags);
     $this->verifyRenderCache($cid, $tags);
     $this->pass("Test listing of referencing entities.", 'Debug');
     // Prime the page cache for the listing of referencing entities.
     $this->verifyPageCache($listing_path, 'MISS');
     // Verify a cache hit, but also the presence of the correct cache tags.
     $tags = Cache::mergeTags($render_cache_tags, $theme_cache_tags, $referencing_entity_cache_tags);
     $this->verifyPageCache($listing_path, 'HIT', $tags);
     $this->pass("Test empty listing.", 'Debug');
     // Prime the page cache for the empty listing.
     $this->verifyPageCache($empty_entity_listing_path, 'MISS');
     // Verify a cache hit, but also the presence of the correct cache tags.
     $this->verifyPageCache($empty_entity_listing_path, 'HIT', $empty_entity_listing_cache_tags);
     $this->pass("Test listing containing referenced entity.", 'Debug');
     // Prime the page cache for the listing containing the referenced entity.
     $this->verifyPageCache($nonempty_entity_listing_path, 'MISS');
     // Verify a cache hit, but also the presence of the correct cache tags.
     $this->verifyPageCache($nonempty_entity_listing_path, 'HIT', $nonempty_entity_listing_cache_tags);
     // Verify that after modifying the referenced entity, there is a cache miss
     // for every route except the one for the non-referencing entity.
     $this->pass("Test modification of referenced entity.", 'Debug');
     $this->entity->save();
     $this->verifyPageCache($referencing_entity_path, 'MISS');
     $this->verifyPageCache($listing_path, 'MISS');
     $this->verifyPageCache($empty_entity_listing_path, 'MISS');
     $this->verifyPageCache($nonempty_entity_listing_path, 'MISS');
     $this->verifyPageCache($non_referencing_entity_path, 'HIT');
     // Verify cache hits.
     $this->verifyPageCache($referencing_entity_path, 'HIT');
     $this->verifyPageCache($listing_path, 'HIT');
     $this->verifyPageCache($empty_entity_listing_path, 'HIT');
     $this->verifyPageCache($nonempty_entity_listing_path, 'HIT');
     // Verify that after modifying the referencing entity, there is a cache miss
     // for every route except the ones for the non-referencing entity and the
     // empty entity listing.
     $this->pass("Test modification of referencing entity.", 'Debug');
     $this->referencing_entity->save();
     $this->verifyPageCache($referencing_entity_path, 'MISS');
     $this->verifyPageCache($listing_path, 'MISS');
     $this->verifyPageCache($nonempty_entity_listing_path, 'HIT');
     $this->verifyPageCache($non_referencing_entity_path, 'HIT');
     $this->verifyPageCache($empty_entity_listing_path, 'HIT');
     // Verify cache hits.
     $this->verifyPageCache($referencing_entity_path, 'HIT');
     $this->verifyPageCache($listing_path, 'HIT');
     $this->verifyPageCache($nonempty_entity_listing_path, 'HIT');
     // Verify that after modifying the non-referencing entity, there is a cache
     // miss only for the non-referencing entity route.
     $this->pass("Test modification of non-referencing entity.", 'Debug');
     $this->non_referencing_entity->save();
     $this->verifyPageCache($referencing_entity_path, 'HIT');
     $this->verifyPageCache($listing_path, 'HIT');
     $this->verifyPageCache($empty_entity_listing_path, 'HIT');
     $this->verifyPageCache($nonempty_entity_listing_path, 'HIT');
     $this->verifyPageCache($non_referencing_entity_path, 'MISS');
     // Verify cache hits.
     $this->verifyPageCache($non_referencing_entity_path, 'HIT');
     if ($this->entity->getEntityType()->hasHandlerClass('view_builder')) {
         // Verify that after modifying the entity's display, there is a cache miss
         // for both the referencing entity, and the listing of referencing
         // entities, but not for any other routes.
         $referenced_entity_view_mode = $this->selectViewMode($this->entity->getEntityTypeId());
         $this->pass("Test modification of referenced entity's '{$referenced_entity_view_mode}' display.", 'Debug');
         $entity_display = entity_get_display($entity_type, $this->entity->bundle(), $referenced_entity_view_mode);
         $entity_display->save();
         $this->verifyPageCache($referencing_entity_path, 'MISS');
         $this->verifyPageCache($listing_path, 'MISS');
         $this->verifyPageCache($non_referencing_entity_path, 'HIT');
         $this->verifyPageCache($empty_entity_listing_path, 'HIT');
         $this->verifyPageCache($nonempty_entity_listing_path, 'HIT');
         // Verify cache hits.
         $this->verifyPageCache($referencing_entity_path, 'HIT');
         $this->verifyPageCache($listing_path, 'HIT');
     }
     $bundle_entity_type = $this->entity->getEntityType()->getBundleEntityType();
     if ($bundle_entity_type !== 'bundle') {
         // Verify that after modifying the corresponding bundle entity, there is a
         // cache miss for both the referencing entity, and the listing of
         // referencing entities, but not for any other routes.
         $this->pass("Test modification of referenced entity's bundle entity.", 'Debug');
         $bundle_entity = entity_load($bundle_entity_type, $this->entity->bundle());
         $bundle_entity->save();
         $this->verifyPageCache($referencing_entity_path, 'MISS');
         $this->verifyPageCache($listing_path, 'MISS');
         $this->verifyPageCache($non_referencing_entity_path, 'HIT');
         // Special case: entity types may choose to use their bundle entity type
         // cache tags, to avoid having excessively granular invalidation.
         $is_special_case = $bundle_entity->getCacheTags() == $this->entity->getCacheTags() && $bundle_entity->getEntityType()->getListCacheTags() == $this->entity->getEntityType()->getListCacheTags();
         if ($is_special_case) {
             $this->verifyPageCache($empty_entity_listing_path, 'MISS');
             $this->verifyPageCache($nonempty_entity_listing_path, 'MISS');
         } else {
             $this->verifyPageCache($empty_entity_listing_path, 'HIT');
             $this->verifyPageCache($nonempty_entity_listing_path, 'HIT');
         }
         // Verify cache hits.
         $this->verifyPageCache($referencing_entity_path, 'HIT');
         $this->verifyPageCache($listing_path, 'HIT');
         if ($is_special_case) {
             $this->verifyPageCache($empty_entity_listing_path, 'HIT');
             $this->verifyPageCache($nonempty_entity_listing_path, 'HIT');
         }
     }
     if ($this->entity->getEntityType()->get('field_ui_base_route')) {
         // Verify that after modifying a configurable field on the entity, there
         // is a cache miss.
         $this->pass("Test modification of referenced entity's configurable field.", 'Debug');
         $field_storage_name = $this->entity->getEntityTypeId() . '.configurable_field';
         $field_storage = entity_load('field_storage_config', $field_storage_name);
         $field_storage->save();
         $this->verifyPageCache($referencing_entity_path, 'MISS');
         $this->verifyPageCache($listing_path, 'MISS');
         $this->verifyPageCache($empty_entity_listing_path, 'HIT');
         $this->verifyPageCache($nonempty_entity_listing_path, 'HIT');
         $this->verifyPageCache($non_referencing_entity_path, 'HIT');
         // Verify cache hits.
         $this->verifyPageCache($referencing_entity_path, 'HIT');
         $this->verifyPageCache($listing_path, 'HIT');
         // Verify that after modifying a configurable field on the entity, there
         // is a cache miss.
         $this->pass("Test modification of referenced entity's configurable field.", 'Debug');
         $field_name = $this->entity->getEntityTypeId() . '.' . $this->entity->bundle() . '.configurable_field';
         $field = entity_load('field_config', $field_name);
         $field->save();
         $this->verifyPageCache($referencing_entity_path, 'MISS');
         $this->verifyPageCache($listing_path, 'MISS');
         $this->verifyPageCache($empty_entity_listing_path, 'HIT');
         $this->verifyPageCache($nonempty_entity_listing_path, 'HIT');
         $this->verifyPageCache($non_referencing_entity_path, 'HIT');
         // Verify cache hits.
         $this->verifyPageCache($referencing_entity_path, 'HIT');
         $this->verifyPageCache($listing_path, 'HIT');
     }
     // Verify that after invalidating the entity's cache tag directly, there is
     // a cache miss for every route except the ones for the non-referencing
     // entity and the empty entity listing.
     $this->pass("Test invalidation of referenced entity's cache tag.", 'Debug');
     Cache::invalidateTags($this->entity->getCacheTags());
     $this->verifyPageCache($referencing_entity_path, 'MISS');
     $this->verifyPageCache($listing_path, 'MISS');
     $this->verifyPageCache($nonempty_entity_listing_path, 'MISS');
     $this->verifyPageCache($non_referencing_entity_path, 'HIT');
     $this->verifyPageCache($empty_entity_listing_path, 'HIT');
     // Verify cache hits.
     $this->verifyPageCache($referencing_entity_path, 'HIT');
     $this->verifyPageCache($listing_path, 'HIT');
     $this->verifyPageCache($nonempty_entity_listing_path, 'HIT');
     // Verify that after invalidating the entity's list cache tag directly,
     // there is a cache miss for both the empty entity listing and the non-empty
     // entity listing routes, but not for other routes.
     $this->pass("Test invalidation of referenced entity's list cache tag.", 'Debug');
     Cache::invalidateTags($this->entity->getEntityType()->getListCacheTags());
     $this->verifyPageCache($empty_entity_listing_path, 'MISS');
     $this->verifyPageCache($nonempty_entity_listing_path, 'MISS');
     $this->verifyPageCache($referencing_entity_path, 'HIT');
     $this->verifyPageCache($non_referencing_entity_path, 'HIT');
     $this->verifyPageCache($listing_path, 'HIT');
     // Verify cache hits.
     $this->verifyPageCache($empty_entity_listing_path, 'HIT');
     $this->verifyPageCache($nonempty_entity_listing_path, 'HIT');
     if (!empty($view_cache_tag)) {
         // Verify that after invalidating the generic entity type's view cache tag
         // directly, there is a cache miss for both the referencing entity, and the
         // listing of referencing entities, but not for other routes.
         $this->pass("Test invalidation of referenced entity's 'view' cache tag.", 'Debug');
         Cache::invalidateTags($view_cache_tag);
         $this->verifyPageCache($referencing_entity_path, 'MISS');
         $this->verifyPageCache($listing_path, 'MISS');
         $this->verifyPageCache($non_referencing_entity_path, 'HIT');
         $this->verifyPageCache($empty_entity_listing_path, 'HIT');
         $this->verifyPageCache($nonempty_entity_listing_path, 'HIT');
         // Verify cache hits.
         $this->verifyPageCache($referencing_entity_path, 'HIT');
         $this->verifyPageCache($listing_path, 'HIT');
     }
     // Verify that after deleting the entity, there is a cache miss for every
     // route except for the the non-referencing entity one.
     $this->pass('Test deletion of referenced entity.', 'Debug');
     $this->entity->delete();
     $this->verifyPageCache($referencing_entity_path, 'MISS');
     $this->verifyPageCache($listing_path, 'MISS');
     $this->verifyPageCache($empty_entity_listing_path, 'MISS');
     $this->verifyPageCache($nonempty_entity_listing_path, 'MISS');
     $this->verifyPageCache($non_referencing_entity_path, 'HIT');
     // Verify cache hits.
     $referencing_entity_cache_tags = Cache::mergeTags($this->referencing_entity->getCacheTags(), \Drupal::entityManager()->getViewBuilder('entity_test')->getCacheTags());
     $tags = Cache::mergeTags($render_cache_tags, $theme_cache_tags, $referencing_entity_cache_tags);
     $this->verifyPageCache($referencing_entity_path, 'HIT', $tags);
     $tags = Cache::mergeTags($render_cache_tags, $theme_cache_tags);
     $this->verifyPageCache($listing_path, 'HIT', $tags);
     $tags = Cache::mergeTags($render_cache_tags, $theme_cache_tags, $this->entity->getEntityType()->getListCacheTags());
     $this->verifyPageCache($empty_entity_listing_path, 'HIT', $tags);
     $tags = Cache::mergeTags($tags, $this->getAdditionalCacheTagsForEntityListing());
     $this->verifyPageCache($nonempty_entity_listing_path, 'HIT', $tags);
 }
 /**
  * Tests cache tags presence and invalidation of the entity when referenced.
  *
  * Tests the following cache tags:
  * - entity type view cache tag: "<entity type>_view"
  * - entity cache tag: "<entity type>:<entity ID>"
  * - entity type list cache tag: "<entity type>_list"
  * - referencing entity type view cache tag: "<referencing entity type>_view"
  * - referencing entity type cache tag: "<referencing entity type>:<referencing entity ID>"
  */
 public function testReferencedEntity()
 {
     $entity_type = $this->entity->getEntityTypeId();
     $referencing_entity_url = $this->referencing_entity->urlInfo('canonical');
     $non_referencing_entity_url = $this->non_referencing_entity->urlInfo('canonical');
     $listing_url = Url::fromRoute('entity.entity_test.collection_referencing_entities', ['entity_reference_field_name' => $entity_type . '_reference', 'referenced_entity_type' => $entity_type, 'referenced_entity_id' => $this->entity->id()]);
     $empty_entity_listing_url = Url::fromRoute('entity.entity_test.collection_empty', ['entity_type_id' => $entity_type]);
     $nonempty_entity_listing_url = Url::fromRoute('entity.entity_test.collection_labels_alphabetically', ['entity_type_id' => $entity_type]);
     // The default cache contexts for rendered entities.
     $entity_cache_contexts = ['theme', 'user.roles'];
     // Cache tags present on every rendered page.
     $page_cache_tags = Cache::mergeTags(['rendered'], \Drupal::moduleHandler()->moduleExists('block') ? ['config:block_list'] : []);
     $view_cache_tag = array();
     if ($this->entity->getEntityType()->hasHandlerClass('view_builder')) {
         $view_cache_tag = \Drupal::entityManager()->getViewBuilder($entity_type)->getCacheTags();
     }
     // Generate the cache tags for the (non) referencing entities.
     $referencing_entity_cache_tags = Cache::mergeTags($this->referencing_entity->getCacheTags(), \Drupal::entityManager()->getViewBuilder('entity_test')->getCacheTags(), $this->entity->getCacheTags(), $this->getAdditionalCacheTagsForEntity($this->entity), $view_cache_tag, ['rendered']);
     $non_referencing_entity_cache_tags = Cache::mergeTags($this->non_referencing_entity->getCacheTags(), \Drupal::entityManager()->getViewBuilder('entity_test')->getCacheTags(), ['rendered']);
     // Generate the cache tags for all two possible entity listing paths.
     // 1. list cache tag only (listing query has no match)
     // 2. list cache tag plus entity cache tag (listing query has a match)
     $empty_entity_listing_cache_tags = Cache::mergeTags($this->entity->getEntityType()->getListCacheTags(), $page_cache_tags);
     $nonempty_entity_listing_cache_tags = Cache::mergeTags($this->entity->getEntityType()->getListCacheTags(), $this->entity->getCacheTags(), $this->getAdditionalCacheTagsForEntityListing($this->entity), $page_cache_tags);
     $this->pass("Test referencing entity.", 'Debug');
     $this->verifyPageCache($referencing_entity_url, 'MISS');
     // Verify a cache hit, but also the presence of the correct cache tags.
     $this->verifyPageCache($referencing_entity_url, 'HIT', Cache::mergeTags($referencing_entity_cache_tags, $page_cache_tags));
     // Also verify the existence of an entity render cache entry.
     $cache_keys = ['entity_view', 'entity_test', $this->referencing_entity->id(), 'full'];
     $cid = $this->createCacheId($cache_keys, $entity_cache_contexts);
     $redirected_cid = $this->createRedirectedCacheId($cache_keys, $entity_cache_contexts);
     $this->verifyRenderCache($cid, $referencing_entity_cache_tags, $redirected_cid);
     $this->pass("Test non-referencing entity.", 'Debug');
     $this->verifyPageCache($non_referencing_entity_url, 'MISS');
     // Verify a cache hit, but also the presence of the correct cache tags.
     $this->verifyPageCache($non_referencing_entity_url, 'HIT', Cache::mergeTags($non_referencing_entity_cache_tags, $page_cache_tags));
     // Also verify the existence of an entity render cache entry.
     $cache_keys = ['entity_view', 'entity_test', $this->non_referencing_entity->id(), 'full'];
     $cid = $this->createCacheId($cache_keys, $entity_cache_contexts);
     $this->verifyRenderCache($cid, $non_referencing_entity_cache_tags);
     $this->pass("Test listing of referencing entities.", 'Debug');
     // Prime the page cache for the listing of referencing entities.
     $this->verifyPageCache($listing_url, 'MISS');
     // Verify a cache hit, but also the presence of the correct cache tags.
     $this->verifyPageCache($listing_url, 'HIT', Cache::mergeTags($referencing_entity_cache_tags, $page_cache_tags));
     $this->pass("Test empty listing.", 'Debug');
     // Prime the page cache for the empty listing.
     $this->verifyPageCache($empty_entity_listing_url, 'MISS');
     // Verify a cache hit, but also the presence of the correct cache tags.
     $this->verifyPageCache($empty_entity_listing_url, 'HIT', $empty_entity_listing_cache_tags);
     // Verify the entity type's list cache contexts are present.
     $contexts_in_header = $this->drupalGetHeader('X-Drupal-Cache-Contexts');
     $this->assertEqual($this->getAdditionalCacheContextsForEntityListing(), empty($contexts_in_header) ? [] : explode(' ', $contexts_in_header));
     $this->pass("Test listing containing referenced entity.", 'Debug');
     // Prime the page cache for the listing containing the referenced entity.
     $this->verifyPageCache($nonempty_entity_listing_url, 'MISS', $nonempty_entity_listing_cache_tags);
     // Verify a cache hit, but also the presence of the correct cache tags.
     $this->verifyPageCache($nonempty_entity_listing_url, 'HIT', $nonempty_entity_listing_cache_tags);
     // Verify the entity type's list cache contexts are present.
     $contexts_in_header = $this->drupalGetHeader('X-Drupal-Cache-Contexts');
     $this->assertEqual($this->getAdditionalCacheContextsForEntityListing(), empty($contexts_in_header) ? [] : explode(' ', $contexts_in_header));
     // Verify that after modifying the referenced entity, there is a cache miss
     // for every route except the one for the non-referencing entity.
     $this->pass("Test modification of referenced entity.", 'Debug');
     $this->entity->save();
     $this->verifyPageCache($referencing_entity_url, 'MISS');
     $this->verifyPageCache($listing_url, 'MISS');
     $this->verifyPageCache($empty_entity_listing_url, 'MISS');
     $this->verifyPageCache($nonempty_entity_listing_url, 'MISS');
     $this->verifyPageCache($non_referencing_entity_url, 'HIT');
     // Verify cache hits.
     $this->verifyPageCache($referencing_entity_url, 'HIT');
     $this->verifyPageCache($listing_url, 'HIT');
     $this->verifyPageCache($empty_entity_listing_url, 'HIT');
     $this->verifyPageCache($nonempty_entity_listing_url, 'HIT');
     // Verify that after modifying the referencing entity, there is a cache miss
     // for every route except the ones for the non-referencing entity and the
     // empty entity listing.
     $this->pass("Test modification of referencing entity.", 'Debug');
     $this->referencing_entity->save();
     $this->verifyPageCache($referencing_entity_url, 'MISS');
     $this->verifyPageCache($listing_url, 'MISS');
     $this->verifyPageCache($nonempty_entity_listing_url, 'HIT');
     $this->verifyPageCache($non_referencing_entity_url, 'HIT');
     $this->verifyPageCache($empty_entity_listing_url, 'HIT');
     // Verify cache hits.
     $this->verifyPageCache($referencing_entity_url, 'HIT');
     $this->verifyPageCache($listing_url, 'HIT');
     $this->verifyPageCache($nonempty_entity_listing_url, 'HIT');
     // Verify that after modifying the non-referencing entity, there is a cache
     // miss only for the non-referencing entity route.
     $this->pass("Test modification of non-referencing entity.", 'Debug');
     $this->non_referencing_entity->save();
     $this->verifyPageCache($referencing_entity_url, 'HIT');
     $this->verifyPageCache($listing_url, 'HIT');
     $this->verifyPageCache($empty_entity_listing_url, 'HIT');
     $this->verifyPageCache($nonempty_entity_listing_url, 'HIT');
     $this->verifyPageCache($non_referencing_entity_url, 'MISS');
     // Verify cache hits.
     $this->verifyPageCache($non_referencing_entity_url, 'HIT');
     if ($this->entity->getEntityType()->hasHandlerClass('view_builder')) {
         // Verify that after modifying the entity's display, there is a cache miss
         // for both the referencing entity, and the listing of referencing
         // entities, but not for any other routes.
         $referenced_entity_view_mode = $this->selectViewMode($this->entity->getEntityTypeId());
         $this->pass("Test modification of referenced entity's '{$referenced_entity_view_mode}' display.", 'Debug');
         $entity_display = entity_get_display($entity_type, $this->entity->bundle(), $referenced_entity_view_mode);
         $entity_display->save();
         $this->verifyPageCache($referencing_entity_url, 'MISS');
         $this->verifyPageCache($listing_url, 'MISS');
         $this->verifyPageCache($non_referencing_entity_url, 'HIT');
         $this->verifyPageCache($empty_entity_listing_url, 'HIT');
         $this->verifyPageCache($nonempty_entity_listing_url, 'HIT');
         // Verify cache hits.
         $this->verifyPageCache($referencing_entity_url, 'HIT');
         $this->verifyPageCache($listing_url, 'HIT');
     }
     $bundle_entity_type = $this->entity->getEntityType()->getBundleEntityType();
     if ($bundle_entity_type !== 'bundle') {
         // Verify that after modifying the corresponding bundle entity, there is a
         // cache miss for both the referencing entity, and the listing of
         // referencing entities, but not for any other routes.
         $this->pass("Test modification of referenced entity's bundle entity.", 'Debug');
         $bundle_entity = entity_load($bundle_entity_type, $this->entity->bundle());
         $bundle_entity->save();
         $this->verifyPageCache($referencing_entity_url, 'MISS');
         $this->verifyPageCache($listing_url, 'MISS');
         $this->verifyPageCache($non_referencing_entity_url, 'HIT');
         // Special case: entity types may choose to use their bundle entity type
         // cache tags, to avoid having excessively granular invalidation.
         $is_special_case = $bundle_entity->getCacheTags() == $this->entity->getCacheTags() && $bundle_entity->getEntityType()->getListCacheTags() == $this->entity->getEntityType()->getListCacheTags();
         if ($is_special_case) {
             $this->verifyPageCache($empty_entity_listing_url, 'MISS');
             $this->verifyPageCache($nonempty_entity_listing_url, 'MISS');
         } else {
             $this->verifyPageCache($empty_entity_listing_url, 'HIT');
             $this->verifyPageCache($nonempty_entity_listing_url, 'HIT');
         }
         // Verify cache hits.
         $this->verifyPageCache($referencing_entity_url, 'HIT');
         $this->verifyPageCache($listing_url, 'HIT');
         if ($is_special_case) {
             $this->verifyPageCache($empty_entity_listing_url, 'HIT');
             $this->verifyPageCache($nonempty_entity_listing_url, 'HIT');
         }
     }
     if ($this->entity->getEntityType()->get('field_ui_base_route')) {
         // Verify that after modifying a configurable field on the entity, there
         // is a cache miss.
         $this->pass("Test modification of referenced entity's configurable field.", 'Debug');
         $field_storage_name = $this->entity->getEntityTypeId() . '.configurable_field';
         $field_storage = FieldStorageConfig::load($field_storage_name);
         $field_storage->save();
         $this->verifyPageCache($referencing_entity_url, 'MISS');
         $this->verifyPageCache($listing_url, 'MISS');
         $this->verifyPageCache($empty_entity_listing_url, 'HIT');
         $this->verifyPageCache($nonempty_entity_listing_url, 'HIT');
         $this->verifyPageCache($non_referencing_entity_url, 'HIT');
         // Verify cache hits.
         $this->verifyPageCache($referencing_entity_url, 'HIT');
         $this->verifyPageCache($listing_url, 'HIT');
         // Verify that after modifying a configurable field on the entity, there
         // is a cache miss.
         $this->pass("Test modification of referenced entity's configurable field.", 'Debug');
         $field_name = $this->entity->getEntityTypeId() . '.' . $this->entity->bundle() . '.configurable_field';
         $field = FieldConfig::load($field_name);
         $field->save();
         $this->verifyPageCache($referencing_entity_url, 'MISS');
         $this->verifyPageCache($listing_url, 'MISS');
         $this->verifyPageCache($empty_entity_listing_url, 'HIT');
         $this->verifyPageCache($nonempty_entity_listing_url, 'HIT');
         $this->verifyPageCache($non_referencing_entity_url, 'HIT');
         // Verify cache hits.
         $this->verifyPageCache($referencing_entity_url, 'HIT');
         $this->verifyPageCache($listing_url, 'HIT');
     }
     // Verify that after invalidating the entity's cache tag directly, there is
     // a cache miss for every route except the ones for the non-referencing
     // entity and the empty entity listing.
     $this->pass("Test invalidation of referenced entity's cache tag.", 'Debug');
     Cache::invalidateTags($this->entity->getCacheTags());
     $this->verifyPageCache($referencing_entity_url, 'MISS');
     $this->verifyPageCache($listing_url, 'MISS');
     $this->verifyPageCache($nonempty_entity_listing_url, 'MISS');
     $this->verifyPageCache($non_referencing_entity_url, 'HIT');
     $this->verifyPageCache($empty_entity_listing_url, 'HIT');
     // Verify cache hits.
     $this->verifyPageCache($referencing_entity_url, 'HIT');
     $this->verifyPageCache($listing_url, 'HIT');
     $this->verifyPageCache($nonempty_entity_listing_url, 'HIT');
     // Verify that after invalidating the entity's list cache tag directly,
     // there is a cache miss for both the empty entity listing and the non-empty
     // entity listing routes, but not for other routes.
     $this->pass("Test invalidation of referenced entity's list cache tag.", 'Debug');
     Cache::invalidateTags($this->entity->getEntityType()->getListCacheTags());
     $this->verifyPageCache($empty_entity_listing_url, 'MISS');
     $this->verifyPageCache($nonempty_entity_listing_url, 'MISS');
     $this->verifyPageCache($referencing_entity_url, 'HIT');
     $this->verifyPageCache($non_referencing_entity_url, 'HIT');
     $this->verifyPageCache($listing_url, 'HIT');
     // Verify cache hits.
     $this->verifyPageCache($empty_entity_listing_url, 'HIT');
     $this->verifyPageCache($nonempty_entity_listing_url, 'HIT');
     if (!empty($view_cache_tag)) {
         // Verify that after invalidating the generic entity type's view cache tag
         // directly, there is a cache miss for both the referencing entity, and the
         // listing of referencing entities, but not for other routes.
         $this->pass("Test invalidation of referenced entity's 'view' cache tag.", 'Debug');
         Cache::invalidateTags($view_cache_tag);
         $this->verifyPageCache($referencing_entity_url, 'MISS');
         $this->verifyPageCache($listing_url, 'MISS');
         $this->verifyPageCache($non_referencing_entity_url, 'HIT');
         $this->verifyPageCache($empty_entity_listing_url, 'HIT');
         $this->verifyPageCache($nonempty_entity_listing_url, 'HIT');
         // Verify cache hits.
         $this->verifyPageCache($referencing_entity_url, 'HIT');
         $this->verifyPageCache($listing_url, 'HIT');
     }
     // Verify that after deleting the entity, there is a cache miss for every
     // route except for the non-referencing entity one.
     $this->pass('Test deletion of referenced entity.', 'Debug');
     $this->entity->delete();
     $this->verifyPageCache($referencing_entity_url, 'MISS');
     $this->verifyPageCache($listing_url, 'MISS');
     $this->verifyPageCache($empty_entity_listing_url, 'MISS');
     $this->verifyPageCache($nonempty_entity_listing_url, 'MISS');
     $this->verifyPageCache($non_referencing_entity_url, 'HIT');
     // Verify cache hits.
     $referencing_entity_cache_tags = Cache::mergeTags($this->referencing_entity->getCacheTags(), \Drupal::entityManager()->getViewBuilder('entity_test')->getCacheTags(), ['rendered']);
     $this->verifyPageCache($referencing_entity_url, 'HIT', Cache::mergeTags($referencing_entity_cache_tags, $page_cache_tags));
     $this->verifyPageCache($listing_url, 'HIT', $page_cache_tags);
     $this->verifyPageCache($empty_entity_listing_url, 'HIT', $empty_entity_listing_cache_tags);
     $this->verifyPageCache($nonempty_entity_listing_url, 'HIT', Cache::mergeTags($this->entity->getEntityType()->getListCacheTags(), $this->getAdditionalCacheTagsForEntityListing(), $page_cache_tags));
 }