require_login();
if (has_capability('moodle/user:viewuseractivitiesreport', $personalcontext) and !has_capability('moodle/course:view', $coursecontext)) {
// do not require parents to be enrolled in courses ;-)
- course_setup($course);
+ $PAGE->set_course($course);
} else {
require_login($course);
}
* @return int number of changed settings
*/
function admin_write_settings($formdata) {
- global $CFG, $SITE, $COURSE, $DB;
+ global $CFG, $SITE, $PAGE, $DB;
$olddbsessions = !empty($CFG->dbsessions);
$formdata = (array)$formdata;
// now update $SITE - it might have been changed
$SITE = $DB->get_record('course', array('id'=>$SITE->id));
- course_setup($SITE);
+ $PAGE->set_course($SITE);
// now reload all settings - some of them might depend on the changed
admin_get_root(true);
/// USER AUTHENTICATION AND LOGIN ////////////////////////////////////////
-/**
- * Setup all global $CFG course variables, set locale and also themes
- * This function can be used on pages that do not require login instead of require_login()
- *
- * @param mixed $courseorid id of the course or course object
- */
-function course_setup($courseorid=0) {
- global $COURSE, $SITE, $DB;
-
-/// Redefine global $COURSE if needed
- if (empty($courseorid)) {
- // no change in global $COURSE - for backwards compatibiltiy
- // if require_rogin() used after require_login($courseid);
- } else if (is_object($courseorid)) {
- $COURSE = clone($courseorid);
- } else {
- if ($courseorid == SITEID) {
- $COURSE = clone($SITE);
- } else {
- if (!$COURSE = $DB->get_record('course', array('id'=>$courseorid))) {
- print_error('invalidcourseid');
- }
- }
- }
-
-/// set locale and themes
- moodle_setlocale();
- theme_setup();
-
-}
-
/**
* Returns full login url.
*
* in order to keep redirects working properly. MDL-14495
*/
function require_login($courseorid=0, $autologinguest=true, $cm=null, $setwantsurltome=true) {
- global $CFG, $SESSION, $USER, $COURSE, $FULLME;
+ global $CFG, $SESSION, $USER, $COURSE, $FULLME, $PAGE, $DB;
/// setup global $COURSE, themes, language and locale
- course_setup($courseorid);
+ if (!empty($courseorid)) {
+ if (is_object($courseorid)) {
+ $course = $courseorid;
+ } else if ($courseorid == SITEID) {
+ $course = clone($SITE);
+ } else {
+ $course = $DB->get_record('course', array('id' => $courseorid));
+ if (!$course) {
+ throw new moodle_exception('invalidcourseid');
+ }
+ }
+ $PAGE->set_course($course);
+ }
/// If the user is not even logged in yet then make sure they are
if (!isloggedin()) {
* @package pages
*/
+/**
+ * $PAGE is a central store of information about the current page we are
+ * generating in response to the user's request. It does not do very much itself
+ * except keep track of information, however, it serves as the access point to
+ * some more significant components like $PAGE->theme, $PAGE->requires,
+ * $PAGE->blocks, etc.
+ */
+class moodle_page {
+ /**#@+ Tracks the where we are in the generation of the page. */
+ const STATE_BEFORE_HEADER = 0;
+ const STATE_PRINTING_HEADER = 1;
+ const STATE_IN_BODY = 2;
+ const STATE_PRINTING_FOOTER = 3;
+ const STATE_DONE = 4;
+ /**#@-*/
+
+ protected $_state = self::STATE_BEFORE_HEADER;
+
+ protected $_course = null;
+
+ /**
+ * @return integer one of the STATE_... constants. You should not normally need
+ * to use this in your code. It is indended for internal use by this class
+ * and its friends like print_header, to check that everything is working as
+ * expected. Also accessible as $PAGE->state.
+ */
+ public function get_state() {
+ return $this->_state;
+ }
+
+ /**
+ * @return boolean has the header already been printed? Also accessible as
+ * $PAGE->headerprinted.
+ */
+ public function get_headerprinted() {
+ return $this->_state >= self::STATE_IN_BODY;
+ }
+
+ /**
+ * @return object the current course that we are inside - a row from the
+ * course table. (Also available as $COURSE global.) If we are not inside
+ * an actual course, this will be the site course. You can also access this
+ * as $PAGE->course.
+ */
+ public function get_course() {
+ global $SITE;
+ if (is_null($this->_course)) {
+ return $SITE;
+ }
+ return $this->_course;
+ }
+
+ /**
+ * Set the state. The state must be one of that STATE_... constants, and
+ * the state is only allowed to advance one step at a time.
+ * @param integer $state the new state.
+ */
+ public function set_state($state) {
+ if ($state != $this->_state + 1 || $state > self::STATE_DONE) {
+ throw new coding_exception('Invalid state passed to moodle_page::set_state. We are in state ' .
+ $this->_state . ' and state ' . $state . ' was requestsed.');
+ }
+
+ if ($state == self::STATE_PRINTING_HEADER && !$this->_course) {
+ global $SITE;
+ $this->set_course($SITE);
+ }
+
+ $this->_state = $state;
+ }
+
+ /**
+ * Set the current course. This sets both $PAGE->course and $COURSE. It also
+ * sets the right theme and locale.
+ *
+ * Normally you don't need to call this function yourself, require_login will
+ * call it for you if you pass a $course to it. You can use this function
+ * on pages that do need to call require_login().
+ *
+ * @param object the course to set as the global course.
+ */
+ public function set_course($course) {
+ global $COURSE, $SITE;
+
+ if (empty($course->id)) {
+ throw new coding_exception('$course passed to moodle_page::set_course does not look like a proper course object.');
+ }
+
+ if ($this->_state > self::STATE_BEFORE_HEADER) {
+ throw new coding_exception('Cannot call moodle_page::set_course after output has been started.');
+ }
+
+ $this->_course = clone($course);
+ $COURSE = $this->_course;
+
+ moodle_setlocale();
+ theme_setup();
+ }
+
+ /**
+ * PHP overloading magic to make the $PAGE->course syntax work.
+ */
+ public function __get($field) {
+ $getmethod = 'get_' . $field;
+ if (method_exists($this, $getmethod)) {
+ return $this->$getmethod();
+ } else {
+ throw new coding_exception('Unknown field ' . $field . ' of $PAGE.');
+ }
+ }
+}
+
/**
* @deprecated since Moodle 2.0
* Load any page_base subclasses from the pagelib.php library in a particular folder.
* its numeric ID. Returns a fully constructed page_base subclass you can work with.
*/
function page_create_object($type, $id = NULL) {
- global $CFG;
+ global $CFG, $PAGE;
$data = new stdClass;
$data->pagetype = $type;
}
$object->init_quick($data);
+ $object->set_course($PAGE->course);
return $object;
}
* @package pages
* @todo This parent class is very messy still. Please for the moment ignore it and move on to the derived class page_course to see the comments there.
*/
-class page_base {
+class page_base extends moodle_page {
/**
* The string identifier for the type of page being described.
* @var string $type
* @return void
*/
function cron_setup_user($user=null, $course=null) {
- global $CFG, $SITE;
+ global $CFG, $SITE, $PAGE;
static $cronuser = null;
static $cronsession = null;
}
if ($course) {
- course_setup($course);
+ $PAGE->set_course($course);
} else {
- course_setup($SITE);
+ $PAGE->set_course($SITE);
}
// TODO: it should be possible to improve perf by caching some limited number of users here ;-)
*/
global $USER;
+/**
+ * A central store of information about the current page we are
+ * generating in response to the user's request.
+ *
+ * @global moodle_page $PAGE
+ */
+global $PAGE;
+
/**
* The current course. An alias for $PAGE->course.
* @global object $COURSE
get_system_context();
}
+/// Create the $PAGE global.
+ $PAGE = new moodle_page();
+
/// Set error reporting back to normal
if ($originaldatabasedebug == -1) {
$CFG->debug = DEBUG_MINIMAL;
}
}
- // set default locale and themes - might be changed again later from require_login()
- course_setup();
+ // We used to call moodle_setlocale() and theme_setup() here, even though they
+ // would be called again from require_login or $PAGE->set_course. As an experiment
+ // I am going to try removing those calls. With luck it will help us find and
+ // fix a few bugs where scripts do not initialise thigns properly, wihtout causing
+ // too much grief.
if (!empty($CFG->guestloginbutton)) {
if ($CFG->theme == 'standard' or $CFG->theme == 'standardwhite') { // Temporary measure to help with XHTML validation
* The upgrade is finished at the end of script or after timeout.
*/
function upgrade_started($preinstall=false) {
- global $CFG, $DB;
+ global $CFG, $DB, $PAGE;
static $started = false;
upgrade_set_timeout(120);
} else {
- if (!CLI_SCRIPT and !defined('HEADER_PRINTED')) {
+ if (!CLI_SCRIPT and !$PAGE->headerprinted) {
$strupgrade = get_string('upgradingversion', 'admin');
print_header($strupgrade.' - Moodle '.$CFG->target_release, $strupgrade,
* to reload the parent window before this one closes.
*/
function close_window($delay = 0, $reloadopener = false) {
- global $THEME;
+ global $THEME, $PAGE;
- if (!defined('HEADER_PRINTED')) {
+ if (!$PAGE->headerprinted) {
print_header(get_string('closewindow'));
} else {
print_container_end_all(false, $THEME->open_header_containers);
$meta='', $cache=true, $button=' ', $menu='',
$usexml=false, $bodytags='', $return=false) {
- global $USER, $CFG, $THEME, $SESSION, $ME, $SITE, $COURSE;
+ global $USER, $CFG, $THEME, $SESSION, $ME, $SITE, $COURSE, $PAGE;
if (gettype($navigation) == 'string' && strlen($navigation) != 0 && $navigation != 'home') {
debugging("print_header() was sent a string as 3rd ($navigation) parameter. "
. "This is deprecated in favour of an array built by build_navigation(). Please upgrade your code.", DEBUG_DEVELOPER);
}
+ $PAGE->set_state(moodle_page::STATE_PRINTING_HEADER);
+
$heading = format_string($heading); // Fix for MDL-8582
if (CLI_SCRIPT) {
}
}
-/// This makes sure that the header is never repeated twice on a page
- if (defined('HEADER_PRINTED')) {
- debugging('print_header() was called more than once - this should not happen. Please check the code for this page closely. Note: print_error() and redirect() are now safe to call after print_header().');
- return;
- }
- define('HEADER_PRINTED', 'true');
-
-
/// Add the required stylesheets
$stylesheetshtml = '';
foreach ($CFG->stylesheets as $stylesheet) {
$output .= require_js('', 2);
$output .= print_js_call('moodle_initialise_body', array(), true);
+ $PAGE->set_state(moodle_page::STATE_IN_BODY);
+
if ($return) {
return $output;
} else {
* @return mixed string or void
*/
function print_footer($course=NULL, $usercourse=NULL, $return=false) {
- global $USER, $CFG, $THEME, $COURSE, $SITE;
+ global $USER, $CFG, $THEME, $COURSE, $SITE, $PAGE;
if (defined('ADMIN_EXT_HEADER_PRINTED') and !defined('ADMIN_EXT_FOOTER_PRINTED')) {
admin_externalpage_print_footer();
return;
}
+ $PAGE->set_state(moodle_page::STATE_PRINTING_FOOTER);
+
/// Course links or special footer
if ($course) {
if ($course === 'empty') {
$output = ob_get_contents();
ob_end_clean();
+ $PAGE->set_state(moodle_page::STATE_DONE);
+
if ($return) {
return $output;
} else {
header('Expires: ' . gmdate("D, d M Y H:i:s", time() + $lifetime) . ' GMT');
header('Cache-Control: max-age='. $lifetime);
header('Pragma: ');
- header('Content-type: text/css'); // Correct MIME type
+ header('Content-type: text/css'); // Correct MIME type
$DEFAULT_SHEET_LIST = array('styles_layout', 'styles_fonts', 'styles_color');
if (empty($themename)) {
- $themename = current_theme(); // So we have something. Normally not needed.
+ $themename = current_theme(); // So we have something. Normally not needed.
} else {
$themename = clean_param($themename, PARAM_SAFEDIR);
}
- if (!empty($forceconfig)) { // Page wants to use the config from this theme instead
+ theme_setup($themename);
+
+ if (!empty($forceconfig)) { // Page wants to use the config from this theme instead
unset($THEME);
include($CFG->themedir.'/'.$forceconfig.'/'.'config.php');
}
/// If this is the standard theme calling us, then find out what sheets we need
-
if ($themename == 'standard') {
if (!isset($THEME->standardsheets) or $THEME->standardsheets === true) { // Use all the sheets we have
$THEME->sheets = $DEFAULT_SHEET_LIST;
- } else if (empty($THEME->standardsheets)) { // We can stop right now!
+ } else if (empty($THEME->standardsheets)) { // We can stop right now!
echo "/***** Nothing required from this stylesheet by main theme *****/\n\n";
exit;
- } else { // Use the provided subset only
+ } else { // Use the provided subset only
$THEME->sheets = $THEME->standardsheets;
}
/// If we are a parent theme, then check for parent definitions
-
} else if (!empty($THEME->parent) && $themename == $THEME->parent) {
if (!isset($THEME->parentsheets) or $THEME->parentsheets === true) { // Use all the sheets we have
$THEME->sheets = $DEFAULT_SHEET_LIST;
}
/// Work out the last modified date for this theme
-
foreach ($THEME->sheets as $sheet) {
if (file_exists($CFG->themedir.'/'.$themename.'/'.$sheet.'.css')) {
$sheetmodified = filemtime($CFG->themedir.'/'.$themename.'/'.$sheet.'.css');
}
}
-
/// Get a list of all the files we want to include
$files = array();
function theme_setup($theme = '', $params=NULL) {
/// Sets up global variables related to themes
- global $CFG, $THEME, $SESSION, $USER, $HTTPSPAGEREQUIRED;
+ global $CFG, $THEME, $SESSION, $USER, $HTTPSPAGEREQUIRED, $PAGE;
/// Do not mess with THEME if header already printed - this would break all the extra stuff in global $THEME from print_header()!!
- if (defined('HEADER_PRINTED')) {
+ if ($PAGE->headerprinted) {
return;
}
$params[] = 'lang='.current_language();
}
-
/// Convert params to string
if ($params) {
$paramstring = '?'.implode('&', $params);
* Internal function - do not use directly!!
*/
function _print_normal_error($errorcode, $module, $a, $link, $backtrace, $debuginfo=null, $showerrordebugwarning=false) {
- global $CFG, $SESSION, $THEME, $DB;
+ global $CFG, $SESSION, $THEME, $DB, $PAGE;
if ($DB) {
//if you enable db debugging and exception is thrown, the print footer prints a lot of rubbish
$errordocroot = 'http://docs.moodle.org';
}
- if (! defined('HEADER_PRINTED')) {
+ if (!$PAGE->headerprinted) {
//header not yet printed
@header('HTTP/1.0 404 Not Found');
print_header(get_string('error'));
* @todo Finish documenting this function
*/
function notice ($message, $link='', $course=NULL) {
- global $CFG, $SITE, $THEME, $COURSE;
+ global $CFG, $SITE, $THEME, $COURSE, $PAGE;
$message = clean_text($message); // In case nasties are in here
die;
}
- if (! defined('HEADER_PRINTED')) {
+ if (!$PAGE->headerprinted) {
//header not yet printed
print_header(get_string('notice'));
} else {
* echo "<script type='text/javascript'>alert('Redirect $url');</script>";
*/
function redirect($url, $message='', $delay=-1) {
- global $CFG, $THEME, $SESSION;
+ global $CFG, $THEME, $SESSION, $PAGE;
if (!empty($CFG->usesid) && !isset($_COOKIE[session_name()])) {
$url = $SESSION->sid_process_url($url);
}
/// when no message and header printed yet, try to redirect
- if (empty($message) and !defined('HEADER_PRINTED')) {
+ if (empty($message) and !$PAGE->headerprinted) {
// Technically, HTTP/1.1 requires Location: header to contain
// the absolute path. (In practice browsers accept relative
if ($delay == -1) {
$delay = 3; // if no delay specified wait 3 seconds
}
- if (! defined('HEADER_PRINTED')) {
+ if (!$PAGE->headerprinted) {
// this type of redirect might not be working in some browsers - such as lynx :-(
print_header('', '', '', '', $errorprinted ? '' : ('<meta http-equiv="refresh" content="'. $delay .'; url='. $encodedurl .'" />'));
$delay += 3; // double redirect prevention, it was sometimes breaking upgrades before 1.7
}
function get_user_window($sessionid) {
-
- global $CFG;
+ global $CFG, $PAGE;
static $str;
$info = &$this->sets_info[$sessionid];
- course_setup($info['course'], $info['user']);
+ $PAGE->set_course($info['course']);
$timenow = time();
}
function message_broadcast($message, $sender) {
+ global $PAGE;
+
if(empty($this->conn_sets)) {
return true;
}
{
// Simply give them the message
- course_setup($info['course'], $info['user']);
+ $PAGE->set_course($info['course']);
$output = chat_format_message_manually($message, $info['courseid'], $sender, $info['user']);
$this->trace('Delivering message "'.$output->text.'" to '.$this->conn_sets[$sessionid][CHAT_CONNECTION_CHANNEL]);
$USER = $DB->get_record('user', array('id'=>$chatuser->userid));
//Setup course, lang and theme
- course_setup($chatuser->course);
+ $PAGE->set_course($course);
ob_start();
?>
}
//Get the minimal course
- if (!$course = $DB->get_record('course', array('id'=>$chatuser->course), 'id,theme,lang')) {
+ if (!$course = $DB->get_record('course', array('id'=>$chatuser->course))) {
print_error('invalidcourseid');
}
$USER->description = '';
//Setup course, lang and theme
- course_setup($course);
+ $PAGE->set_course($course);
// force deleting of timed out users if there is a silence in room or just entering
if ((time() - $chat_lasttime) > $CFG->chat_old_ping) {
}
//Get the minimal course
- if (!$course = $DB->get_record('course', array('id'=>$chatuser->course), 'id,theme,lang')) {
+ if (!$course = $DB->get_record('course', array('id'=>$chatuser->course))) {
print_error('invalidcourseid');
}
$USER->description = '';
//Setup course, lang and theme
- course_setup($course);
+ $PAGE->set_course($course);
// force deleting of timed out users if there is a silence in room or just entering
if ((time() - $chat_lasttime) > $CFG->chat_old_ping) {
}
//Get the minimal course
- if (!$course = $DB->get_record('course', array('id'=>$chatuser->course), 'id,theme,lang')) {
+ if (!$course = $DB->get_record('course', array('id'=>$chatuser->course))) {
print_error('invalidcourseid');
}
$USER->description = '';
//Setup course, lang and theme
- course_setup($course);
+ $PAGE->set_course($course);
$courseid = $chatuser->course;
$USER = $DB->get_record('user', array('id'=>$chatuser->userid));
//Setup course, lang and theme
- course_setup($chatuser->course);
+ $PAGE->set_course($DB->get_record('course', array('id' => $chatuser->course)));
ob_start();
?>
print_error('invalidcoursemodule');
}
- // call course_setup to use forced language, MDL-6926
- course_setup($course->id);
+ // Ensure lang, theme, etc. is set up properly. MDL-6926
+ $PAGE->set_course($course);
$coursecontext = get_context_instance(CONTEXT_COURSE, $course->id);
$modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
print_error('invalidcoursemodule');
}
$modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
- require_login($course->id, false, $cm);
+ require_login($course, false, $cm);
if (isguestuser()) {
// just in case
$forum->maxattachments = 3;
}
- // setup course variable to force form language
- // fix for MDL-6926
- course_setup($course->id);
require_once('post_form.php');
$mform_post = new mod_forum_post_form('post.php', array('course'=>$course, 'cm'=>$cm, 'coursecontext'=>$coursecontext, 'modcontext'=>$modcontext, 'forum'=>$forum, 'post'=>$post));
print_error('invalidcourseid');
}
-course_setup($course); // we should not require login here
+$PAGE->set_course($course); // we should not require login here
if ($id != SITEID and !empty($CFG->allowcoursethemes) and !empty($course->theme) and !empty($THEME->chameleonteachereditenabled)) {
if (!has_capability('moodle/course:update', get_context_instance(CONTEXT_COURSE, $id))) {