diff --git a/lib/adminlib.php b/lib/adminlib.php index 86997359dcb..610558c4f1d 100644 --- a/lib/adminlib.php +++ b/lib/adminlib.php @@ -5391,7 +5391,7 @@ class admin_setting_manageportfolio extends admin_setting { function admin_externalpage_setup($section, $extrabutton = '', array $extraurlparams = null, $actualurl = '') { global $CFG, $PAGE, $USER, $SITE, $OUTPUT; - $PAGE->set_context(get_context_instance(CONTEXT_SYSTEM)); + $PAGE->set_context(null); // hack - set context to something, by default to system context $site = get_site(); require_login(); diff --git a/lib/outputrenderers.php b/lib/outputrenderers.php index 1dcf3e6136a..c1ef9d2c8e3 100644 --- a/lib/outputrenderers.php +++ b/lib/outputrenderers.php @@ -1964,6 +1964,7 @@ EOD; // can not be used from command line or when outputting custom XML @header($_SERVER['SERVER_PROTOCOL'] . ' 404 Not Found'); } + $this->page->set_context(null); // ugly hack - make sure page context is set to something, we do not want bogus warnings here $this->page->set_url('/'); // no url //$this->page->set_pagelayout('base'); //TODO: MDL-20676 blocks on error pages are weird, unfortunately it somehow detect the pagelayout from URL :-( $this->page->set_title(get_string('error')); @@ -2581,6 +2582,9 @@ class core_renderer_ajax extends core_renderer { */ public function fatal_error($message, $moreinfourl, $link, $backtrace, $debuginfo = null) { global $FULLME, $USER; + + $this->page->set_context(null); // ugly hack - make sure page context is set to something, we do not want bogus warnings here + $e = new stdClass(); $e->error = $message; $e->stacktrace = NULL; diff --git a/lib/pagelib.php b/lib/pagelib.php index ec823b21eae..8a16473cf1f 100644 --- a/lib/pagelib.php +++ b/lib/pagelib.php @@ -328,12 +328,13 @@ class moodle_page { */ protected function magic_get_context() { if (is_null($this->_context)) { - if (CLI_SCRIPT) { - // cli scripts work in system context, do not annoy devs with fatal errors here - $this->_context = get_context_instance(CONTEXT_SYSTEM); + if (CLI_SCRIPT or NO_MOODLE_COOKIES) { + // cli scripts work in system context, do not annoy devs with debug info + // very few scripts do not use cookies, we can safely use system as default context there } else { - throw new coding_exception('$PAGE->context accessed before it was known.'); + debugging('Coding problem: this page does not set $PAGE->context properly.'); } + $this->_context = get_context_instance(CONTEXT_SYSTEM); } return $this->_context; } @@ -641,7 +642,7 @@ class moodle_page { if ($this->_legacypageobject) { return $this->_legacypageobject->user_allowed_editing(); } - return has_any_capability($this->all_editing_caps(), $this->context); + return has_any_capability($this->all_editing_caps(), $this->_context); } /** @@ -652,7 +653,7 @@ class moodle_page { $summary = ''; $summary .= 'General type: ' . $this->pagelayout . '. '; if (!during_initial_install()) { - $summary .= 'Context ' . print_context_name($this->context) . ' (context id ' . $this->context->id . '). '; + $summary .= 'Context ' . print_context_name($this->_context) . ' (context id ' . $this->_context->id . '). '; } $summary .= 'Page type ' . $this->pagetype . '. '; if ($this->subpage) { @@ -723,6 +724,28 @@ class moodle_page { * @param object $context a context object, normally obtained with get_context_instance. */ public function set_context($context) { + if ($context === null) { + // extremely ugly hack which sets context to some value in order to prevent warnings, + // use only for core error handling!!!! + if (!$this->_context) { + $this->_context = get_context_instance(CONTEXT_SYSTEM); + } + return; + } + + // ideally we should set context only once + if (isset($this->_context)) { + if ($context->id == $this->_context->id) { + // fine - no change needed + } else if ($this->_context->contextlevel == CONTEXT_SYSTEM or $this->_context->contextlevel == CONTEXT_COURSE) { + // hmm - not ideal, but it might produce too many warnings due to the design of require_login + } else { + // we do not want devs to do weird switching of context levels on the fly, + // because we might have used the context already such as in text filter in page title + debugging('Coding problem: unsupported modification of PAGE->context from '.$this->_context->contextlevel.' to '.$context->contextlevel); + } + } + $this->_context = $context; } @@ -732,6 +755,8 @@ class moodle_page { * @param objcet $cm a full cm object obtained from get_coursemodule_from_id or get_coursemodule_from_instance. */ public function set_cm($cm, $course = null, $module = null) { + global $DB; + if (!isset($cm->name) || !isset($cm->modname) || !isset($cm->id)) { throw new coding_exception('The $cm you set on $PAGE must have been obtained with get_coursemodule_from_id or get_coursemodule_from_instance. That is, the ->name and -> modname fields must be present and correct.'); } @@ -742,8 +767,7 @@ class moodle_page { } if (!$this->_course || $this->_course->id != $cm->course) { if (!$course) { - global $DB; - $course = $DB->get_record('course', array('id' => $cm->course)); + $course = $DB->get_record('course', array('id' => $cm->course), '*', MUST_EXIST); } if ($course->id != $cm->course) { throw new coding_exception('The course you passed to $PAGE->set_cm does not seem to correspond to the $cm.'); @@ -1115,6 +1139,11 @@ class moodle_page { return; } + if (!during_initial_install()) { + // detect PAGE->context mess + $this->magic_get_context(); + } + if (!$this->_course && !during_initial_install()) { $this->set_course($SITE); } @@ -1290,7 +1319,7 @@ class moodle_page { if (!during_initial_install()) { $this->add_body_class('course-' . $this->_course->id); - $this->add_body_class('context-' . $this->context->id); + $this->add_body_class('context-' . $this->_context->id); } if (!empty($this->_cm)) { @@ -1669,10 +1698,10 @@ function page_map_class($type, $classname = NULL) { * @deprecated since Moodle 2.0 * Parent class from which all Moodle page classes derive * - * @package moodlecore - * @subpackage pages - * @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com} - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @package core + * @subpackage lib + * @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class page_base extends moodle_page { /** @@ -1707,10 +1736,10 @@ class page_base extends moodle_page { * Although this does nothing, this class declaration should be left for now * since there may be legacy class doing class page_... extends page_course * - * @package moodlecore - * @subpackage pages - * @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com} - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @package core + * @subpackage lib + * @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class page_course extends page_base { } @@ -1719,10 +1748,10 @@ class page_course extends page_base { * @deprecated since Moodle 2.0 * Class that models the common parts of all activity modules * - * @package moodlecore - * @subpackage pages - * @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com} - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @package core + * @subpackage lib + * @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class page_generic_activity extends page_base { // Although this function is deprecated, it should be left here because diff --git a/lib/setuplib.php b/lib/setuplib.php index b67cc77128e..106040e34c5 100644 --- a/lib/setuplib.php +++ b/lib/setuplib.php @@ -963,18 +963,24 @@ class bootstrap_renderer { $recursing = is_early_init($backtrace); } + $earlymethods = array( + 'fatal_error' => 'early_error', + 'notification' => 'early_notification', + ); + // If lib/outputlib.php has been loaded, call it. if (!empty($PAGE) && !$recursing) { + if (array_key_exists($method, $earlymethods)) { + //prevent PAGE->context warnings - exceptions might appear before we set any context + $PAGE->set_context(null); + } $PAGE->initialise_theme_and_output(); 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); }