From c84a2dbea26fb49b90ff28460be0ef03a5784ec5 Mon Sep 17 00:00:00 2001 From: tjhunt Date: Mon, 29 Jun 2009 05:00:45 +0000 Subject: [PATCH] MDL-19077 - change how $OUTPUT is initialised. Please read the comment at the top of bootstrap_renderer in setuplib.php --- lib/accesslib.php | 4 + lib/moodlelib.php | 19 +-- lib/outputlib.php | 109 +++++++++++--- lib/pagelib.php | 7 +- lib/setup.php | 37 +++-- lib/setuplib.php | 240 +++++++++++++++++++++---------- lib/simpletest/testoutputlib.php | 8 +- lib/weblib.php | 20 ++- theme/custom_corners/config.php | 11 +- 9 files changed, 306 insertions(+), 149 deletions(-) diff --git a/lib/accesslib.php b/lib/accesslib.php index 761e5adbef..afaf568e28 100755 --- a/lib/accesslib.php +++ b/lib/accesslib.php @@ -480,6 +480,10 @@ function has_capability($capability, $context, $userid=NULL, $doanything=true) { } if (empty($userid)) { // we must accept null, 0, '0', '' etc. in $userid + if (empty($USER->id)) { + // Session not set up yet. + return false; + } $userid = $USER->id; } diff --git a/lib/moodlelib.php b/lib/moodlelib.php index 8e38f1fb6e..6bc0484d9d 100644 --- a/lib/moodlelib.php +++ b/lib/moodlelib.php @@ -249,18 +249,6 @@ define('PARAM_PERMISSION', 0x80000); */ define('PAGE_COURSE_VIEW', 'course-view'); -/// Debug levels /// -/** no warnings at all */ -define ('DEBUG_NONE', 0); -/** E_ERROR | E_PARSE */ -define ('DEBUG_MINIMAL', 5); -/** E_ERROR | E_PARSE | E_WARNING | E_NOTICE */ -define ('DEBUG_NORMAL', 15); -/** E_ALL without E_STRICT for now, do show recoverable fatal errors */ -define ('DEBUG_ALL', 6143); -/** DEBUG_ALL with extra Moodle debug messages - (DEBUG_ALL | 32768) */ -define ('DEBUG_DEVELOPER', 38911); - /** Get remote addr constant */ define('GETREMOTEADDR_SKIP_HTTP_CLIENT_IP', '1'); /** Get remote addr constant */ @@ -5588,14 +5576,13 @@ function print_string($identifier, $module='', $a=NULL) { * * Notes for develpers * =================== - * * Performance of this class is important. If you decide to change this class, * please use the lib/simpletest/getstringperformancetester.php script to make * sure your changes do not cause a performance problem. * - * In some cases (for example _print_early_error) get_string gets called very - * early on during Moodle's self-initialisation. Think very carefully before - * relying on the normal Moodle libraries here. + * In some cases (for example bootstrap_renderer::early_error) get_string gets + * called very early on during Moodle's self-initialisation. Think very carefully + * before relying on the normal Moodle libraries here. * * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * @package moodlecore diff --git a/lib/outputlib.php b/lib/outputlib.php index 7d4d8b9241..b7bcb4d33c 100644 --- a/lib/outputlib.php +++ b/lib/outputlib.php @@ -28,17 +28,23 @@ */ -/** - * Set up a preliminary $OUTPUT. This will be changed later once the correct theme - * for this page is known. Must be called after $PAGE is setup. - */ -function setup_bootstrat_output() { - global $OUTPUT, $PAGE; +function initialise_theme_and_output() { + global $CFG, $OUTPUT, $PAGE, $THEME; + if (!($OUTPUT instanceof bootstrap_renderer)) { + return; // Already done. + } + if (!isset($CFG->theme) || empty($PAGE)) { + // Too soon to do anything. + return; + } + theme_setup(); if (CLI_SCRIPT) { - $OUTPUT = new cli_core_renderer(new xhtml_container_stack(), $PAGE); + $rendererfactory = new cli_renderer_factory($THEME, $PAGE); } else { - $OUTPUT = new moodle_core_renderer(new xhtml_container_stack(), $PAGE); + $classname = $THEME->rendererfactory; + $rendererfactory = new $classname($THEME, $PAGE); } + $OUTPUT = $rendererfactory->get_renderer('core'); } @@ -181,7 +187,7 @@ class standard_renderer_factory extends renderer_factory_base { /* Implement the subclass method. */ public function create_renderer($module) { if ($module == 'core') { - return new moodle_core_renderer($this->opencontainers, $this->page); + return new moodle_core_renderer($this->opencontainers, $this->page, $this); } else { $class = $this->standard_renderer_class_for_module($module); return new $class($this->opencontainers, $this->get_renderer('core'), $this->page); @@ -208,7 +214,27 @@ class custom_corners_renderer_factory extends standard_renderer_factory { */ public function __construct($theme, $page) { parent::__construct($theme, $page); - $this->renderers = array('core' => new custom_corners_core_renderer($this->opencontainers, $this->page)); + $this->renderers = array('core' => new custom_corners_core_renderer($this->opencontainers, $this->page, $this)); + } +} + + +/** + * This is a slight variation on the standard_renderer_factory used by CLI scripts. + * + * @copyright 2009 Tim Hunt + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @since Moodle 2.0 + */ +class cli_renderer_factory extends standard_renderer_factory { + /** + * Constructor. + * @param object $theme the theme we are rendering for. + * @param moodle_page $page the page we are doing output for. + */ + public function __construct($theme, $page) { + parent::__construct($theme, $page); + $this->renderers = array('core' => new cli_core_renderer($this->opencontainers, $this->page, $this)); } } @@ -262,7 +288,7 @@ class theme_overridden_renderer_factory extends standard_renderer_factory { $classname = $prefix . $module . '_renderer'; if (class_exists($classname)) { if ($module == 'core') { - return new $classname($this->opencontainers, $this->page); + return new $classname($this->opencontainers, $this->page, $this); } else { return new $classname($this->opencontainers, $this->get_renderer('core'), $this->page); } @@ -342,7 +368,7 @@ class template_renderer_factory extends renderer_factory_base { // Create a template_renderer that copies the API of the standard renderer. $copiedclass = $this->standard_renderer_class_for_module($module); - return new template_renderer($copiedclass, $searchpaths, $this->opencontainers, $this->page); + return new template_renderer($copiedclass, $searchpaths, $this->opencontainers, $this->page, $this); } } @@ -432,6 +458,7 @@ class template_renderer extends moodle_renderer_base { protected $copiedclass; /** @var array of places to search for templates. */ protected $searchpaths; + protected $rendererfactory; /** * Magic word used when breaking apart container templates to implement @@ -445,11 +472,22 @@ class template_renderer extends moodle_renderer_base { * @param $searchpaths a list of folders to search for templates in. * @param $opencontainers the xhtml_container_stack to use. * @param moodle_page $page the page we are doing output for. + * @param renderer_factory $rendererfactory the renderer factory that created us. */ - public function __construct($copiedclass, $searchpaths, $opencontainers, $page) { + public function __construct($copiedclass, $searchpaths, $opencontainers, $page, $rendererfactory) { parent::__construct($opencontainers, $page); $this->copiedclass = new ReflectionClass($copiedclass); $this->searchpaths = $searchpaths; + $this->rendererfactory = $rendererfactory; + } + + /** + * Get a renderer for another part of Moodle. + * @param $module the name of part of moodle. E.g. 'core', 'quiz', 'qtype_multichoice'. + * @return object an object implementing the requested renderer interface. + */ + public function get_other_renderer($module) { + $this->rendererfactory->get_renderer($module); } /* PHP magic method implementation. */ @@ -704,6 +742,27 @@ class moodle_core_renderer extends moodle_renderer_base { const END_HTML_TOKEN = '%%ENDHTML%%'; const MAIN_CONTENT_TOKEN = '[MAIN CONTENT GOES HERE]'; protected $contenttype; + protected $rendererfactory; + + /** + * Constructor + * @param $opencontainers the xhtml_container_stack to use. + * @param moodle_page $page the page we are doing output for. + * @param renderer_factory $rendererfactory the renderer factory that created us. + */ + public function __construct($opencontainers, $page, $rendererfactory) { + parent::__construct($opencontainers, $page); + $this->rendererfactory = $rendererfactory; + } + + /** + * Get a renderer for another part of Moodle. + * @param $module the name of part of moodle. E.g. 'core', 'quiz', 'qtype_multichoice'. + * @return object an object implementing the requested renderer interface. + */ + public function get_other_renderer($module) { + $this->rendererfactory->get_renderer($module); + } public function doctype() { global $CFG; @@ -1114,7 +1173,8 @@ class moodle_core_renderer extends moodle_renderer_base { if ($this->opencontainers->count() == 0) { // Header not yet printed @header('HTTP/1.0 404 Not Found'); - print_header(get_string('error')); + $this->page->set_title(get_string('error')); + $output .= $this->header(); } else { $output .= $this->opencontainers->pop_all_but_last(); } @@ -1142,7 +1202,7 @@ class moodle_core_renderer extends moodle_renderer_base { $output .= $this->continue_button($link); } - print_footer(); + $output .= $this->footer(); // Padding to encourage IE to display our error page, rather than its own. $output .= str_repeat(' ', 512); @@ -1471,6 +1531,8 @@ class cli_core_renderer extends moodle_core_renderer { * @since Moodle 2.0 */ class custom_corners_core_renderer extends moodle_core_renderer { + protected $wraplevel = 1; + protected function custom_corners_divs($classes = '', $idbase = '') { if (strpos($classes, 'clearfix') !== false) { $clearfix = ' clearfix'; @@ -1495,11 +1557,8 @@ class custom_corners_core_renderer extends moodle_core_renderer { $idbb = $idbase . '-bb'; } - // Calculate current level - $level = $this->opencontainers->count(); - // Create start tags. - $start = $this->output_start_tag('div', array('id' => $idbb, 'class' => "wrap wraplevel$level $classes")) . "\n"; + $start = $this->output_start_tag('div', array('id' => $id, 'class' => "wrap wraplevel{$this->wraplevel} $classes")) . "\n"; $start .= $this->output_tag('div', array('id' => $idbt, 'class' => 'bt'), '
 
') . "\n"; $start .= $this->output_start_tag('div', array('id' => $idi1, 'class' => 'i1')); $start .= $this->output_start_tag('div', array('id' => $idi2, 'class' => 'i2')); @@ -1518,12 +1577,24 @@ class custom_corners_core_renderer extends moodle_core_renderer { public function box_start($classes = 'generalbox', $id = '') { list($start, $end) = $this->custom_corners_divs('ccbox box ' . moodle_renderer_base::prepare_classes($classes), $id); $this->opencontainers->push('box', $end); + $this->wraplevel += 1; return $start; } + public function box_end() { + $this->wraplevel -= 1; + return parent::box_end(); + } + public function container_start($classes = '', $id = '') { list($start, $end) = $this->custom_corners_divs(moodle_renderer_base::prepare_classes($classes), $id); $this->opencontainers->push('container', $end); + $this->wraplevel += 1; return $start; } + + public function container_end() { + $this->wraplevel -= 1; + return parent::container_end(); + } } diff --git a/lib/pagelib.php b/lib/pagelib.php index 548a990b83..14686bb693 100644 --- a/lib/pagelib.php +++ b/lib/pagelib.php @@ -335,14 +335,17 @@ class moodle_page { * @return blocks_manager the blocks manager object for this page. */ public function get_blocks() { - global $CFG; + global $CFG, $THEME; if (is_null($this->_blocks)) { + initialise_theme_and_output(); if (!empty($CFG->blockmanagerclass)) { $classname = $CFG->blockmanagerclass; } else { $classname = 'block_manager'; } $this->_blocks = new $classname($this); + $this->_blocks->add_regions($THEME->blockregions); + $this->_blocks->set_default_region($THEME->defaultblockregion); } return $this->_blocks; } @@ -481,7 +484,6 @@ class moodle_page { } moodle_setlocale(); - theme_setup(); } /** @@ -743,7 +745,6 @@ class moodle_page { $this->_course = new stdClass; $this->_course->id = 1; moodle_setlocale(); - theme_setup(); return; } diff --git a/lib/setup.php b/lib/setup.php index 57bd20c431..4131b03f7e 100644 --- a/lib/setup.php +++ b/lib/setup.php @@ -97,8 +97,10 @@ global $COURSE; * $OUTPUT is an instance of moodle_core_renderer or one of its subclasses. Use * it to generate HTML for output. * - * $OUTPUT is initialised when the theme is setup. That normally happens during - * the call to require_login, or $PAGE->set_course. + * $OUTPUT is initialised the first time it is used. See {@link bootstrap_renderer} + * for the magic that does that. After $OUTPUT has been initialised, any attempt + * to change something that affects the current theme ($PAGE->course, logged in use, + * httpsrequried ... will result in an exception.) * * @global object $OUTPUT * @name $OUTPUT @@ -205,6 +207,11 @@ global $SCRIPT; /// Time to start counting init_performance_info(); +/// Put $OUTPUT in place, so errors can be displayed. + $OUTPUT = new bootstrap_renderer(); + +/// set handler for uncought exceptions - equivalent to print_error() call + set_exception_handler('default_exception_handler'); /// If there are any errors in the standard libraries we want to know! error_reporting(E_ALL); @@ -249,9 +256,6 @@ global $SCRIPT; //point zend include path to moodles lib/zend so that includes and requires will search there for files before anywhere else ini_set('include_path', $CFG->libdir.'/zend' . PATH_SEPARATOR . ini_get('include_path')); -/// set handler for uncought exceptions - equivalent to print_error() call - set_exception_handler('default_exception_handler'); - /// make sure PHP is not severly misconfigured setup_validate_php_configuration(); @@ -346,7 +350,6 @@ global $SCRIPT; unset($originaldatabasedebug); error_reporting($CFG->debug); - /// find out if PHP cofigured to display warnings if (ini_get_bool('display_errors')) { define('WARN_DISPLAY_ERRORS_ENABLED', true); @@ -369,19 +372,6 @@ global $SCRIPT; @ini_set('log_errors', '1'); } -/// Create the $PAGE global. - if (!empty($CFG->moodlepageclass)) { - $classname = $CFG->moodlepageclass; - } else { - $classname = 'moodle_page'; - } - $PAGE = new $classname(); - -/// Create an initial $OUTPUT. This will be changes later once we know the theme. - setup_bootstrat_output(); - - unset($classname); - /// detect unsupported upgrade jump as soon as possible - do not change anything, do not use system functions if (!empty($CFG->version) and $CFG->version < 2007101509) { print_error('upgraderequires19', 'error'); @@ -475,6 +465,15 @@ global $SCRIPT; $CFG->javascript = $CFG->libdir .'/javascript.php'; $CFG->moddata = 'moddata'; +/// Create the $PAGE global. + if (!empty($CFG->moodlepageclass)) { + $classname = $CFG->moodlepageclass; + } else { + $classname = 'moodle_page'; + } + $PAGE = new $classname(); + unset($classname); + /// A hack to get around magic_quotes_gpc being turned on /// It is strongly recommended to disable "magic_quotes_gpc"! if (ini_get_bool('magic_quotes_gpc')) { diff --git a/lib/setuplib.php b/lib/setuplib.php index 0b9bc8befd..bfaa223134 100644 --- a/lib/setuplib.php +++ b/lib/setuplib.php @@ -26,6 +26,18 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ +/// Debug levels /// +/** no warnings at all */ +define ('DEBUG_NONE', 0); +/** E_ERROR | E_PARSE */ +define ('DEBUG_MINIMAL', 5); +/** E_ERROR | E_PARSE | E_WARNING | E_NOTICE */ +define ('DEBUG_NORMAL', 15); +/** E_ALL without E_STRICT for now, do show recoverable fatal errors */ +define ('DEBUG_ALL', 6143); +/** DEBUG_ALL with extra Moodle debug messages - (DEBUG_ALL | 32768) */ +define ('DEBUG_DEVELOPER', 38911); + /** * Simple class * @@ -38,6 +50,9 @@ class object {}; /** * Base Moodle Exception class * + * Although this class is defined here, you cannot throw a moodle_exception until + * after moodlelib.php has been included (which will happen very soon). + * * @package moodlecore * @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com} * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later @@ -124,11 +139,11 @@ class invalid_state_exception extends moodle_exception { * Does not return. Terminates execution. */ function default_exception_handler($ex, $isupgrade = false, $plugin = null) { - global $CFG, $DB, $SCRIPT; + global $CFG, $DB, $OUTPUT, $SCRIPT; // detect active db transactions, rollback and log as error - if ($DB->is_transaction_started()) { - error_log('Database transaction aborted by exception in '.$CFG->dirroot.$SCRIPT); + if ($DB && $DB->is_transaction_started()) { + error_log('Database transaction aborted by exception in ' . $CFG->dirroot . $SCRIPT); try { // note: transaction blocks should never change current $_SESSION $DB->rollback_sql(); @@ -140,9 +155,8 @@ function default_exception_handler($ex, $isupgrade = false, $plugin = null) { $place = array('file'=>$ex->getFile(), 'line'=>$ex->getLine(), 'exception'=>get_class($ex)); array_unshift($backtrace, $place); - $earlyerror = empty($OUTPUT); foreach ($backtrace as $stackframe) { - if (isset($stackframe['function']) && $stackframe['function'] == 'print_header') { + if (isset($stackframe['function']) && $stackframe['function'] == 'default_exception_handler') { $earlyerror = true; break; } @@ -172,13 +186,7 @@ function default_exception_handler($ex, $isupgrade = false, $plugin = null) { $CFG->debug = DEBUG_DEVELOPER; } - if ($earlyerror) { - // Error found before setup.php finished - _print_early_error($message, $backtrace, $debuginfo); - } else { - echo $OUTPUT->fatal_error($message, $moreinfourl, $link, debug_backtrace()); - } - + echo $OUTPUT->fatal_error($message, $moreinfourl, $link, debug_backtrace()); exit(1); // General error code } @@ -202,13 +210,7 @@ function print_error($errorcode, $module = 'error', $link = '', $a = null) { } list($message, $moreinfourl, $link) = prepare_error_message($errorcode, $module, $link, $a); - - if (empty($OUTPUT)) { - // Error found before setup.php finished - _print_early_error($message); - } else { - echo $OUTPUT->fatal_error($message, $moreinfourl, $link, debug_backtrace()); - } + echo $OUTPUT->fatal_error($message, $moreinfourl, $link, debug_backtrace()); exit(1); // General error code } @@ -229,15 +231,26 @@ function prepare_error_message($errorcode, $module, $link, $a) { $DB->set_debug(0); } + // Be careful, no guarantee moodlelib.php is loaded. if (empty($module) || $module == 'moodle' || $module == 'core') { $module = 'error'; } - $message = get_string($errorcode, $module, $a); - if ($module === 'error' and strpos($message, '[[') === 0) { - // Search in moodle file if error specified - needed for backwards compatibility - $message = get_string($errorcode, 'moodle', $a); + if (function_exists('get_string')) { + $message = get_string($errorcode, $module, $a); + if ($module === 'error' and strpos($message, '[[') === 0) { + // Search in moodle file if error specified - needed for backwards compatibility + $message = get_string($errorcode, 'moodle', $a); + } + } else { + $message = $module . '/' . $errorcode; + } + + // Be careful, no guarantee weblib.php is loaded. + if (function_exists('clean_text')) { + $message = clean_text($message); + } else { + $message = htmlspecialchars($message); } - $message = clean_text($message); if (!empty($CFG->errordocroot)) { $errordocroot = $CFG->errordocroot; @@ -265,56 +278,6 @@ function prepare_error_message($errorcode, $module, $link, $a) { return array($message, $moreinfourl, $link); } -/** - * Internal function used by print_error. Do not use this directly!! - * - * Displays a fatal error before the theme is fully initialised. - * For example errors that occur during lib/setup.php. - * - * @param string $message - * @param string $link - * @param array $backtrace - * @param string $debuginfo - */ -function _print_early_error($message, $backtrace = null, $debuginfo = null) { - // In the name of protocol correctness, monitoring and performance - // profiling, set the appropriate error headers for machine comsumption - if (isset($_SERVER['SERVER_PROTOCOL'])) { - // Avoid it with cron.php. Note that we assume it's HTTP/1.x - @header($_SERVER['SERVER_PROTOCOL'] . ' 503 Service Unavailable'); - } - - // better disable any caching - @header('Content-Type: text/html; charset=utf-8'); - @header('Cache-Control: no-store, no-cache, must-revalidate'); - @header('Cache-Control: post-check=0, pre-check=0', false); - @header('Pragma: no-cache'); - @header('Expires: Mon, 20 Aug 1969 09:23:00 GMT'); - @header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); - - echo ' - - - -' . get_string('error') . ' - -
-' . $message . ' -
'; - if (debugging('', DEBUG_DEVELOPER)) { - if (!empty($debuginfo)) { - echo '
' . $debuginfo . '
'; - } - if (!empty($backtrace)) { - echo '
Stack trace: ' . format_backtrace($backtrace, false) . '
'; - } - } - - echo ''; -} - /** * Formats a backtrace ready for output. * @@ -526,7 +489,7 @@ function init_performance_info() { $PERF->logwrites = 0; if (function_exists('microtime')) { $PERF->starttime = microtime(); - } + } if (function_exists('memory_get_usage')) { $PERF->startmemory = memory_get_usage(); } @@ -739,5 +702,130 @@ function init_eaccelerator() { } +/** + * This class solves the problem of how to initialise $OUTPUT. + * + * The problem is caused be two factors + *
    + *
  1. On the one hand, we cannot be sure when output will start. In particular, + * an error, which needs to be displayed, could br thrown at any time.
  2. + *
  3. On the other hand, we cannot be sure when we will have all the information + * necessary to correctly initialise $OUTPUT. $OUTPUT depends on the theme, which + * (potentially) depends on the current course, course categories, and logged in user. + * It also depends on whether the current page requires HTTPS.
  4. + *
+ * + * So, it is hard to find a single natural place during Moodle script execution, + * which we can guarantee is the right time to initialise $OUTPUT. Instead we + * adopt the following strategy + *
    + *
  1. We will initialise $OUTPUT the first time it is used.
  2. + *
  3. If, after $OUTPUT has been initialised, the script tries to change something + * that $OUPTUT depends on, we throw an exception making it clear that the script + * did something wrong. + *
+ * + * The only problem with that is, how do we initialise $OUTPUT on first use if, + * it is going to be used like $OUTPUT->somthing(...)? Well that is where this + * class comes in. Initially, we set up $OUTPUT = new bootstrap_renderer(). Then, + * when any method is called on that object, we initialise $OUTPUT, and pass the call on. + * + * Note that this class is used before lib/outputlib.php has been loaded, so we + * must be careful referring to classes/funtions from there, they may not be + * defined yet, and we must avoid fatal errors. + * + * @copyright 2009 Tim Hunt + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @since Moodle 2.0 + */ +class bootstrap_renderer { + /** + * Handles re-entrancy. Without this, errors or debugging output that occur + * during the initialisation of $OUTPUT, cause infinite recursion. + * @var boolean + */ + protected $initialising = false; + + public function __call($method, $arguments) { + global $OUTPUT; + + // If lib/outputlib.php has been loaded, call it. + if (!$this->initialising && function_exists('initialise_theme_and_output')) { + $this->initialising = true; + initialise_theme_and_output(debug_backtrace()); + if (!($OUTPUT instanceof bootstrap_renderer)) { + return call_user_func_array(array($OUTPUT, $method), $arguments); + } + } -?> + $this->initialising = true; + // Too soon to initialise $OUTPUT, provide a couple of key methods. + $earlymethods = array( + 'fatal_error' => 'early_error', + 'notification' => 'early_notification', + ); + if (array_key_exists($method, $earlymethods)) { + return call_user_func_array(array('bootstrap_renderer', $earlymethods[$method]), $arguments); + } + + throw new coding_exception('Attempt to start output before enough information is known to initialise the theme.'); + } + + /** + * This function should only be called by this class, or by + * @return unknown_type + */ + public static function early_error($message, $moreinfourl, $link, $backtrace, + $debuginfo = null, $showerrordebugwarning = false) { + // In the name of protocol correctness, monitoring and performance + // profiling, set the appropriate error headers for machine comsumption + if (isset($_SERVER['SERVER_PROTOCOL'])) { + // Avoid it with cron.php. Note that we assume it's HTTP/1.x + @header($_SERVER['SERVER_PROTOCOL'] . ' 503 Service Unavailable'); + } + + // better disable any caching + @header('Content-Type: text/html; charset=utf-8'); + @header('Cache-Control: no-store, no-cache, must-revalidate'); + @header('Cache-Control: post-check=0, pre-check=0', false); + @header('Pragma: no-cache'); + @header('Expires: Mon, 20 Aug 1969 09:23:00 GMT'); + @header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); + + if (function_exists('get_string') && function_exists('get_html_lang')) { + $htmllang = get_html_lang(); + $strerror = get_string('error'); + } else { + $htmllang = ''; + $strerror = 'Error'; + } + + + $output = ' + + + +' . $strerror . ' + +
+' . $message . ' +
'; + if (!empty($CFG->debug) && $CFG->debug >= DEBUG_DEVELOPER) { + if (!empty($debuginfo)) { + $output .= '
' . $debuginfo . '
'; + } + if (!empty($backtrace)) { + $output .= '
Stack trace: ' . format_backtrace($backtrace, false) . '
'; + } + } + + $output .= ''; + return $output; + } + + public static function early_notification($message, $classes = 'notifyproblem') { + return '
' . $message . '
'; + } +} diff --git a/lib/simpletest/testoutputlib.php b/lib/simpletest/testoutputlib.php index 002f6059f7..d638f9a0fa 100644 --- a/lib/simpletest/testoutputlib.php +++ b/lib/simpletest/testoutputlib.php @@ -50,7 +50,7 @@ class testable_renderer_factory extends renderer_factory_base { public function create_renderer($module) { $this->createcalls[] = $module; - return new moodle_core_renderer(new xhtml_container_stack(), null); + return new moodle_core_renderer(new xhtml_container_stack(), null, null); } public function standard_renderer_class_for_module($module) { @@ -64,7 +64,7 @@ class testable_renderer_factory extends renderer_factory_base { */ class moodle_test_renderer extends moodle_core_renderer { public function __construct($containerstack, $page) { - parent::__construct($containerstack, $page); + parent::__construct($containerstack, $page, null); } public function greeting($name = 'world') { @@ -722,7 +722,7 @@ class template_renderer_test extends UnitTestCase { $page = new stdClass; $page->course = new stdClass; $this->renderer = new template_renderer('moodle_test_renderer', - array($this->templatefolder), new xhtml_container_stack(), $page); + array($this->templatefolder), new xhtml_container_stack(), $page, null); $this->savedtemplates = array(); } @@ -787,7 +787,7 @@ class moodle_core_renderer_test extends UnitTestCase { public function setUp() { parent::setUp(); $this->containerstack = new xhtml_container_stack(); - $this->renderer = new moodle_core_renderer($this->containerstack, null); + $this->renderer = new moodle_core_renderer($this->containerstack, null, null); } public function test_select_menu_simple() { diff --git a/lib/weblib.php b/lib/weblib.php index 081dd60ee1..4aa9b3c5f2 100644 --- a/lib/weblib.php +++ b/lib/weblib.php @@ -3198,18 +3198,16 @@ function theme_setup($theme = '', $params=NULL) { $CFG->stylesheets[] = $CFG->themewww.'/'.$theme.'/rtl.css'.$paramstring; } - /// Set up the block regions. - if (!empty($THEME->blockregions)) { - $PAGE->blocks->add_regions($THEME->blockregions); - } else { - // Support legacy themes by supplying a sensible default. - $PAGE->blocks->add_regions(array('side-pre', 'side-post')); + // Support legacy themes, by setting sensible defaults for some of the new + // properties that were introduced in Moodle 2.0. + if (empty($THEME->rendererfactory)) { + $THEME->rendererfactory = 'standard_renderer_factory'; } - if (!empty($THEME->defaultblockregion)) { - $PAGE->blocks->set_default_region($THEME->defaultblockregion); - } else { - // Support legacy themes by supplying a sensible default. - $PAGE->blocks->set_default_region('side-post'); + if (empty($THEME->blockregions)) { + $THEME->blockregions = array('side-pre', 'side-post'); + } + if (empty($THEME->defaultblockregion)) { + $THEME->defaultblockregion = 'side-post'; } } diff --git a/theme/custom_corners/config.php b/theme/custom_corners/config.php index 37be46b0f7..28b893d4d9 100644 --- a/theme/custom_corners/config.php +++ b/theme/custom_corners/config.php @@ -184,4 +184,13 @@ $THEME->custompix = false; /// "pix/mod" directory containing all the icons /// for all the activity modules. //////////////////////////////////////////////////////////////////////////////// -?> + + +$THEME->rendererfactory = 'custom_corners_renderer_factory'; +/// This is an advanced features that lets you control the HTML that Moodle +/// generates. You need to specify a class that implements the renderer_factory +/// interface. As well as the default 'standard_renderer_factory', there is +/// also the experimental 'template_renderer_factory', or you could implement +/// your own. For more information, please see +/// http://docs.moodle.org/en/Developement:How_Moodle_outputs_HTML +//////////////////////////////////////////////////////////////////////////////// -- 2.39.5