diff --git a/core/includes/common.inc b/core/includes/common.inc
index 5572e54..edefe1d 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -3468,7 +3468,6 @@ function drupal_render(&$elements, $is_recursive_call = FALSE) {
*
* @return string
* The rendered HTML of all children of the element.
-
* @see drupal_render()
*/
function drupal_render_children(&$element, $children_keys = NULL) {
@@ -3681,7 +3680,7 @@ function drupal_render_cache_generate_placeholder($callback, array &$context) {
'token' => \Drupal\Component\Utility\Crypt::randomBytesBase64(55),
);
- return '';
+ return '';
}
/**
diff --git a/core/modules/ckeditor/src/Plugin/CKEditorPlugin/Internal.php b/core/modules/ckeditor/src/Plugin/CKEditorPlugin/Internal.php
index 7272357..c0faa78 100644
--- a/core/modules/ckeditor/src/Plugin/CKEditorPlugin/Internal.php
+++ b/core/modules/ckeditor/src/Plugin/CKEditorPlugin/Internal.php
@@ -9,6 +9,7 @@
use Drupal\ckeditor\CKEditorPluginBase;
use Drupal\Component\Utility\NestedArray;
+use Drupal\Core\Cache\Cache;
use Drupal\editor\Entity\Editor;
use Drupal\filter\Plugin\FilterInterface;
@@ -251,22 +252,42 @@ public function getButtons() {
* An array containing the "format_tags" configuration.
*/
protected function generateFormatTagsSetting(Editor $editor) {
- // The
tag is always allowed — HTML without
tags is nonsensical.
- $format_tags = array('p');
+ // When no text format is associated yet, assume no tag is allowed.
+ // @see \Drupal\Editor\EditorInterface::hasAssociatedFilterFormat()
+ if (!$editor->hasAssociatedFilterFormat()) {
+ return array();
+ }
- // Given the list of possible format tags, automatically determine whether
- // the current text format allows this tag, and thus whether it should show
- // up in the "Format" dropdown.
- $possible_format_tags = array('h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'pre');
- foreach ($possible_format_tags as $tag) {
- $input = '<' . $tag . '>TEST' . $tag . '>';
- $output = trim(check_markup($input, $editor->id(), '', TRUE));
- if ($input == $output) {
- $format_tags[] = $tag;
+ $format = $editor->getFilterFormat();
+ $cid = 'ckeditor_internal_format_tags:' . $format->id();
+
+ if ($cached = \Drupal::cache()->get($cid)) {
+ $format_tags = $cached->data;
+ }
+ else {
+ // The
tag is always allowed — HTML without
tags is nonsensical.
+ $format_tags = array('p');
+
+ // Given the list of possible format tags, automatically determine whether
+ // the current text format allows this tag, and thus whether it should show
+ // up in the "Format" dropdown.
+ $possible_format_tags = array('h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'pre');
+ foreach ($possible_format_tags as $tag) {
+ $input = '<' . $tag . '>TEST' . $tag . '>';
+ $output = trim(check_markup($input, $editor->id()));
+ if ($input == $output) {
+ $format_tags[] = $tag;
+ }
}
+ $format_tags = implode(';', $format_tags);
+
+ // Cache the "format_tags" configuration. This cache item is infinitely
+ // valid; it only changes whenever the text format is changed, hence it's
+ // tagged with the text format's cache tag.
+ \Drupal::cache()->set($cid, $format_tags, Cache::PERMANENT, $format->getCacheTag());
}
- return implode(';', $format_tags);
+ return $format_tags;
}
/**
diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module
index b09bfa8..4844daf 100644
--- a/core/modules/comment/comment.module
+++ b/core/modules/comment/comment.module
@@ -1369,8 +1369,9 @@ function template_preprocess_comment(&$variables) {
$variables['user_picture'] = array();
}
- if (\Drupal::config('user.settings')->get('signatures') && $account->getSignature()) {
- $variables['signature'] = check_markup($account->getSignature(), $account->getSignatureFormat(), '', TRUE) ;
+ if (isset($variables['elements']['signature'])) {
+ $variables['signature'] = $variables['elements']['signature']['#markup'];
+ unset($variables['elements']['signature']);
}
else {
$variables['signature'] = '';
diff --git a/core/modules/comment/src/CommentViewBuilder.php b/core/modules/comment/src/CommentViewBuilder.php
index e993e7a..7769b5e 100644
--- a/core/modules/comment/src/CommentViewBuilder.php
+++ b/core/modules/comment/src/CommentViewBuilder.php
@@ -131,6 +131,21 @@ public function buildComponents(array &$build, array $entities, array $displays,
'#markup' => $placeholder,
);
+ $account = comment_prepare_author($entity);
+ if (\Drupal::config('user.settings')->get('signatures') && $account->getSignature()) {
+ $build[$id]['signature'] = array(
+ '#type' => 'processed_text',
+ '#text' => $account->getSignature(),
+ '#format' => $account->getSignatureFormat(),
+ '#langcode' => $entity->language()->getId(),
+ );
+ // The signature will only be rendered in the theme layer, which means
+ // its associated cache tags will not bubble up. Work around this for
+ // now by already rendering the signature here.
+ // @todo remove this work-around, see https://drupal.org/node/2273277
+ drupal_render($build[$id]['signature'], TRUE);
+ }
+
if (!isset($build[$id]['#attached'])) {
$build[$id]['#attached'] = array();
}
diff --git a/core/modules/editor/src/EditorController.php b/core/modules/editor/src/EditorController.php
index 59c1ef9..e5a768e 100644
--- a/core/modules/editor/src/EditorController.php
+++ b/core/modules/editor/src/EditorController.php
@@ -47,7 +47,7 @@ public function getUntransformedText(EntityInterface $entity, $field_name, $lang
// Direct text editing is only supported for single-valued fields.
$field = $entity->getTranslation($langcode)->$field_name;
- $editable_text = check_markup($field->value, $field->format, $langcode, FALSE, array(FilterInterface::TYPE_TRANSFORM_REVERSIBLE, FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE));
+ $editable_text = check_markup($field->value, $field->format, $langcode, array(FilterInterface::TYPE_TRANSFORM_REVERSIBLE, FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE));
$response->addCommand(new GetUntransformedTextCommand($editable_text));
return $response;
diff --git a/core/modules/editor/src/Plugin/Filter/EditorFileReference.php b/core/modules/editor/src/Plugin/Filter/EditorFileReference.php
new file mode 100644
index 0000000..37717a0
--- /dev/null
+++ b/core/modules/editor/src/Plugin/Filter/EditorFileReference.php
@@ -0,0 +1,55 @@
+query('//*[@data-editor-file-uuid]') as $node) {
+ $uuid = $node->getAttribute('data-editor-file-uuid');
+ // Only process the first occurrence of each file UUID.
+ if (!isset($processed_uuids[$uuid])) {
+ $processed_uuids[$uuid] = TRUE;
+
+ $file = entity_load_by_uuid('file', $uuid);
+ if ($file) {
+ $result->addCacheTags($file->getCacheTag());
+ }
+ }
+ }
+ }
+
+ return $result;
+ }
+
+}
diff --git a/core/modules/editor/src/Tests/EditorFileReferenceFilterTest.php b/core/modules/editor/src/Tests/EditorFileReferenceFilterTest.php
new file mode 100644
index 0000000..d0bfbb5
--- /dev/null
+++ b/core/modules/editor/src/Tests/EditorFileReferenceFilterTest.php
@@ -0,0 +1,120 @@
+ 'Editor File Reference filter',
+ 'description' => "Tests Editor module's file reference filter.",
+ 'group' => 'Text Editor',
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function setUp() {
+ parent::setUp();
+ $this->installConfig(array('system'));
+ $this->installSchema('file', array('file_managed', 'file_usage'));
+
+ $manager = $this->container->get('plugin.manager.filter');
+ $bag = new FilterBag($manager, array());
+ $this->filters = $bag->getAll();
+ }
+
+ /**
+ * Tests the editor file reference filter.
+ */
+ function testEditorFileReferenceFilter() {
+ $filter = $this->filters['editor_file_reference'];
+
+ $test = function($input) use ($filter) {
+ return $filter->process($input, 'und');
+ };
+
+ file_put_contents('public://llama.jpg', $this->randomName());
+ $image = entity_create('file', array('uri' => 'public://llama.jpg'));
+ $image->save();
+ $id = $image->id();
+ $uuid = $image->uuid();
+
+ file_put_contents('public://alpaca.jpg', $this->randomName());
+ $image_2 = entity_create('file', array('uri' => 'public://alpaca.jpg'));
+ $image_2->save();
+ $id_2 = $image_2->id();
+ $uuid_2 = $image_2->uuid();
+
+ $this->pass('No data-editor-file-uuid attribute.');
+ $input = '';
+ $output = $test($input);
+ $this->assertIdentical($input, $output->getProcessedText());
+
+ $this->pass('One data-editor-file-uuid attribute.');
+ $input = '';
+ $output = $test($input);
+ $this->assertIdentical($input, $output->getProcessedText());
+ $this->assertEqual(array('file' => array($id)), $output->getCacheTags());
+
+ $this->pass('One data-editor-file-uuid attribute with odd capitalization.');
+ $input = '';
+ $output = $test($input);
+ $this->assertIdentical($input, $output->getProcessedText());
+ $this->assertEqual(array('file' => array($id)), $output->getCacheTags());
+
+ $this->pass('One data-editor-file-uuid attribute on a non-image tag.');
+ $input = '';
+ $output = $test($input);
+ $this->assertIdentical($input, $output->getProcessedText());
+ $this->assertEqual(array('file' => array($id)), $output->getCacheTags());
+
+ $this->pass('One data-editor-file-uuid attribute with an invalid value.');
+ $input = '';
+ $output = $test($input);
+ $this->assertIdentical($input, $output->getProcessedText());
+ $this->assertEqual(array(), $output->getCacheTags());
+
+ $this->pass('Two different data-editor-file-uuid attributes.');
+ $input = '';
+ $input .= '';
+ $output = $test($input);
+ $this->assertIdentical($input, $output->getProcessedText());
+ $this->assertEqual(array('file' => array($id, $id_2)), $output->getCacheTags());
+
+ $this->pass('Two identical data-editor-file-uuid attributes.');
+ $input = '';
+ $input .= '';
+ $output = $test($input);
+ $this->assertIdentical($input, $output->getProcessedText());
+ $this->assertEqual(array('file' => array($id)), $output->getCacheTags());
+ }
+
+}
diff --git a/core/modules/entity_reference/src/Plugin/Field/FieldFormatter/EntityReferenceEntityFormatter.php b/core/modules/entity_reference/src/Plugin/Field/FieldFormatter/EntityReferenceEntityFormatter.php
index 410a256..4065ea2 100644
--- a/core/modules/entity_reference/src/Plugin/Field/FieldFormatter/EntityReferenceEntityFormatter.php
+++ b/core/modules/entity_reference/src/Plugin/Field/FieldFormatter/EntityReferenceEntityFormatter.php
@@ -106,6 +106,7 @@ public function viewElements(FieldItemListInterface $items) {
// its cache tags to be bubbled up and included with those of the
// main entity when cache tags are collected for a renderable array
// in drupal_render().
+ // @todo remove this work-around, see https://drupal.org/node/2273277
$referenced_entity_build = entity_view($item->entity, $view_mode, $item->getLangcode());
drupal_render($referenced_entity_build, TRUE);
$elements[$delta] = $referenced_entity_build;
diff --git a/core/modules/entity_reference/src/Tests/EntityReferenceFormatterTest.php b/core/modules/entity_reference/src/Tests/EntityReferenceFormatterTest.php
index 37fd4b1..61d0ee5 100644
--- a/core/modules/entity_reference/src/Tests/EntityReferenceFormatterTest.php
+++ b/core/modules/entity_reference/src/Tests/EntityReferenceFormatterTest.php
@@ -60,8 +60,6 @@ public static function getInfo() {
public function setUp() {
parent::setUp();
- $this->installConfig(array('filter'));
-
entity_reference_create_instance($this->entityType, $this->bundle, $this->fieldName, 'Field test', $this->entityType);
// Set up a field, so that the entity that'll be referenced bubbles up a
@@ -88,6 +86,11 @@ public function setUp() {
))
->save();
+ entity_create('filter_format', array(
+ 'format' => 'full_html',
+ 'name' => 'Full HTML',
+ ))->save();
+
// Create the entity to be referenced.
$this->referencedEntity = entity_create($this->entityType, array('name' => $this->randomName()));
$this->referencedEntity->body = array(
@@ -180,7 +183,7 @@ public function testEntityFormatter() {
$expected_rendered_body_field = '
Body:
-
+
Hello, world!
';
diff --git a/core/modules/filter/config/install/filter.format.plain_text.yml b/core/modules/filter/config/install/filter.format.plain_text.yml
index 70abb88..5de8988 100644
--- a/core/modules/filter/config/install/filter.format.plain_text.yml
+++ b/core/modules/filter/config/install/filter.format.plain_text.yml
@@ -9,7 +9,6 @@ weight: 10
roles:
- anonymous
- authenticated
-cache: true
filters:
# Escape all HTML.
filter_html_escape:
diff --git a/core/modules/filter/config/schema/filter.schema.yml b/core/modules/filter/config/schema/filter.schema.yml
index f1df7df..e0f53e3 100644
--- a/core/modules/filter/config/schema/filter.schema.yml
+++ b/core/modules/filter/config/schema/filter.schema.yml
@@ -36,9 +36,6 @@ filter.format.*:
sequence:
- type: string
label: 'Role'
- cache:
- type: boolean
- label: 'Cache'
filters:
type: sequence
label: 'Enabled filters'
@@ -47,6 +44,9 @@ filter.format.*:
langcode:
type: string
label: 'Default language'
+ dependencies:
+ type: config_dependencies
+ label: 'Dependencies'
filter_settings.*:
type: sequence
diff --git a/core/modules/filter/filter.module b/core/modules/filter/filter.module
index 3efe9ad..5c0a4e2 100644
--- a/core/modules/filter/filter.module
+++ b/core/modules/filter/filter.module
@@ -6,6 +6,7 @@
*/
use Drupal\Component\Utility\Html;
+use Drupal\Component\Utility\NestedArray;
use Drupal\Component\Utility\String;
use Drupal\Component\Utility\Xss;
use Drupal\Core\Cache\Cache;
@@ -98,10 +99,137 @@ function filter_element_info() {
'#base_type' => 'textarea',
'#theme_wrappers' => array('text_format_wrapper'),
);
+ $type['processed_text'] = array(
+ '#text' => '',
+ '#format' => NULL,
+ '#filter_types_to_skip' => array(),
+ '#langcode' => 'und',
+ '#pre_render' => array('filter_pre_render_text'),
+ );
return $type;
}
/**
+ * Pre-render callback: Renders a processed text element into #markup.
+ *
+ * Runs all the enabled filters on a piece of text.
+ *
+ * Note: Because filters can inject JavaScript or execute PHP code, security is
+ * vital here. When a user supplies a text format, you should validate it using
+ * $format->access() before accepting/using it. This is normally done in the
+ * validation stage of the Form API. You should for example never make a
+ * preview of content in a disallowed format.
+ *
+ * @param array $element
+ * A structured array with the following key-value pairs:
+ * - #text: containing the text to be filtered
+ * - #format: containing the machine name of the filter format to be used to
+ * filter the text. Defaults to the fallback format. See
+ * filter_fallback_format().
+ * - #langcode: the language code of the text to be filtered, e.g. 'en' for
+ * English. This allows filters to be language-aware so language-specific
+ * text replacement can be implemented. Defaults to 'und'.
+ * - #filter_types_to_skip: an array of filter types to skip, or an empty
+ * array (default) to skip no filter types. All of the format's filters will
+ * be applied, except for filters of the types that are marked to be skipped.
+ * FilterInterface::TYPE_HTML_RESTRICTOR is the only type that cannot be
+ * skipped.
+ *
+ * @return array
+ * The passed-in element with the filtered text in '#markup'.
+ *
+ * @ingroup sanitization
+ */
+function filter_pre_render_text(array $element) {
+ $format_id = $element['#format'];
+ $filter_types_to_skip = $element['#filter_types_to_skip'];
+ $text = $element['#text'];
+ $langcode = $element['#langcode'];
+
+ if (!isset($format_id)) {
+ $format_id = filter_fallback_format();
+ }
+ // If the requested text format does not exist, the text cannot be filtered.
+ /** @var \Drupal\filter\Entity\FilterFormat $format **/
+ if (!$format = entity_load('filter_format', $format_id)) {
+ watchdog('filter', 'Missing text format: %format.', array('%format' => $format_id), WATCHDOG_ALERT);
+ $element['#markup'] = '';
+ return $element;
+ }
+
+ // Prevent FilterInterface::TYPE_HTML_RESTRICTOR from being skipped.
+ if (in_array(FilterInterface::TYPE_HTML_RESTRICTOR, $filter_types_to_skip)) {
+ $filter_types_to_skip = array_diff($filter_types_to_skip, array(FilterInterface::TYPE_HTML_RESTRICTOR));
+ }
+
+ // Convert all Windows and Mac newlines to a single newline, so filters only
+ // need to deal with one possibility.
+ $text = str_replace(array("\r\n", "\r"), "\n", $text);
+
+ // Get a complete list of filters, ordered properly.
+ /** @var \Drupal\filter\FilterBag $filters **/
+ $filters = $format->filters();
+
+ // Give filters the chance to escape HTML-like data such as code or formulas.
+ /** @var \Drupal\filter\Plugin\FilterInterface $filter **/
+ foreach ($filters as $filter) {
+ // If necessary, skip filters of a certain type.
+ if (in_array($filter->getType(), $filter_types_to_skip)) {
+ continue;
+ }
+ if ($filter->status) {
+ $text = $filter->prepare($text, $langcode);
+ }
+ }
+
+ // Perform filtering.
+ $all_cache_tags = array();
+ $all_assets = array();
+ $all_post_render_cache_callbacks = array();
+ foreach ($filters as $filter) {
+ // If necessary, skip filters of a certain type.
+ if (in_array($filter->getType(), $filter_types_to_skip)) {
+ continue;
+ }
+ if ($filter->status) {
+ $result = $filter->process($text, $langcode);
+ $all_assets[] = $result->getAssets();
+ $all_cache_tags[] = $result->getCacheTags();
+ $all_post_render_cache_callbacks[] = $result->getPostRenderCacheCallbacks();
+ $text = $result->getProcessedText();
+ }
+ }
+
+ // Filtering done, store in #markup.
+ $element['#markup'] = $text;
+
+ // Collect all cache tags.
+ if (isset($element['#cache']) && isset($element['#cache']['tags'])) {
+ // Prepend the original cache tags array.
+ array_unshift($all_cache_tags, $element['#cache']['tags']);
+ }
+ // Prepend the text format's cache tags array.
+ array_unshift($all_cache_tags, $format->getCacheTag());
+ $element['#cache']['tags'] = NestedArray::mergeDeepArray($all_cache_tags);
+
+ // Collect all attached assets.
+ if (isset($element['#attached'])) {
+ // Prepend the original attached assets array.
+ array_unshift($all_assets, $element['#attached']);
+ }
+ $element['#attached'] = NestedArray::mergeDeepArray($all_assets);
+
+ // Collect all #post_render_cache callbacks.
+ if (isset($element['#post_render_cache'])) {
+ // Prepend the original attached #post_render_cache array.
+ array_unshift($all_assets, $element['#post_render_cache']);
+ }
+ $element['#post_render_cache'] = NestedArray::mergeDeepArray($all_post_render_cache_callbacks);
+
+ return $element;
+}
+
+/**
* Implements hook_permission().
*/
function filter_permission() {
@@ -301,24 +429,6 @@ function filter_fallback_format() {
}
/**
- * Checks if the text in a certain text format is allowed to be cached.
- *
- * This function can be used to check whether the result of the filtering
- * process can be cached. A text format may allow caching depending on the
- * filters enabled.
- *
- * @param string $format_id
- * The text format ID to check.
- *
- * @return bool
- * TRUE if the given text format allows caching, FALSE otherwise.
- */
-function filter_format_allowcache($format_id) {
- $format = $format_id ? entity_load('filter_format', $format_id) : FALSE;
- return !empty($format->cache);
-}
-
-/**
* Runs all the enabled filters on a piece of text.
*
* Note: Because filters can inject JavaScript or execute PHP code, security is
@@ -327,99 +437,46 @@ function filter_format_allowcache($format_id) {
* validation stage of the Form API. You should for example never make a
* preview of content in a disallowed format.
*
- * @param $text
+ * Note: this function should only be used when filtering text for use elsewhere
+ * than on a rendered HTML page. If this is part of a HTML page, then a
+ * renderable array with a #type 'processed_text' element should be used instead
+ * of this, because that will allow cache tags to be set and bubbled up, assets
+ * to be loaded and #post_render_cache callbacks to be associated. In other
+ * words: if you are presenting the filtered text in a HTML page, the only way
+ * this will be presented correctly, is by using the 'processed_text' element.
+ *
+ * @param string $text
* The text to be filtered.
- * @param $format_id
+ * @param string|null $format_id
* (optional) The machine name of the filter format to be used to filter the
* text. Defaults to the fallback format. See filter_fallback_format().
- * @param $langcode
+ * @param string $langcode
* (optional) The language code of the text to be filtered, e.g. 'en' for
- * English. This allows filters to be language aware so language specific
+ * English. This allows filters to be language-aware so language-specific
* text replacement can be implemented. Defaults to an empty string.
- * @param $cache
- * (optional) A Boolean indicating whether to cache the filtered output in the
- * {cache_filter} table. The caller may set this to FALSE when the output is
- * already cached elsewhere to avoid duplicate cache lookups and storage.
- * Defaults to FALSE.
* @param array $filter_types_to_skip
* (optional) An array of filter types to skip, or an empty array (default)
* to skip no filter types. All of the format's filters will be applied,
* except for filters of the types that are marked to be skipped.
- * FilterInterface::TYPE_HTML_RESTRICTOR is the only type that cannot be skipped.
+ * FilterInterface::TYPE_HTML_RESTRICTOR is the only type that cannot be
+ * skipped.
*
- * @return
+ * @return string
* The filtered text.
*
+ * @see filter_process_text()
+ *
* @ingroup sanitization
*/
-function check_markup($text, $format_id = NULL, $langcode = '', $cache = FALSE, $filter_types_to_skip = array()) {
- if (!isset($format_id)) {
- $format_id = filter_fallback_format();
- }
- // If the requested text format does not exist, the text cannot be filtered.
- if (!$format = entity_load('filter_format', $format_id)) {
- watchdog('filter', 'Missing text format: %format.', array('%format' => $format_id), WATCHDOG_ALERT);
- return '';
- }
-
- // Prevent FilterInterface::TYPE_HTML_RESTRICTOR from being skipped.
- if (in_array(FilterInterface::TYPE_HTML_RESTRICTOR, $filter_types_to_skip)) {
- $filter_types_to_skip = array_diff($filter_types_to_skip, array(FilterInterface::TYPE_HTML_RESTRICTOR));
- }
-
- // When certain filters should be skipped, don't perform caching.
- if ($filter_types_to_skip) {
- $cache = FALSE;
- }
-
- // Check for a cached version of this piece of text.
- $cache = $cache && !empty($format->cache);
- $cache_id = '';
- if ($cache) {
- $cache_id = $format->format . ':' . $langcode . ':' . hash('sha256', $text);
- if ($cached = \Drupal::cache('filter')->get($cache_id)) {
- return $cached->data;
- }
- }
-
- // Convert all Windows and Mac newlines to a single newline, so filters only
- // need to deal with one possibility.
- $text = str_replace(array("\r\n", "\r"), "\n", $text);
-
- // Get a complete list of filters, ordered properly.
- $filters = $format->filters();
-
- // Give filters the chance to escape HTML-like data such as code or formulas.
- foreach ($filters as $filter) {
- // If necessary, skip filters of a certain type.
- if (in_array($filter->getType(), $filter_types_to_skip)) {
- continue;
- }
- if ($filter->status) {
- $text = $filter->prepare($text, $langcode, $cache, $cache_id);
- }
- }
-
- // Perform filtering.
- foreach ($filters as $filter) {
- // If necessary, skip filters of a certain type.
- if (in_array($filter->getType(), $filter_types_to_skip)) {
- continue;
- }
- if ($filter->status) {
- $text = $filter->process($text, $langcode, $cache, $cache_id);
- }
- }
-
- // Cache the filtered text. This cache is infinitely valid. It becomes
- // obsolete when $text changes (which leads to a new $cache_id). It is
- // automatically flushed when the text format is updated.
- // @see \Drupal\filter\Entity\FilterFormat::save()
- if ($cache) {
- \Drupal::cache('filter')->set($cache_id, $text, Cache::PERMANENT, array('filter_format' => $format->id()));
- }
-
- return $text;
+function check_markup($text, $format_id = NULL, $langcode = 'und', $filter_types_to_skip = array()) {
+ $build = array(
+ '#type' => 'processed_text',
+ '#text' => $text,
+ '#format' => $format_id,
+ '#filter_types_to_skip' => $filter_types_to_skip,
+ '#langcode' => $langcode,
+ );
+ return drupal_render($build);
}
/**
@@ -1144,10 +1201,3 @@ function filter_filter_secure_image_alter(&$image) {
/**
* @} End of "defgroup standard_filters".
*/
-
-/**
- * Implements hook_page_build().
- */
-function filter_page_build(&$page) {
- $page['#attached']['library'][] = 'filter/caption';
-}
diff --git a/core/modules/filter/filter.services.yml b/core/modules/filter/filter.services.yml
index dc93fdd..406161a 100644
--- a/core/modules/filter/filter.services.yml
+++ b/core/modules/filter/filter.services.yml
@@ -1,11 +1,4 @@
services:
- cache.filter:
- class: Drupal\Core\Cache\CacheBackendInterface
- tags:
- - { name: cache.bin }
- factory_method: get
- factory_service: cache_factory
- arguments: [filter]
plugin.manager.filter:
class: Drupal\filter\FilterPluginManager
parent: default_plugin_manager
diff --git a/core/modules/filter/src/Annotation/Filter.php b/core/modules/filter/src/Annotation/Filter.php
index a14b72f..808357c 100644
--- a/core/modules/filter/src/Annotation/Filter.php
+++ b/core/modules/filter/src/Annotation/Filter.php
@@ -65,16 +65,6 @@ class Filter extends Plugin {
public $status = FALSE;
/**
- * Specifies whether the filtered text can be cached.
- *
- * Note that setting this to FALSE makes the entire text format not cacheable,
- * which may have an impact on the site's overall performance.
- *
- * @var bool (optional)
- */
- public $cache = TRUE;
-
- /**
* The default settings for the filter.
*
* @var array (optional)
diff --git a/core/modules/filter/src/Entity/FilterFormat.php b/core/modules/filter/src/Entity/FilterFormat.php
index 6f5f807..9598f77 100644
--- a/core/modules/filter/src/Entity/FilterFormat.php
+++ b/core/modules/filter/src/Entity/FilterFormat.php
@@ -93,13 +93,6 @@ class FilterFormat extends ConfigEntityBase implements FilterFormatInterface, En
protected $roles;
/**
- * Whether processed text of this format can be cached.
- *
- * @var bool
- */
- public $cache = FALSE;
-
- /**
* Configured filters for this text format.
*
* An associative array of filters assigned to the text format, keyed by the
@@ -207,15 +200,6 @@ public function preSave(EntityStorageInterface $storage) {
// @todo Do not save disabled filters whose properties are identical to
// all default properties.
-
- // Determine whether the format can be cached.
- // @todo This is a derived/computed definition, not configuration.
- $this->cache = TRUE;
- foreach ($this->filters()->getAll() as $filter) {
- if ($filter->status && !$filter->cache) {
- $this->cache = FALSE;
- }
- }
}
/**
diff --git a/core/modules/filter/src/FilterProcessResult.php b/core/modules/filter/src/FilterProcessResult.php
new file mode 100644
index 0000000..17f0a13
--- /dev/null
+++ b/core/modules/filter/src/FilterProcessResult.php
@@ -0,0 +1,250 @@
+setAssets(array(
+ * 'library' => array(
+ * 'filter/caption',
+ * ),
+ * ));
+ *
+ * // Associate cache tags to be invalidated by.
+ * $result->setCacheTags($node->getCacheTag());
+ *
+ * return $result;
+ * }
+ * @endcode
+ */
+class FilterProcessResult {
+
+ /**
+ * The processed text.
+ *
+ * @see \Drupal\filter\Plugin\FilterInterface::process()
+ *
+ * @var string
+ */
+ protected $processedText;
+
+ /**
+ * An array of associated assets to be attached.
+ *
+ * @see drupal_process_attached()
+ *
+ * @var array
+ */
+ protected $assets;
+
+ /**
+ * The attached cache tags.
+ *
+ * @see drupal_render_collect_cache_tags()
+ *
+ * @var array
+ */
+ protected $cacheTags;
+
+ /**
+ * The associated #post_render_cache callbacks.
+ *
+ * @see _drupal_render_process_post_render_cache()
+ *
+ * @var array
+ */
+ protected $postRenderCacheCallbacks;
+
+ /**
+ * Constructs a FilterProcessResult object.
+ *
+ * @param string $processed_text
+ * The text as processed by a text filter.
+ */
+ public function __construct($processed_text) {
+ $this->processedText = $processed_text;
+
+ $this->assets = array();
+ $this->cacheTags = array();
+ $this->postRenderCacheCallbacks = array();
+ }
+
+ /**
+ * Gets the processed text.
+ *
+ * @return string
+ */
+ public function getProcessedText() {
+ return $this->processedText;
+ }
+
+ /**
+ * Gets the processed text.
+ *
+ * @return string
+ */
+ public function __toString() {
+ return $this->getProcessedText();
+ }
+
+ /**
+ * Sets the processed text.
+ *
+ * @param string $processed_text
+ * The text as processed by a text filter.
+ *
+ * @return $this
+ */
+ public function setProcessedText($processed_text) {
+ $this->processedText = $processed_text;
+ return $this;
+ }
+
+ /**
+ * Gets cache tags associated with the processed text.
+ *
+ * @return array
+ */
+ public function getCacheTags() {
+ return $this->cacheTags;
+ }
+
+ /**
+ * Adds cache tags associated with the processed text.
+ *
+ * @param array $cache_tags
+ * The cache tags to be added.
+ *
+ * @return $this
+ */
+ public function addCacheTags(array $cache_tags) {
+ $this->cacheTags = NestedArray::mergeDeep($this->cacheTags, $cache_tags);
+ return $this;
+ }
+
+ /**
+ * Sets cache tags associated with the processed text.
+ *
+ * @param array $cache_tags
+ * The cache tags to be associated.
+ *
+ * @return $this
+ */
+ public function setCacheTags(array $cache_tags) {
+ $this->cacheTags = $cache_tags;
+ return $this;
+ }
+
+ /**
+ * Gets assets associated with the processed text.
+ *
+ * @return array
+ */
+ public function getAssets() {
+ return $this->assets;
+ }
+
+ /**
+ * Adds assets associated with the processed text.
+ *
+ * @param array $assets
+ * The associated assets to be attached.
+ *
+ * @return $this
+ */
+ public function addAssets(array $assets) {
+ $this->assets = drupal_merge_attached($this->assets, $assets);
+ return $this;
+ }
+
+ /**
+ * Sets assets associated with the processed text.
+ *
+ * @param array $assets
+ * The associated assets to be attached.
+ *
+ * @return $this
+ */
+ public function setAssets(array $assets) {
+ $this->assets = $assets;
+ return $this;
+ }
+
+ /**
+ * Gets #post_render_cache callbacks associated with the processed text.
+ *
+ * @return array
+ */
+ public function getPostRenderCacheCallbacks() {
+ return $this->postRenderCacheCallbacks;
+ }
+
+ /**
+ * Adds #post_render_cache callbacks associated with the processed text.
+ *
+ * @param callable $callback
+ * The #post_render_cache callback that will replace the placeholder with
+ * its eventual markup.
+ * @param array $context
+ * An array providing context for the #post_render_cache callback.
+ *
+ * @see drupal_render_cache_generate_placeholder()
+ *
+ * @return $this
+ */
+ public function addPostRenderCacheCallback($callback, array $context) {
+ $this->postRenderCacheCallbacks[$callback][] = $context;
+ return $this;
+ }
+
+ /**
+ * Sets #post_render_cache callbacks associated with the processed text.
+ *
+ * @param array $post_render_cache_callbacks
+ * The associated #post_render_cache callbacks to be executed.
+ *
+ * @return $this
+ */
+ public function setPostRenderCacheCallbacks(array $post_render_cache_callbacks) {
+ $this->postRenderCacheCallbacks = $post_render_cache_callbacks;
+ return $this;
+ }
+
+}
diff --git a/core/modules/filter/src/Plugin/Filter/FilterAutoP.php b/core/modules/filter/src/Plugin/Filter/FilterAutoP.php
index a77b19e..0627527 100644
--- a/core/modules/filter/src/Plugin/Filter/FilterAutoP.php
+++ b/core/modules/filter/src/Plugin/Filter/FilterAutoP.php
@@ -7,6 +7,7 @@
namespace Drupal\filter\Plugin\Filter;
+use Drupal\filter\FilterProcessResult;
use Drupal\filter\Plugin\FilterBase;
/**
@@ -23,8 +24,8 @@ class FilterAutoP extends FilterBase {
/**
* {@inheritdoc}
*/
- public function process($text, $langcode, $cache, $cache_id) {
- return _filter_autop($text);
+ public function process($text, $langcode) {
+ return new FilterProcessResult(_filter_autop($text));
}
/**
diff --git a/core/modules/filter/src/Plugin/Filter/FilterCaption.php b/core/modules/filter/src/Plugin/Filter/FilterCaption.php
index 08ad4c8..bccaf02 100644
--- a/core/modules/filter/src/Plugin/Filter/FilterCaption.php
+++ b/core/modules/filter/src/Plugin/Filter/FilterCaption.php
@@ -11,6 +11,7 @@
use Drupal\Component\Utility\String;
use Drupal\Component\Utility\Unicode;
use Drupal\Component\Utility\Xss;
+use Drupal\filter\FilterProcessResult;
use Drupal\filter\Plugin\FilterBase;
/**
@@ -28,9 +29,11 @@ class FilterCaption extends FilterBase {
/**
* {@inheritdoc}
*/
- public function process($text, $langcode, $cache, $cache_id) {
+ public function process($text, $langcode) {
+ $result = new FilterProcessResult($text);
if (stristr($text, 'data-caption') !== FALSE || stristr($text, 'data-align') !== FALSE) {
+ $caption_found = FALSE;
$dom = Html::load($text);
$xpath = new \DOMXPath($dom);
foreach ($xpath->query('//*[@data-caption or @data-align]') as $node) {
@@ -71,6 +74,9 @@ public function process($text, $langcode, $cache, $cache_id) {
}
continue;
}
+ else {
+ $caption_found = TRUE;
+ }
// Given the updated node, caption and alignment: re-render it with a
// caption.
@@ -96,10 +102,18 @@ public function process($text, $langcode, $cache, $cache_id) {
$node->parentNode->replaceChild($updated_node, $node);
}
- return Html::serialize($dom);
+ $result->setProcessedText(Html::serialize($dom));
+
+ if ($caption_found) {
+ $result->addAssets(array(
+ 'library' => array(
+ 'filter/caption',
+ ),
+ ));
+ }
}
- return $text;
+ return $result;
}
/**
diff --git a/core/modules/filter/src/Plugin/Filter/FilterHtml.php b/core/modules/filter/src/Plugin/Filter/FilterHtml.php
index 109d943..543f147 100644
--- a/core/modules/filter/src/Plugin/Filter/FilterHtml.php
+++ b/core/modules/filter/src/Plugin/Filter/FilterHtml.php
@@ -7,6 +7,7 @@
namespace Drupal\filter\Plugin\Filter;
+use Drupal\filter\FilterProcessResult;
use Drupal\filter\Plugin\FilterBase;
/**
@@ -58,8 +59,8 @@ public function settingsForm(array $form, array &$form_state) {
/**
* {@inheritdoc}
*/
- public function process($text, $langcode, $cache, $cache_id) {
- return _filter_html($text, $this);
+ public function process($text, $langcode) {
+ return new FilterProcessResult(_filter_html($text, $this));
}
/**
diff --git a/core/modules/filter/src/Plugin/Filter/FilterHtmlCorrector.php b/core/modules/filter/src/Plugin/Filter/FilterHtmlCorrector.php
index bc0a036..0be711c 100644
--- a/core/modules/filter/src/Plugin/Filter/FilterHtmlCorrector.php
+++ b/core/modules/filter/src/Plugin/Filter/FilterHtmlCorrector.php
@@ -8,6 +8,7 @@
namespace Drupal\filter\Plugin\Filter;
use Drupal\Component\Utility\Html;
+use Drupal\filter\FilterProcessResult;
use Drupal\filter\Plugin\FilterBase;
/**
@@ -25,8 +26,8 @@ class FilterHtmlCorrector extends FilterBase {
/**
* {@inheritdoc}
*/
- public function process($text, $langcode, $cache, $cache_id) {
- return Html::normalize($text);
+ public function process($text, $langcode) {
+ return new FilterProcessResult(Html::normalize($text));
}
}
diff --git a/core/modules/filter/src/Plugin/Filter/FilterHtmlEscape.php b/core/modules/filter/src/Plugin/Filter/FilterHtmlEscape.php
index 0825df0..a508298 100644
--- a/core/modules/filter/src/Plugin/Filter/FilterHtmlEscape.php
+++ b/core/modules/filter/src/Plugin/Filter/FilterHtmlEscape.php
@@ -7,6 +7,7 @@
namespace Drupal\filter\Plugin\Filter;
+use Drupal\filter\FilterProcessResult;
use Drupal\filter\Plugin\FilterBase;
/**
@@ -24,8 +25,8 @@ class FilterHtmlEscape extends FilterBase {
/**
* {@inheritdoc}
*/
- public function process($text, $langcode, $cache, $cache_id) {
- return _filter_html_escape($text);
+ public function process($text, $langcode) {
+ return new FilterProcessResult(_filter_html_escape($text));
}
/**
diff --git a/core/modules/filter/src/Plugin/Filter/FilterHtmlImageSecure.php b/core/modules/filter/src/Plugin/Filter/FilterHtmlImageSecure.php
index f00b055..f03c75a 100644
--- a/core/modules/filter/src/Plugin/Filter/FilterHtmlImageSecure.php
+++ b/core/modules/filter/src/Plugin/Filter/FilterHtmlImageSecure.php
@@ -7,6 +7,7 @@
namespace Drupal\filter\Plugin\Filter;
+use Drupal\filter\FilterProcessResult;
use Drupal\filter\Plugin\FilterBase;
/**
@@ -25,8 +26,8 @@ class FilterHtmlImageSecure extends FilterBase {
/**
* {@inheritdoc}
*/
- public function process($text, $langcode, $cache, $cache_id) {
- return _filter_html_image_secure_process($text);
+ public function process($text, $langcode) {
+ return new FilterProcessResult(_filter_html_image_secure_process($text));
}
/**
diff --git a/core/modules/filter/src/Plugin/Filter/FilterNull.php b/core/modules/filter/src/Plugin/Filter/FilterNull.php
index d4fbe62..9c30edc 100644
--- a/core/modules/filter/src/Plugin/Filter/FilterNull.php
+++ b/core/modules/filter/src/Plugin/Filter/FilterNull.php
@@ -7,6 +7,7 @@
namespace Drupal\filter\Plugin\Filter;
+use Drupal\filter\FilterProcessResult;
use Drupal\filter\Plugin\FilterBase;
/**
@@ -47,8 +48,8 @@ public function __construct(array $configuration, $plugin_id, $plugin_definition
/**
* {@inheritdoc}
*/
- public function process($text, $langcode, $cache, $cache_id) {
- return '';
+ public function process($text, $langcode) {
+ return new FilterProcessResult('');
}
/**
diff --git a/core/modules/filter/src/Plugin/Filter/FilterUrl.php b/core/modules/filter/src/Plugin/Filter/FilterUrl.php
index 0918b19..469ff41 100644
--- a/core/modules/filter/src/Plugin/Filter/FilterUrl.php
+++ b/core/modules/filter/src/Plugin/Filter/FilterUrl.php
@@ -7,6 +7,7 @@
namespace Drupal\filter\Plugin\Filter;
+use Drupal\filter\FilterProcessResult;
use Drupal\filter\Plugin\FilterBase;
/**
@@ -41,8 +42,8 @@ public function settingsForm(array $form, array &$form_state) {
/**
* {@inheritdoc}
*/
- public function process($text, $langcode, $cache, $cache_id) {
- return _filter_url($text, $this);
+ public function process($text, $langcode) {
+ return new FilterProcessResult(_filter_url($text, $this));
}
/**
diff --git a/core/modules/filter/src/Plugin/FilterBase.php b/core/modules/filter/src/Plugin/FilterBase.php
index facd818..44421e1 100644
--- a/core/modules/filter/src/Plugin/FilterBase.php
+++ b/core/modules/filter/src/Plugin/FilterBase.php
@@ -45,13 +45,6 @@
public $weight = 0;
/**
- * A Boolean indicating whether the text processed by this filter may be cached.
- *
- * @var bool
- */
- public $cache = TRUE;
-
- /**
* An associative array containing the configured settings of this filter.
*
* @var array
@@ -72,7 +65,6 @@ public function __construct(array $configuration, $plugin_id, $plugin_definition
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->provider = $this->pluginDefinition['provider'];
- $this->cache = $this->pluginDefinition['cache'];
$this->setConfiguration($configuration);
}
@@ -154,7 +146,7 @@ public function settingsForm(array $form, array &$form_state) {
/**
* {@inheritdoc}
*/
- public function prepare($text, $langcode, $cache, $cache_id) {
+ public function prepare($text, $langcode) {
return $text;
}
diff --git a/core/modules/filter/src/Plugin/FilterInterface.php b/core/modules/filter/src/Plugin/FilterInterface.php
index f6f7dd2..fea8559 100644
--- a/core/modules/filter/src/Plugin/FilterInterface.php
+++ b/core/modules/filter/src/Plugin/FilterInterface.php
@@ -36,19 +36,20 @@
* should then actually change the content: transform URLs into hyperlinks,
* convert smileys into images, etc.
*
- * For performance reasons, content is only filtered once; the result is stored
- * in the cache table and retrieved from the cache the next time the same piece
- * of content is displayed. If a filter's output is dynamic, it can override
- * the cache mechanism, but obviously this should be used with caution: having
- * one filter that does not support caching in a collection of filters disables
- * caching for the entire collection, not just for one filter.
- *
- * Beware of the filter cache when developing your module: it is advised to set
- * your filter to 'cache' to FALSE while developing, but be sure to remove that
- * setting if it's not needed, when you are no longer in development mode.
- *
+ * @see filter_process_text()
* @see check_markup()
*
+ * Typically, only text processing is applied, but in more advanced use cases,
+ * filters may also:
+ * - declare asset libraries to be loaded;
+ * - declare cache tags that the resulting filtered text depends upon, so when
+ * either of those cache tags is invalidated, the render-cached HTML that the
+ * filtered text is part of should also be invalidated;
+ * - declare #post_render_cache callbacks to apply uncacheable filtering, for
+ * example because it differs per user.
+ *
+ * @see \Drupal\filter\Plugin\FilterInterface::process()
+ *
* Filters are discovered through annotations, which may contain the following
* definition properties:
* - title: (required) An administrative summary of what the filter does.
@@ -67,9 +68,6 @@
* - status: The default status for new instances of the filter. Defaults to
* FALSE.
* - weight: A default weight for new instances of the filter. Defaults to 0.
- * - cache: Whether the filtered text can be cached. Defaults to TRUE.
- * Note that setting this to FALSE disables caching for an entire text format,
- * which can have a negative impact on the site's overall performance.
* - settings: An associative array containing default settings for new
* instances of the filter.
*
@@ -151,16 +149,11 @@ public function settingsForm(array $form, array &$form_state);
* The text string to be filtered.
* @param string $langcode
* The language code of the text to be filtered.
- * @param bool $cache
- * A Boolean indicating whether the filtered text is going to be cached in
- * {cache_filter}.
- * @param string $cache_id
- * The ID of the filtered text in {cache_filter}, if $cache is TRUE.
*
* @return string
* The prepared, escaped text.
*/
- public function prepare($text, $langcode, $cache, $cache_id);
+ public function prepare($text, $langcode);
/**
* Performs the filter processing.
@@ -169,16 +162,14 @@ public function prepare($text, $langcode, $cache, $cache_id);
* The text string to be filtered.
* @param string $langcode
* The language code of the text to be filtered.
- * @param bool $cache
- * A Boolean indicating whether the filtered text is going to be cached in
- * {cache_filter}.
- * @param string $cache_id
- * The ID of the filtered text in {cache_filter}, if $cache is TRUE.
*
- * @return string
- * The filtered text.
+ * @return \Drupal\filter\FilterProcessResult
+ * The filtered text, wrapped in a FilterProcessResult object, and possibly
+ * with associated assets, cache tags and #post_render_cache callbacks.
+ *
+ * @see \Drupal\filter\FilterProcessResult
*/
- public function process($text, $langcode, $cache, $cache_id);
+ public function process($text, $langcode);
/**
* Returns HTML allowed by this filter's configuration.
diff --git a/core/modules/filter/src/Tests/FilterAPITest.php b/core/modules/filter/src/Tests/FilterAPITest.php
index 1c33d74..e0c06d5 100644
--- a/core/modules/filter/src/Tests/FilterAPITest.php
+++ b/core/modules/filter/src/Tests/FilterAPITest.php
@@ -106,12 +106,12 @@ function testCheckMarkupFilterSubset() {
$expected_filter_text_without_html_generators = "Text with evil content and a URL: http://drupal.org!";
$this->assertIdentical(
- check_markup($text, 'filtered_html', '', FALSE, array()),
+ check_markup($text, 'filtered_html', '', array()),
$expected_filtered_text,
'Expected filter result.'
);
$this->assertIdentical(
- check_markup($text, 'filtered_html', '', FALSE, array(FilterInterface::TYPE_MARKUP_LANGUAGE)),
+ check_markup($text, 'filtered_html', '', array(FilterInterface::TYPE_MARKUP_LANGUAGE)),
$expected_filter_text_without_html_generators,
'Expected filter result when skipping FilterInterface::TYPE_MARKUP_LANGUAGE filters.'
);
@@ -120,7 +120,7 @@ function testCheckMarkupFilterSubset() {
// Drupal core only ships with these two types of filters, so this is the
// most extensive test possible.
$this->assertIdentical(
- check_markup($text, 'filtered_html', '', FALSE, array(FilterInterface::TYPE_HTML_RESTRICTOR, FilterInterface::TYPE_MARKUP_LANGUAGE)),
+ check_markup($text, 'filtered_html', '', array(FilterInterface::TYPE_HTML_RESTRICTOR, FilterInterface::TYPE_MARKUP_LANGUAGE)),
$expected_filter_text_without_html_generators,
'Expected filter result when skipping FilterInterface::TYPE_MARKUP_LANGUAGE filters, even when trying to disable filters of the FilterInterface::TYPE_HTML_RESTRICTOR type.'
);
@@ -224,6 +224,73 @@ function testFilterFormatAPI() {
}
/**
+ * Tests the 'processed_text' element.
+ *
+ * check_markup() is a wrapper for the 'processed_text' element, for use in
+ * simple scenarios; the 'processed_text' element has more advanced features:
+ * it lets filters attach assets, associate cache tags and define
+ * #post_render_cache callbacks.
+ * This test focuses solely on those advanced features.
+ */
+ function testProcessedTextElement() {
+ entity_create('filter_format', array(
+ 'format' => 'element_test',
+ 'name' => 'processed_text element test format',
+ 'filters' => array(
+ 'filter_test_assets' => array(
+ 'weight' => -1,
+ 'status' => TRUE,
+ ),
+ 'filter_test_cache_tags' => array(
+ 'weight' => 0,
+ 'status' => TRUE,
+ ),
+ 'filter_test_post_render_cache' => array(
+ 'weight' => 1,
+ 'status' => TRUE,
+ ),
+ // Run the HTML corrector filter last, because it has the potential to
+ // break the render cache placeholders added by the
+ // filter_test_post_render_cache filter.
+ 'filter_htmlcorrector' => array(
+ 'weight' => 10,
+ 'status' => TRUE,
+ ),
+ ),
+ ))->save();
+
+ $build = array(
+ '#type' => 'processed_text',
+ '#text' => '
Hello, world!
',
+ '#format' => 'element_test',
+ );
+ drupal_render($build);
+
+ // Verify the assets, cache tags and #post_render_cache callbacks.
+ $expected_assets = array(
+ // The assets attached by the filter_test_assets filter.
+ 'library' => array(
+ 'filter/caption',
+ ),
+ );
+ $this->assertEqual($expected_assets, $build['#attached'], 'Expected assets present');
+ $expected_cache_tags = array(
+ // The cache tag set by the processed_text element itself.
+ 'filter_format' => array(
+ 'element_test' => 'element_test',
+ ),
+ // The cache tags set by the filter_test_cache_tags filter.
+ 'foo' => array(
+ 'bar' => 'bar',
+ 'baz' => 'baz',
+ ),
+ );
+ $this->assertEqual($expected_cache_tags, $build['#cache']['tags'], 'Expected cache tags present.');
+ $expected_markup = '
Hello, world!
This is a dynamic llama.
';
+ $this->assertEqual($expected_markup, $build['#markup'], 'Expected #post_render_cache callback has been applied.');
+ }
+
+ /**
* Tests the function of the typed data type.
*/
function testTypedDataAPI() {
diff --git a/core/modules/filter/src/Tests/FilterAdminTest.php b/core/modules/filter/src/Tests/FilterAdminTest.php
index 7aa30a8..9e6d74b 100644
--- a/core/modules/filter/src/Tests/FilterAdminTest.php
+++ b/core/modules/filter/src/Tests/FilterAdminTest.php
@@ -8,7 +8,6 @@
namespace Drupal\filter\Tests;
use Drupal\simpletest\WebTestBase;
-use Drupal\filter\Plugin\FilterInterface;
/**
* Tests the administrative functionality of the Filter module.
@@ -354,73 +353,4 @@ function testUrlFilterAdmin() {
$this->assertNoRaw(t('The text format %format has been updated.', array('%format' => 'Basic HTML')));
}
- /**
- * Tests that changing filter properties clears the filter cache.
- */
- public function testFilterAdminClearsFilterCache() {
- $restricted = 'restricted_html';
- $original_markup = '
Small headers
small headers are allowed in restricted html by default';
-
- // Check that the filter cache is empty for the test markup.
- $cid = $this->computeFilterCacheId($original_markup, $restricted, '', TRUE);
- $this->assertFalse(\Drupal::cache('filter')->get($cid));
-
- // Check that the filter cache gets populated when check_markup is called.
- $actual_markup = check_markup($original_markup, $restricted, '', TRUE);
- $this->assertTrue(\Drupal::cache('filter')->get($cid));
- $this->assertIdentical(strpos($actual_markup, '