core/modules/contact/contact.info.yml | 2 + .../contact/src/Controller/ContactController.php | 3 + .../contact/src/Tests/ContactFormCacheTagsTest.php | 98 ++++++++++++++++++++++ core/modules/editor/src/Element.php | 8 ++ .../filter/src/Tests/FilterFormatCacheTagsTest.php | 96 +++++++++++++++++++++ 5 files changed, 207 insertions(+) diff --git a/core/modules/contact/contact.info.yml b/core/modules/contact/contact.info.yml index a50d17d..e02742d 100644 --- a/core/modules/contact/contact.info.yml +++ b/core/modules/contact/contact.info.yml @@ -5,3 +5,5 @@ package: Core version: VERSION core: 8.x configure: contact.form_list +dependencies: + - field diff --git a/core/modules/contact/src/Controller/ContactController.php b/core/modules/contact/src/Controller/ContactController.php index cffbf5a..5759fc6 100644 --- a/core/modules/contact/src/Controller/ContactController.php +++ b/core/modules/contact/src/Controller/ContactController.php @@ -7,6 +7,7 @@ namespace Drupal\contact\Controller; +use Drupal\contact\Entity\ContactForm; use Drupal\Core\Controller\ControllerBase; use Drupal\Core\Datetime\DateFormatter; use Drupal\Core\Flood\FloodInterface; @@ -104,6 +105,7 @@ public function contactSitePage(ContactFormInterface $contact_form = NULL) { $form = $this->entityFormBuilder()->getForm($message); $form['#title'] = String::checkPlain($contact_form->label()); + $form['#cache']['tags'] = drupal_merge_cache_tags($contact_form->getCacheTag(), entity_get_form_display('contact_message', 'feedback', 'default')->getCacheTag()); return $form; } @@ -129,6 +131,7 @@ public function contactPersonalPage(UserInterface $user) { $form = $this->entityFormBuilder()->getForm($message); $form['#title'] = $this->t('Contact @username', array('@username' => $user->getUsername())); + $form['#cache']['tags'] = drupal_merge_cache_tags(ContactForm::load('personal')->getCacheTag(), entity_get_form_display('contact_message', 'personal', 'default')->getCacheTag()); return $form; } diff --git a/core/modules/contact/src/Tests/ContactFormCacheTagsTest.php b/core/modules/contact/src/Tests/ContactFormCacheTagsTest.php new file mode 100644 index 0000000..5b1f2b5 --- /dev/null +++ b/core/modules/contact/src/Tests/ContactFormCacheTagsTest.php @@ -0,0 +1,98 @@ +grantPermission('access site-wide contact form') + ->grantPermission('access user contact forms') + ->save(); + } + + /** + * Tests cache tags presence and invalidation of the Contact form entity. + * + * Tests the following cache tags: + * - ['contact_form' => ''] + */ + public function testContactForm() { + // Test the site-wide contact form. Rendered by + // ContactController::contactSitePage(). + $this->assertContactForm('feedback', 'contact'); + + // Test a personal contact form. Rendered by + // ContactController::contactPersonalPage(). + $this->assertContactForm('personal', 'user/1/contact'); + } + + /** + * Asserts whether a contact form is correctly tagged with cache tags. + * + * @param string $id + * A contact form entity ID. + * @param $path + * The corresponding path, where this contact form is rendered. + */ + protected function assertContactForm($id, $path) { + // Prime the page cache. + $this->verifyPageCache($path, 'MISS'); + + // Verify a cache hit, but also the presence of the correct cache tags. + $expected_tags = array( + 'theme:stark', + 'theme_global_settings:1', + 'contact_form:' . $id, + 'entity_form_display:contact_message.' . $id . '.default', + 'rendered:1', + ); + $this->verifyPageCache($path, 'HIT', $expected_tags); + + // Verify that after modifying the contact form, there is a cache miss. + $this->pass('Test modification of contact form.', 'Debug'); + ContactForm::load($id)->save(); + $this->verifyPageCache($path, 'MISS'); + + // Verify a cache hit. + $this->verifyPageCache($path, 'HIT', $expected_tags); + + // Verify that after modifying the contact form's form display, there is a + // cache miss. + $this->pass('Test modification of form display of contact form.', 'Debug'); + $entity_form_display = entity_get_form_display('contact_message', $id, 'default'); + $entity_form_display->enforceIsNew(FALSE)->save(); + + $this->verifyPageCache($path, 'MISS'); + + // Verify a cache hit. + $this->verifyPageCache($path, 'HIT', $expected_tags); + } + +} diff --git a/core/modules/editor/src/Element.php b/core/modules/editor/src/Element.php index f0b97bf..da1aef2 100644 --- a/core/modules/editor/src/Element.php +++ b/core/modules/editor/src/Element.php @@ -52,6 +52,7 @@ function preRenderTextFormat(array $element) { $format_ids = array_keys($element['format']['format']['#options']); // Early-return if no text editor is associated with any of the text formats. + /** @var \Drupal\editor\EditorInterface[] $editors */ $editors = Editor::loadMultiple($format_ids); if (count($editors) === 0) { return $element; @@ -84,6 +85,13 @@ function preRenderTextFormat(array $element) { $element['format']['guidelines'][$format_id]['#access'] = FALSE; } + // Associate the Text Editor's cache tags. + $cache_tags = isset($element['#cache']['tags']) ? $element['#cache']['tags'] : []; + foreach ($editors as $editor) { + $cache_tags = drupal_merge_cache_tags($cache_tags, $editor->getCacheTag()); + } + $element['#cache']['tags'] = $cache_tags; + // Attach Text Editor module's (this module) library. $element['#attached']['library'][] = 'editor/drupal.editor'; diff --git a/core/modules/filter/src/Tests/FilterFormatCacheTagsTest.php b/core/modules/filter/src/Tests/FilterFormatCacheTagsTest.php new file mode 100644 index 0000000..e8b7872 --- /dev/null +++ b/core/modules/filter/src/Tests/FilterFormatCacheTagsTest.php @@ -0,0 +1,96 @@ + 'Llama', + 'type' => 'basic', + 'body' => [ + 'value' => 'The name "llama" was adopted by European settlers from native Peruvians.', + 'format' => 'plain_text', + ], + ])->save(); + + // Place it, so we can look at cache tags on the front page. + $this->drupalPlaceBlock('block_content:' . BlockContent::load(1)->uuid()); + } + + /** + * Tests cache tags presence and invalidation of the Text format entity. + * + * Tests the following cache tags: + * - ['filter_format' => ''] + */ + public function testRenderedFilterFormat() { + $id = 'plain_text'; + $path = ''; + + $block_content = BlockContent::load(1); + $matching_block_ids = array_keys(entity_load_multiple_by_properties('block', ['plugin' => 'block_content:' . $block_content->uuid()])); + $base_tags= array( + 'theme:stark', + 'theme_global_settings:1', + 'block_view:1', + 'block:' . $matching_block_ids[0], + 'block_plugin:block_content__' . $block_content->uuid(), + 'block_content_view:1', + 'block_content:1', + 'rendered:1', + ); + + // Prime the page cache. + $this->verifyPageCache($path, 'MISS'); + + // Verify a cache hit, but also the presence of the correct cache tags. + $expected_tags = $base_tags; + $expected_tags[] = 'filter_format:plain_text'; + $this->verifyPageCache($path, 'HIT', $expected_tags); + + // Verify that after modifying the text format, there is a cache miss. + $this->pass('Test modification of text format.', 'Debug'); + FilterFormat::load($id)->save(); + $this->verifyPageCache($path, 'MISS'); + + // Verify a cache hit. + $this->verifyPageCache($path, 'HIT', $expected_tags); + + // Verify that after deleting the text format, there is a cache miss. + $this->pass('Test deletion of text format.', 'Debug'); + FilterFormat::load($id)->delete(); + $this->verifyPageCache($path, 'MISS'); + + // Verify a cache hit. + $this->verifyPageCache($path, 'HIT', $base_tags); + } + +}