]> git.mjollnir.org Git - moodle.git/commitdiff
filters: MDL-7336 change weblib to use the new code
authortjhunt <tjhunt>
Mon, 13 Apr 2009 06:56:32 +0000 (06:56 +0000)
committertjhunt <tjhunt>
Mon, 13 Apr 2009 06:56:32 +0000 (06:56 +0000)
* Rename filter base class from filter_base to moodle_text_filter
* Remove unnecessary explicit constructors in moodle_text_filter
subclasses
* New filter_manager class, rather than static methods in filter_base
* Move some logic out of weblib, and into filter_manager
* Count filtering ops when $CFG->perfdebug on, via
performance_measuring_filter_manager
* Kill unused filter_string function. Petr said it should have been
private to weblib

14 files changed:
blocks/moodleblock.class.php
course/info.php
filter/activitynames/filter.php
filter/algebra/filter.php
filter/censor/filter.php
filter/emailprotect/filter.php
filter/mediaplugin/filter.php
filter/multilang/filter.php
filter/tex/filter.php
filter/tidy/filter.php
lib/filterlib.php
lib/moodlelib.php
lib/simpletest/testfiltermanager.php [new file with mode: 0644]
lib/weblib.php

index e6f51ade2339d9917d19d98f8e3e6347dd02aff3..c6bb802c4348822af2d066d6384d48b9391d8537 100644 (file)
@@ -380,7 +380,7 @@ class block_base {
         }
 
         //Accesssibility: added H2 (was in, weblib.php: print_side_block)
-        $title .= '<h2>'.filter_text($this->title).'</h2>';
+        $title .= '<h2>'.format_string($this->title).'</h2>';
 
         if ($this->edit_controls !== NULL) {
             $title .= $this->edit_controls;
index 47eebd1e182e165154fb96dd0ab377f386c91903..7ced5175e266cfbc5bd16f7672c2a7fd74c131ae 100644 (file)
@@ -53,8 +53,7 @@
 
     print_box_start('generalbox info');
 
-    echo filter_text(text_to_html($course->summary),$course->id);
-
+    echo format_text($course->summary, FORMAT_MOODLE, NULL, $course->id);
 
     if ($managerroles = get_config('', 'coursemanager')) {
         $coursemanagerroles = split(',', $managerroles);
index 89347b841367e0834f677eac72415b6af443ff5e..67923a2f49f1320d0ce07570b893774f6ad88182 100644 (file)
@@ -3,15 +3,11 @@
     //activities when its name (title) is found inside every Moodle text
     //It's based in the glosssary filter by Williams Castillo
     //Modifications by stronk7.
-class activitynames_filter extends filter_base {
+class activitynames_filter extends moodle_text_filter {
     // Trivial-cache - keyed on $cachedcourseid
     static $activitylist = null;
     static $cachedcourseid;
 
-    function __construct($courseid, $format, $options){
-        parent::__construct($courseid, $format, $options);
-    }
-
     function filter($text) {
         global $CFG, $COURSE, $DB;
 
index 1ec66b13dcda657b3f7835670dff9bdff484b6c4..555e8bfc515e9585b8a8d1c32da43452059cf6ad 100644 (file)
@@ -84,10 +84,7 @@ function string_file_picture_algebra($imagefile, $tex= "", $height="", $width=""
   return $output;
 }
 
-class algebra_filter extends filter_base {
-    function __construct($courseid, $format, $options){
-        parent::__construct($courseid, $format, $options);
-    }
+class algebra_filter extends moodle_text_filter {
     function filter($text){
         global $CFG, $DB;
 
index 919e3196101ac94b98ec7967041cd0ebe34b655c..58fac89411896ee0b461de48b071c2e4df7f38fd 100644 (file)
 
 /// This is the filtering class. It accepts the courseid and 
 /// options to be filtered (In HTML form).
-class censor_filter extends filter_base {
-    function __construct($courseid, $format, $options) {
-        parent::__construct($courseid, $format, $options);
-    }
+class censor_filter extends moodle_text_filter {
     private function _canseecensor() {
         $cansee = false;
         $context = get_context_instance(CONTEXT_SYSTEM, SITEID);
index 612b639f58fafea59285d481be681fe1f4021446..9427b5e86151a32497a2ef5922978dcc24da1ff5 100644 (file)
@@ -3,10 +3,7 @@
       // hides them using the Moodle obfuscate_text function. 
       // Original code by Mike Churchward
 
-class emailprotect_filter extends filter_base {
-    function __construct($courseid, $format, $options) {
-        parent::__construct($courseid, $format, $options);
-    }
+class emailprotect_filter extends moodle_text_filter {
     function filter($text) {
     /// Do a quick check using stripos to avoid unnecessary work
         if (strpos($text, '@') === false) {
index 5086fd6ec109099041884544e0a190763e8aa9ec..f42f8f7b4cded904eaefb2a3b0ae5324cd80b654 100644 (file)
 
 require_once($CFG->libdir.'/filelib.php');
 
-class mediaplugin_filter extends filter_base {
-    private $eolas_fix_applied;
-    function __construct($courseid, $format, $options) {
-        parent::__construct($courseid, $format, $options);
-        $this->eolas_fix_applied = false;
-    }
+class mediaplugin_filter extends moodle_text_filter {
+    private $eolas_fix_applied = false;
     function filter($text) {
         global $CFG;
         // You should never modify parameters passed to a method or function, it's BAD practice. Create a copy instead.
index 2f5eb0c0c8f368ba945bd7b4fefa117c43cf1846..3aa23c1d5d47d9b8c557c4a23aa1855b8924e2d5 100644 (file)
 // Following new syntax is not compatible with old one:
 //   <span lang="XX" class="multilang">one lang</span><span lang="YY" class="multilang">another language</span>
 
-class multilang_filter extends filter_base {
-    function __construct($courseid, $format, $options) {
-        parent::__construct($courseid, $format, $options);
-    }
-
+class multilang_filter extends moodle_text_filter {
     function filter($text) {
         global $CFG;
 
index 01ee633d77edba4992e34722067f56730b0cc591..c113ec6722569f23b2cd98837bb6ab7768f97ec0 100644 (file)
@@ -101,10 +101,7 @@ function string_file_picture_tex($imagefile, $tex= "", $height="", $width="", $a
     return $output;
 }
 
-class tex_filter extends filter_base {
-    function __construct($courseid, $format, $options) {
-        parent::__construct($courseid, $format, $options);
-    }
+class tex_filter extends moodle_text_filter {
     function filter ($text) {
 
         global $CFG, $DB;
index bb6893d6692998a956337058c91fef297326fa18..53d1f2d11b80995c704d6d5fcafab59ab814cc68 100644 (file)
 // If you want to know what you can set in $tidyoptions and what their default
 // values are, see http://php.net/manual/en/function.tidy-get-config.php.
       
-class tidy_filter extends filter_base {
-    function __construct($courseid, $format, $options) {
-        parent::__construct($courseid, $format, $options);
-    }
-
+class tidy_filter extends moodle_text_filter {
     /**
     * @author Hannes Gassert <hannes at mediagonal dot ch>
     * @param        string         text to be filtered
index def5d451065faf745cbb380724c21c222cf6fdd9..e953c850a48a76a16acac87c13772b21e4aa9fed 100644 (file)
@@ -9,56 +9,253 @@ define('TEXTFILTER_INHERIT', 0);
 define('TEXTFILTER_OFF', -1);
 define('TEXTFILTER_DISABLED', -9999);
 
-abstract class filter_base {
-    public static $filters = array();
-    protected $courseid;
-    protected $format;
-    protected $options;
+/**
+ * Class to manage the filtering of strings. It is intended that this class is
+ * only used by weblib.php. Client code should probably be using the
+ * format_text and format_string functions.
+ *
+ * This class is a singleton.
+ */
+class filter_manager {
+    /** This list of active filters, by context, for filtering content.
+     * An array contextid => array of filter objects. */
+    protected $textfilters = array();
 
-    public function __construct($courseid, $format, $options) {
-        $this->courseid = $courseid;
-        $this->format   = $format;
-        $this->options  = $options;
+    /** This list of active filters, by context, for filtering strings.
+     * An array contextid => array of filter objects. */
+    protected $stringfilters = array();
+
+    /** Exploded version of $CFG->stringfilters. */
+    protected $stringfilternames = array();
+
+    /** Holds the singleton instance. */
+    protected static $singletoninstance;
+
+    protected function __construct() {
+        global $CFG;
+        if (!empty($CFG->filterall) && !empty($CFG->stringfilters)) {
+            $stringfilternames = explode(',', $CFG->stringfilters);
+        }
     }
 
-    public static function addfilter($classname, $obj) {
-        if (empty(self::$filters[$classname])) {
-            self::$filters[$classname] = $obj;
-            return true;
-        } else {
-            return false;
+    /**
+     * @return the singleton instance.
+     */
+    public static function instance() {
+        if (is_null(self::$singletoninstance)) {
+            global $CFG;
+            if (!empty($CFG->perfdebug)) {
+                self::$singletoninstance = new performance_measuring_filter_manager();
+            } else {
+                self::$singletoninstance = new self();
+            }
+        }
+        return self::$singletoninstance;
+    }
+
+    /** Load all the filters required by this context. */
+    protected function load_filters($context, $courseid) {
+        $filters = filter_get_active_in_context($context);
+        $this->textfilters[$context->id] = array();
+        $this->stringfilters[$context->id] = array();
+        foreach ($filters as $filtername => $localconfig) {
+            $filter = $this->make_filter_object($filtername, $context, $courseid, $localconfig);
+            if (is_null($filter)) {
+                continue;
+            }
+            $this->textfilters[$context->id][] = $filter;
+            if (in_array($filtername, $this->stringfilternames)) {
+                $this->stringfilters[$context->id][] = $filter;
+            }
         }
     }
 
-    public static function do_filter($text, $courseid = null) {
+    /**
+     * Factory method for creating a filter.
+     * @param string $filter The filter name, for example 'filter/tex' or 'mod/glossary'.
+     * @param $context context object.
+     * @param $courseid course if.
+     * @param $localconfig array of local configuration variables for this filter.
+     * @return moodle_text_filter The filter, or null, if this type of filter is
+     *      not recognised or could not be created.
+     */
+    protected function make_filter_object($filtername, $context, $courseid, $localconfig) {
         global $CFG;
+        $path = $CFG->dirroot .'/'. $filtername .'/filter.php';
+        if (!is_readable($path)) {
+            return null;
+        }
+        include_once($path);
 
-        foreach (self::$filters as $n=>$obj) {
-            $text = $obj->filter($text); 
+        $filterclassname = basename($filtername) . '_filter';
+        if (class_exists($filterclassname)) {
+            return new $filterclassname($courseid, $context, $localconfig);
         }
 
-        // back compatable with old filter plugins
-        if (isset($CFG->textfilters)) {
-            $textfilters = explode(',', $CFG->textfilters);
-            foreach ($textfilters as $v) {
-                $text_filter = basename($v).'_filter';
-                if (empty(self::$filters[$text_filter]) && is_readable($CFG->dirroot .'/'. $v .'/filter.php')) {
-                    include_once($CFG->dirroot .'/'. $v .'/filter.php');
-                    if (function_exists($text_filter)) {
-                        $text = $text_filter($courseid, $text);
-                    }
-                }
-            }
+        $legacyfunctionname = basename($filtername) . '_filter';
+        if (function_exists($legacyfunctionname)) {
+            return new legacy_filter($legacyfunctionname, $courseid, $context, $localconfig);
+        }
+
+        return null;
+    }
+
+    protected function apply_filter_chain($text, $filterchain) {
+        foreach ($filterchain as $filter) {
+            $text = $filter->filter($text);
+        }
+        return $text;
+    }
+
+    protected function get_text_filters($context, $courseid) {
+        if (!isset($this->textfilters[$context->id])) {
+            $this->load_filters($context, $courseid);
         }
+        return $this->textfilters[$context->id];
+    }
+
+    protected function get_string_filters($context, $courseid) {
+        if (!isset($this->stringfilters[$context->id])) {
+            $this->load_filters($context, $courseid);
+        }
+        return $this->stringfilters[$context->id];
+    }
+
+    public function filter_text($text, $context, $courseid) {
+        $text = $this->apply_filter_chain($text, $this->get_text_filters($context, $courseid));
+        /// <nolink> tags removed for XHTML compatibility
+        $text = str_replace(array('<nolink>', '</nolink>'), '', $text);
         return $text;
     }
 
+    public function filter_string($string, $context, $courseid) {
+        return $this->apply_filter_chain($string, $this->get_string_filters($context, $courseid));
+    }
+
+    public function text_filtering_hash($context, $courseid) {
+        $filters = $this->get_text_filters($context, $courseid);
+        $hashes = array();
+        foreach ($filters as $filter) {
+            $hashes[] = $filter->hash();
+        }
+        return implode('-', $hashes);
+    }
+}
+
+/**
+ * Filter manager subclass that does nothing. Having this simplifies the logic
+ * of format_text, etc.
+ */
+class null_filter_manager {
+    public function filter_text($text, $context, $courseid) {
+        return $text;
+    }
+
+    public function filter_string($string, $context, $courseid) {
+        return $text;
+    }
+
+    public function text_filtering_hash() {
+        return '';
+    }
+}
+
+/**
+ * Filter manager subclass that tacks how much work it does.
+ */
+class performance_measuring_filter_manager extends filter_manager {
+    protected $filterscreated = 0;
+    protected $textsfiltered = 0;
+    protected $stringsfiltered = 0;
+
+    protected function make_filter_object($filtername, $context, $courseid, $localconfig) {
+        $this->filterscreated++;
+        return parent::make_filter_object($filtername, $context, $courseid, $localconfig);
+    }
+
+    public function filter_text($text, $context, $courseid) {
+        $this->textsfiltered++;
+        return parent::filter_text($text, $context, $courseid);
+    }
+
+    public function filter_string($string, $context, $courseid) {
+        $this->stringsfiltered++;
+        return parent::filter_string($string, $context, $courseid);
+    }
+
+    public function get_performance_summary() {
+        return array(array(
+            'contextswithfilters' => count($this->textfilters),
+            'filterscreated' => $this->filterscreated,
+            'textsfiltered' => $this->textsfiltered,
+            'stringsfiltered' => $this->stringsfiltered,
+        ), array(
+            'contextswithfilters' => 'Contexts for which filters were loaded',
+            'filterscreated' => 'Filters created',
+            'textsfiltered' => 'Pieces of content filtered',
+            'stringsfiltered' => 'Strings filtered',
+        ));
+    }
+}
+
+/**
+ * Base class for text filters. You just need to override this class and
+ * implement the filter method.
+ */
+abstract class moodle_text_filter {
+    /** The course we are in. */
+    protected $courseid;
+    /** The context we are in. */
+    protected $context;
+    /** Any local configuration for this filter in this context. */
+    protected $localconfig;
+
+    /**
+     * Set any context-specific configuration for this filter.
+     * @param object $context The current course id.
+     * @param object $context The current context.
+     * @param array $config Any context-specific configuration for this filter.
+     */
+    public function __construct($courseid, $context, array $localconfig) {
+        $this->courseid = $courseid;
+        $this->context = $context;
+        $this->localconfig = $localconfig;
+    }
+
     public function hash() {
         return __CLASS__;
     }
 
-    // filter plugin must overwrite this function to filter
-    abstract function filter($text);
+    /**
+     * Override this funciton to actually implement the filtering.
+     * @param $text some HTML content.
+     * @return the HTML content after the filtering has been applied.
+     */
+    public abstract function filter($text);
+}
+
+/**
+ * moodle_text_filter implementation that encapsulates an old-style filter that
+ * only defines a function, not a class.
+ */
+class legacy_filter extends moodle_text_filter {
+    protected $filterfunction;
+
+    /**
+     * Set any context-specific configuration for this filter.
+     * @param string $filterfunction
+     * @param object $context The current course id.
+     * @param object $context The current context.
+     * @param array $config Any context-specific configuration for this filter.
+     */
+    public function __construct($filterfunction, $courseid, $context, array $localconfig) {
+        parent::__construct($courseid, $context, $localconfig);
+        $this->filterfunction = $filterfunction;
+    }
+
+    public function filter($text) {
+        return call_user_func($this->filterfunction, $this->courseid, $text);
+    }
 }
 
 /// Define one exclusive separator that we'll use in the temp saved tags
index bd3cb8062a9fe1616d18ff0b38f300081b5a74f4..04774bda6fdd4f9de4817f4ca7ff1371daf653e9 100644 (file)
@@ -7967,6 +7967,16 @@ function get_performance_info() {
     $info['html'] .= '<span class="included">Included '.$info['includecount'].' files</span> ';
     $info['txt']  .= 'includecount: '.$info['includecount'].' ';
 
+    $filtermanager = filter_manager::instance();
+    if (method_exists($filtermanager, 'get_performance_summary')) {
+        list($filterinfo, $nicenames) = $filtermanager->get_performance_summary();
+        $info = array_merge($filterinfo, $info);
+        foreach ($filterinfo as $key => $value) {
+            $info['html'] .= "<span class='$key'>$nicenames[$key]: $value </span> ";
+            $info['txt'] .= "$key: $value ";
+        }
+    }
+
     if (!empty($PERF->logwrites)) {
         $info['logwrites'] = $PERF->logwrites;
         $info['html'] .= '<span class="logwrites">Log DB writes '.$info['logwrites'].'</span> ';
diff --git a/lib/simpletest/testfiltermanager.php b/lib/simpletest/testfiltermanager.php
new file mode 100644 (file)
index 0000000..f032ce9
--- /dev/null
@@ -0,0 +1,129 @@
+<?php // $Id$
+
+///////////////////////////////////////////////////////////////////////////
+//                                                                       //
+// NOTICE OF COPYRIGHT                                                   //
+//                                                                       //
+// Moodle - Modular Object-Oriented Dynamic Learning Environment         //
+//          http://moodle.org                                            //
+//                                                                       //
+// Copyright (C) 1999 onwards Martin Dougiamas  http://dougiamas.com     //
+//                                                                       //
+// This program 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 2 of the License, or     //
+// (at your option) any later version.                                   //
+//                                                                       //
+// This program 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:                          //
+//                                                                       //
+//          http://www.gnu.org/copyleft/gpl.html                         //
+//                                                                       //
+///////////////////////////////////////////////////////////////////////////
+
+/**
+ * Tests for the parts of ../filterlib.php that handle creating filter objects,
+ * and using them to filter strings.
+ *
+ * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
+ * @package moodlecore
+ */
+
+if (!defined('MOODLE_INTERNAL')) {
+    die('Direct access to this script is forbidden.');    ///  It must be included from a Moodle page
+}
+
+require_once($CFG->libdir . '/filterlib.php');
+
+class testable_filter_manager extends filter_manager {
+    public function __construct() {
+        parent::__construct();
+    }
+    public function make_filter_object($filtername, $context, $courseid, $localconfig) {
+        return parent::make_filter_object($filtername, $context, $courseid, $localconfig);
+    }
+    public function apply_filter_chain($text, $filterchain) {
+        return parent::apply_filter_chain($text, $filterchain);
+    }
+}
+
+/**
+ * Test functions that affect filter_active table with contextid = $syscontextid.
+ */
+class filter_manager_test extends UnitTestCase {
+    protected $filtermanager;
+    protected $olddirroot;
+
+    public function setUp() {
+        global $CFG;
+        $this->filtermanager = new testable_filter_manager();
+        $this->olddirroot = $CFG->dirroot;
+        $CFG->dirroot = $CFG->dataroot . '/temp';
+    }
+
+    public function tearDown() {
+        global $CFG;
+        $CFG->dirroot = $this->olddirroot;
+    }
+
+    /** Basically does file_put_contents, but ensures the directory exists first. */
+    protected function write_file($path, $content) {
+        global $CFG;
+        make_upload_directory(str_replace($CFG->dataroot . '/', '', dirname($path)));
+        file_put_contents($path, $content);
+    }
+
+    public function test_make_filter_object_newstyle() {
+        global $CFG;
+        $this->write_file($CFG->dirroot . '/filter/makenewstyletest/filter.php', <<<ENDCODE
+<?php
+class makenewstyletest_filter extends moodle_text_filter {
+    public function filter(\$text) {
+        return \$text;
+    }
+}
+ENDCODE
+        );
+        $filter = $this->filtermanager->make_filter_object('filter/makenewstyletest', null, 1, array());
+        $this->assertIsA($filter, 'moodle_text_filter');
+        $this->assertNotA($filter, 'legacy_filter');
+    }
+
+    public function test_make_filter_object_legacy() {
+        global $CFG;
+        $this->write_file($CFG->dirroot . '/filter/makelegacytest/filter.php', <<<ENDCODE
+<?php
+function makelegacytest_filter(\$courseid, \$text) {
+    return \$text;
+}
+ENDCODE
+        );
+        $filter = $this->filtermanager->make_filter_object('filter/makelegacytest', null, 1, array());
+        $this->assertIsA($filter, 'legacy_filter');
+    }
+
+    public function test_make_filter_object_missing() {
+        $this->assertNull($this->filtermanager->make_filter_object('filter/nonexistant', null, 1, array()));
+    }
+
+    public function test_apply_filter_chain() {
+        $filterchain = array(new doubleup_test_filter(null, 1, array()), new killfrogs_test_filter(null, 1, array()));
+        $this->assertEqual('pawn pawn', $this->filtermanager->apply_filter_chain('frogspawn', $filterchain));
+    }
+}
+
+class doubleup_test_filter extends moodle_text_filter {
+    public function filter($text) {
+        return $text . ' ' . $text;
+    }
+}
+
+class killfrogs_test_filter extends moodle_text_filter {
+    public function filter($text) {
+        return str_replace('frogs', '', $text);
+    }
+}
+
+?>
index aa704f693735313e399403776495cf79cc3ffcf0..d94903f12a48327eb35d39871cdfa74a8d4a0165 100644 (file)
@@ -1253,27 +1253,17 @@ function format_text($text, $format=FORMAT_MOODLE, $options=NULL, $courseid=NULL
         $courseid = $COURSE->id;
     }
 
-    // if filter plugin is OOP format, add it to filter list and append hash
-    // value to $hashstr
-    if (!empty($CFG->textfilters)) {
-        require_once($CFG->libdir.'/filterlib.php');
-        $textfilters = explode(',', $CFG->textfilters);
-        foreach ($textfilters as $textfilter) {
-            if (is_readable($CFG->dirroot .'/'. $textfilter .'/filter.php')) {
-                include_once($CFG->dirroot .'/'. $textfilter .'/filter.php');
-                $text_filter = basename($textfilter).'_filter';
-                if (class_exists($text_filter)) {
-                    $obj = new $text_filter($courseid, $format, $options);
-                    filter_base::addfilter($text_filter, $obj);
-                    $hashstr .= $obj->hash();
-                }
-            }
-        }
+    if ($options->filter) {
+        $filtermanager = filter_manager::instance();
+    } else {
+        $filtermanager = new null_filter_manager();
     }
+    $context = get_context_instance(CONTEXT_SYSTEM); // TODO change, once we have $PAGE->context.
+
     if (!empty($CFG->cachetext) and empty($options->nocache)) {
-        $hashstr .= $text.'-'.(int)$courseid.'-'.current_language().'-'.(int)$format.(int)$options->trusttext.(int)$options->noclean.(int)$options->smiley.(int)$options->filter.(int)$options->para.(int)$options->newlines;
-        // for debug filtering system
-        // $hashstr .= time();
+        $hashstr .= $text.'-'.$filtermanager->text_filtering_hash($context, $courseid).'-'.(int)$courseid.'-'.current_language().'-'.
+                (int)$format.(int)$options->trusttext.(int)$options->noclean.(int)$options->smiley.
+                (int)$options->filter.(int)$options->para.(int)$options->newlines;
 
         $time = time() - $CFG->cachetext;
         $md5key = md5($hashstr);
@@ -1316,8 +1306,6 @@ function format_text($text, $format=FORMAT_MOODLE, $options=NULL, $courseid=NULL
         $text = trusttext_strip($text);
     }
 
-    $CFG->currenttextiscacheable = true;   // Default status - can be changed by any filter
-
     switch ($format) {
         case FORMAT_HTML:
             if ($options->smiley) {
@@ -1326,9 +1314,7 @@ function format_text($text, $format=FORMAT_MOODLE, $options=NULL, $courseid=NULL
             if (!$options->noclean) {
                 $text = clean_text($text, FORMAT_HTML);
             }
-            if ($options->filter) {
-                $text = filter_base::do_filter($text, $courseid);
-            }
+            $text = $filtermanager->filter_text($text, $context, $courseid);
             break;
 
         case FORMAT_PLAIN:
@@ -1354,10 +1340,7 @@ function format_text($text, $format=FORMAT_MOODLE, $options=NULL, $courseid=NULL
             if (!$options->noclean) {
                 $text = clean_text($text, FORMAT_HTML);
             }
-
-            if ($options->filter) {
-                $text = filter_base::do_filter($text, $courseid);
-            }
+            $text = $filtermanager->filter_text($text, $context, $courseid);
             break;
 
         default:  // FORMAT_MOODLE or anything else
@@ -1365,14 +1348,20 @@ function format_text($text, $format=FORMAT_MOODLE, $options=NULL, $courseid=NULL
             if (!$options->noclean) {
                 $text = clean_text($text, FORMAT_HTML);
             }
-
-            if ($options->filter) {
-                $text = filter_base::do_filter($text, $courseid);
-            }
+            $text = $filtermanager->filter_text($text, $context, $courseid);
             break;
     }
 
-    if (empty($options->nocache) and !empty($CFG->cachetext) and $CFG->currenttextiscacheable) {
+    // Warn people that we have removed this old mechanism, just in case they
+    // were stupid enough to rely on it.
+    if (isset($CFG->currenttextiscacheable)) {
+        debugging('Once upon a time, Moodle had a truly evil use of global variables ' .
+                'called $CFG->currenttextiscacheable. The good news is that this no ' .
+                'longer exists. The bad news is that you seem to be using a filter that '.
+                'relies on it. Please seek out and destroy that filter code.', DEBUG_DEVELOPER);
+    }
+
+    if (empty($options->nocache) and !empty($CFG->cachetext)) {
         if (CLI_SCRIPT) {
             // special static cron cache - no need to store it in db if its not already there
             if (count($croncache) > 150) {
@@ -1457,7 +1446,7 @@ function reset_text_filters_cache() {
  *  @param int     $courseid   Current course as filters can, potentially, use it
  *  @return string
  */
-function format_string ($string, $striplinks=true, $courseid=NULL ) {
+function format_string($string, $striplinks=true, $courseid=NULL ) {
 
     global $CFG, $COURSE;
 
@@ -1485,7 +1474,8 @@ function format_string ($string, $striplinks=true, $courseid=NULL ) {
     $string = preg_replace("/\&(?![a-zA-Z0-9#]{1,8};)/", "&amp;", $string);
 
     if (!empty($CFG->filterall)) {
-        $string = filter_string($string, $courseid);
+        $context = get_context_instance(CONTEXT_SYSTEM); // TODO change, once we have $PAGE->context.
+        $string = filter_manager::instance()->filter_string($string, $context, $courseid);
     }
 
     // If the site requires it, strip ALL tags from this string
@@ -1551,16 +1541,11 @@ function format_text_email($text, $format) {
 
 /**
  * Given some text in HTML format, this function will pass it
- * through any filters that have been defined in $CFG->textfilterx
- * The variable defines a filepath to a file containing the
- * filter function.  The file must contain a variable called
- * $textfilter_function which contains the name of the function
- * with $courseid and $text parameters
+ * through any filters that have been configured for this context.
  *
  * @param string $text The text to be passed through format filters
- * @param int $courseid ?
- * @return string
- * @todo Finish documenting this function
+ * @param int $courseid The current course.
+ * @return string the filtered string.
  */
 function filter_text($text, $courseid=NULL) {
     global $CFG, $COURSE;
@@ -1569,85 +1554,9 @@ function filter_text($text, $courseid=NULL) {
         $courseid = $COURSE->id;       // (copied from format_text)
     }
 
-    if (!empty($CFG->textfilters)) {
-        require_once($CFG->libdir.'/filterlib.php');
-        $textfilters = explode(',', $CFG->textfilters);
-        foreach ($textfilters as $textfilter) {
-            if (is_readable($CFG->dirroot .'/'. $textfilter .'/filter.php')) {
-                include_once($CFG->dirroot .'/'. $textfilter .'/filter.php');
-                $functionname = basename($textfilter).'_filter';
-                if (function_exists($functionname)) {
-                    $text = $functionname($courseid, $text);
-                }
-            }
-        }
-    }
-
-    /// <nolink> tags removed for XHTML compatibility
-    $text = str_replace('<nolink>', '', $text);
-    $text = str_replace('</nolink>', '', $text);
-
-    return $text;
-}
-
-
-/**
- * Given a string (short text) in HTML format, this function will pass it
- * through any filters that have been defined in $CFG->stringfilters
- * The variable defines a filepath to a file containing the
- * filter function.  The file must contain a variable called
- * $textfilter_function which contains the name of the function
- * with $courseid and $text parameters
- *
- * @param string $string The text to be passed through format filters
- * @param int $courseid The id of a course
- * @return string
- */
-function filter_string($string, $courseid=NULL) {
-    global $CFG, $COURSE;
-
-    if (empty($CFG->textfilters)) {             // All filters are disabled anyway so quit
-        return $string;
-    }
-
-    if (empty($courseid)) {
-        $courseid = $COURSE->id;
-    }
-
-    require_once($CFG->libdir.'/filterlib.php');
-
-    if (isset($CFG->stringfilters)) {               // We have a predefined list to use, great!
-        if (empty($CFG->stringfilters)) {                    // but it's blank, so finish now
-            return $string;
-        }
-        $stringfilters = explode(',', $CFG->stringfilters);  // ..use the list we have
-
-    } else {                                        // Otherwise try to derive a list from textfilters
-        if (strpos($CFG->textfilters, 'filter/multilang') !== false) {  // Multilang is here
-            $stringfilters = array('filter/multilang');       // Let's use just that
-            $CFG->stringfilters = 'filter/multilang';         // Save it for next time through
-        } else {
-            $CFG->stringfilters = '';                         // Save the result and return
-            return $string;
-        }
-    }
-
+    $context = get_context_instance(CONTEXT_SYSTEM); // TODO change, once we have $PAGE->context.
 
-    foreach ($stringfilters as $stringfilter) {
-        if (is_readable($CFG->dirroot .'/'. $stringfilter .'/filter.php')) {
-            include_once($CFG->dirroot .'/'. $stringfilter .'/filter.php');
-            $functionname = basename($stringfilter).'_filter';
-            if (function_exists($functionname)) {
-                $string = $functionname($courseid, $string);
-            }
-        }
-    }
-
-    /// <nolink> tags removed for XHTML compatibility
-    $string = str_replace('<nolink>', '', $string);
-    $string = str_replace('</nolink>', '', $string);
-
-    return $string;
+    return filter_manager::instance()->filter_text($text, $context, $courseid);
 }
 
 /**
@@ -1698,6 +1607,7 @@ function trusttext_mark($text) {
         return $text;
     }
 }
+
 function trusttext_after_edit(&$text, $context) {
     if (has_capability('moodle/site:trustcontent', $context)) {
         $text = trusttext_strip($text);