MDL-19077 - change how $OUTPUT is initialised.

Please read the comment at the top of bootstrap_renderer in setuplib.php
This commit is contained in:
tjhunt 2009-06-29 05:00:45 +00:00
parent a4103e65fa
commit c84a2dbea2
9 changed files with 308 additions and 151 deletions

View File

@ -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;
}

View File

@ -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

View File

@ -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;
if (CLI_SCRIPT) {
$OUTPUT = new cli_core_renderer(new xhtml_container_stack(), $PAGE);
} else {
$OUTPUT = new moodle_core_renderer(new xhtml_container_stack(), $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) {
$rendererfactory = new cli_renderer_factory($THEME, $PAGE);
} else {
$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'), '<div>&nbsp;</div>') . "\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();
}
}

View File

@ -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;
}

View File

@ -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')) {

View File

@ -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 '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" ' . get_html_lang() . '>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>' . get_string('error') . '</title>
</head><body>
<div style="margin-top: 6em; margin-left:auto; margin-right:auto; color:#990000; text-align:center; font-size:large; border-width:1px;
border-color:black; background-color:#ffffee; border-style:solid; border-radius: 20px; border-collapse: collapse;
width: 80%; -moz-border-radius: 20px; padding: 15px">
' . $message . '
</div>';
if (debugging('', DEBUG_DEVELOPER)) {
if (!empty($debuginfo)) {
echo '<div class="notifytiny">' . $debuginfo . '</div>';
}
if (!empty($backtrace)) {
echo '<div class="notifytiny">Stack trace: ' . format_backtrace($backtrace, false) . '</div>';
}
}
echo '</body></html>';
}
/**
* 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
* <ol>
* <li>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.</li>
* <li>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.</li>
* </ol>
*
* 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
* <ol>
* <li>We will initialise $OUTPUT the first time it is used.</li>
* <li>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.
* </ol>
*
* 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 = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" ' . $htmllang . '>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>' . $strerror . '</title>
</head><body>
<div style="margin-top: 6em; margin-left:auto; margin-right:auto; color:#990000; text-align:center; font-size:large; border-width:1px;
border-color:black; background-color:#ffffee; border-style:solid; border-radius: 20px; border-collapse: collapse;
width: 80%; -moz-border-radius: 20px; padding: 15px">
' . $message . '
</div>';
if (!empty($CFG->debug) && $CFG->debug >= DEBUG_DEVELOPER) {
if (!empty($debuginfo)) {
$output .= '<div class="notifytiny">' . $debuginfo . '</div>';
}
if (!empty($backtrace)) {
$output .= '<div class="notifytiny">Stack trace: ' . format_backtrace($backtrace, false) . '</div>';
}
}
$output .= '</body></html>';
return $output;
}
public static function early_notification($message, $classes = 'notifyproblem') {
return '<div class="' . $classes . '">' . $message . '</div>';
}
}

View File

@ -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() {

View File

@ -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';
}
}

View File

@ -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
////////////////////////////////////////////////////////////////////////////////