MDL-50491 filters: option to disable some filters in filter_text.

This lets you programmatically prevent certain filters running on
certain content.

Also, I created some unit tests for the basic format_text functionality
since there did not seem to be any yet.
This commit is contained in:
Tim Hunt
2015-06-17 13:48:55 +01:00
parent a94b2cb873
commit 7d94679ff1
5 changed files with 203 additions and 24 deletions
+2
View File
@@ -3,6 +3,8 @@ information provided here is intended especially for developers.
=== 3.0 ===
* New argument $skipfilters to filter_manager::filter_text to allow applying
the filters with a given one omitted.
* New admin setting class admin_setting_filter_types which can be used if you
want to make the disablefilters value in your code configurable.
+21 -12
View File
@@ -54,13 +54,13 @@ define('TEXTFILTER_EXCL_SEPARATOR', '-%-');
class filter_manager {
/**
* @var moodle_text_filter[][] This list of active filters, by context, for filtering content.
* An array contextid => array of filter objects.
* An array contextid => ordered array of filter name => filter objects.
*/
protected $textfilters = array();
/**
* @var moodle_text_filter[][] This list of active filters, by context, for filtering strings.
* An array contextid => array of filter objects.
* An array contextid => ordered array of filter name => filter objects.
*/
protected $stringfilters = array();
@@ -127,9 +127,9 @@ class filter_manager {
if (is_null($filter)) {
continue;
}
$this->textfilters[$context->id][] = $filter;
$this->textfilters[$context->id][$filtername] = $filter;
if (in_array($filtername, $this->stringfilternames)) {
$this->stringfilters[$context->id][] = $filter;
$this->stringfilters[$context->id][$filtername] = $filter;
}
}
}
@@ -162,12 +162,17 @@ class filter_manager {
/**
* Apply a list of filters to some content.
* @param string $text
* @param moodle_text_filter[] $filterchain
* @param moodle_text_filter[] $filterchain array filter name => filter object.
* @param array $options options passed to the filters.
* @param array $skipfilters of filter names. Any filters that should not be applied to this text.
* @return string $text
*/
protected function apply_filter_chain($text, $filterchain, array $options = array()) {
foreach ($filterchain as $filter) {
protected function apply_filter_chain($text, $filterchain, array $options = array(),
array $skipfilters = null) {
foreach ($filterchain as $filtername => $filter) {
if ($skipfilters !== null && in_array($filtername, $skipfilters)) {
continue;
}
$text = $filter->filter($text, $options);
}
return $text;
@@ -205,10 +210,12 @@ class filter_manager {
* @param string $text The text to filter
* @param context $context the context.
* @param array $options options passed to the filters
* @param array $skipfilters of filter names. Any filters that should not be applied to this text.
* @return string resulting text
*/
public function filter_text($text, $context, array $options = array()) {
$text = $this->apply_filter_chain($text, $this->get_text_filters($context), $options);
public function filter_text($text, $context, array $options = array(),
array $skipfilters = null) {
$text = $this->apply_filter_chain($text, $this->get_text_filters($context), $options, $skipfilters);
// <nolink> tags removed for XHTML compatibility
$text = str_replace(array('<nolink>', '</nolink>'), '', $text);
return $text;
@@ -275,7 +282,8 @@ class filter_manager {
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class null_filter_manager {
public function filter_text($text, $context, $options) {
public function filter_text($text, $context, array $options = array(),
array $skipfilters = null) {
return $text;
}
@@ -320,9 +328,10 @@ class performance_measuring_filter_manager extends filter_manager {
return parent::make_filter_object($filtername, $context, $localconfig);
}
public function filter_text($text, $context, array $options = array()) {
public function filter_text($text, $context, array $options = array(),
array $skipfilters = null) {
$this->textsfiltered++;
return parent::filter_text($text, $context, $options);
return parent::filter_text($text, $context, $options, $skipfilters);
}
public function filter_string($string, $context) {
+82
View File
@@ -0,0 +1,82 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Unit tests for the {@link filter_manager} class.
*
* @package core
* @category test
* @copyright 2015 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
*/
defined('MOODLE_INTERNAL') || die();
/**
* Unit tests for the {@link filter_manager} class.
*
* @copyright 2015 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
*/
class core_filter_manager_testcase extends advanced_testcase {
/**
* Helper method to apply filters to some text and return the result.
* @param string $text the text to filter.
* @param array $skipfilters any filters not to apply, even if they are configured.
* @return string the filtered text.
*/
protected function filter_text($text, $skipfilters) {
global $PAGE;
$filtermanager = filter_manager::instance();
$filtermanager->setup_page_for_filters($PAGE, $PAGE->context);
$filteroptions = array(
'originalformat' => FORMAT_HTML,
'noclean' => false,
);
return $filtermanager->filter_text($text, $PAGE->context, $filteroptions, $skipfilters);
}
public function test_filter_normal() {
$this->resetAfterTest();
filter_set_global_state('emoticon', TEXTFILTER_ON);
$this->assertRegExp('~^<p><img class="emoticon" alt="smile" ([^>]+)></p>$~',
$this->filter_text('<p>:-)</p>', array()));
}
public function test_one_filter_disabled() {
$this->resetAfterTest();
filter_set_global_state('emoticon', TEXTFILTER_ON);
$this->assertEquals('<p>:-)</p>',
$this->filter_text('<p>:-)</p>', array('emoticon')));
}
public function test_disabling_other_filter_does_not_break_it() {
$this->resetAfterTest();
filter_set_global_state('emoticon', TEXTFILTER_ON);
$this->assertRegExp('~^<p><img class="emoticon" alt="smile" ([^>]+)></p>$~',
$this->filter_text('<p>:-)</p>', array('urltolink')));
}
public function test_one_filter_of_two_disabled() {
$this->resetAfterTest();
filter_set_global_state('emoticon', TEXTFILTER_ON);
filter_set_global_state('urltolink', TEXTFILTER_ON);
$this->assertRegExp('~^<p><img class="emoticon" alt="smile" ([^>]+)> http://google.com/</p>$~',
$this->filter_text('<p>:-) http://google.com/</p>', array('glossary', 'urltolink')));
}
}
+90
View File
@@ -0,0 +1,90 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Unit tests for format_text defined in weblib.php.
*
* @package core
* @category test
* @copyright 2015 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
*/
defined('MOODLE_INTERNAL') || die();
/**
* Unit tests for format_text defined in weblib.php.
*
* @copyright 2015 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
*/
class core_weblib_format_text_testcase extends advanced_testcase {
public function test_format_text_format_html() {
$this->resetAfterTest();
filter_set_global_state('emoticon', TEXTFILTER_ON);
$this->assertRegExp('~^<p><img class="emoticon" alt="smile" ([^>]+)></p>$~',
format_text('<p>:-)</p>', FORMAT_HTML));
}
public function test_format_text_format_html_no_filters() {
$this->resetAfterTest();
filter_set_global_state('emoticon', TEXTFILTER_ON);
$this->assertEquals('<p>:-)</p>',
format_text('<p>:-)</p>', FORMAT_HTML, array('filter' => false)));
}
public function test_format_text_format_plain() {
$this->resetAfterTest();
filter_set_global_state('emoticon', TEXTFILTER_ON);
$this->assertEquals(':-)',
format_text(':-)', FORMAT_PLAIN, array('filter' => false)));
}
public function test_format_text_format_markdown() {
$this->resetAfterTest();
filter_set_global_state('emoticon', TEXTFILTER_ON);
$this->assertRegExp('~^<p><em><img class="emoticon" alt="smile" ([^>]+)></em></p>\n$~',
format_text('*:-)*', FORMAT_MARKDOWN));
}
public function test_format_text_format_markdown_nofilter() {
$this->resetAfterTest();
filter_set_global_state('emoticon', TEXTFILTER_ON);
$this->assertEquals("<p><em>:-)</em></p>\n",
format_text('*:-)*', FORMAT_MARKDOWN, array('filter' => false)));
}
public function test_format_text_format_moodle() {
$this->resetAfterTest();
filter_set_global_state('emoticon', TEXTFILTER_ON);
$this->assertRegExp('~^<div class="text_to_html"><p><img class="emoticon" alt="smile" ([^>]+)></p></div>$~',
format_text('<p>:-)</p>', FORMAT_MOODLE));
}
public function test_format_text_format_moodle_no_filters() {
$this->resetAfterTest();
filter_set_global_state('emoticon', TEXTFILTER_ON);
$this->assertEquals('<div class="text_to_html"><p>:-)</p></div>',
format_text('<p>:-)</p>', FORMAT_MOODLE, array('filter' => false)));
}
public function test_format_text_overflowdiv() {
$this->assertEquals('<div class="no-overflow"><p>:-)</p></div>',
format_text('<p>:-)</p>', FORMAT_HTML, array('overflowdiv' => true)));
}
}
+8 -12
View File
@@ -1204,8 +1204,13 @@ function format_text($text, $format = FORMAT_MOODLE, $options = null, $courseidd
if ($options['filter']) {
$filtermanager = filter_manager::instance();
$filtermanager->setup_page_for_filters($PAGE, $context); // Setup global stuff filters may have.
$filteroptions = array(
'originalformat' => $format,
'noclean' => $options['noclean'],
);
} else {
$filtermanager = new null_filter_manager();
$filteroptions = array();
}
switch ($format) {
@@ -1213,10 +1218,7 @@ function format_text($text, $format = FORMAT_MOODLE, $options = null, $courseidd
if (!$options['noclean']) {
$text = clean_text($text, FORMAT_HTML, $options);
}
$text = $filtermanager->filter_text($text, $context, array(
'originalformat' => FORMAT_HTML,
'noclean' => $options['noclean']
));
$text = $filtermanager->filter_text($text, $context, $filteroptions);
break;
case FORMAT_PLAIN:
@@ -1239,10 +1241,7 @@ function format_text($text, $format = FORMAT_MOODLE, $options = null, $courseidd
if (!$options['noclean']) {
$text = clean_text($text, FORMAT_HTML, $options);
}
$text = $filtermanager->filter_text($text, $context, array(
'originalformat' => FORMAT_MARKDOWN,
'noclean' => $options['noclean']
));
$text = $filtermanager->filter_text($text, $context, $filteroptions);
break;
default: // FORMAT_MOODLE or anything else.
@@ -1250,10 +1249,7 @@ function format_text($text, $format = FORMAT_MOODLE, $options = null, $courseidd
if (!$options['noclean']) {
$text = clean_text($text, FORMAT_HTML, $options);
}
$text = $filtermanager->filter_text($text, $context, array(
'originalformat' => $format,
'noclean' => $options['noclean']
));
$text = $filtermanager->filter_text($text, $context, $filteroptions);
break;
}
if ($options['filter']) {