moodle_page: MDL-12212 start of new moodle_page class

* has course and status fields
* $PAGE->status updated by print_header and footer
* $PAGE->set_course now replace course_setup function
* global $PAGE created in setup.php
* unit tests for functionality so far
* Moodle still seems to work after this commit!
This commit is contained in:
tjhunt 2009-05-06 08:29:22 +00:00
parent de60de044c
commit c13a5e71cc
16 changed files with 198 additions and 95 deletions

View File

@ -26,7 +26,7 @@
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);
}

View File

@ -4152,7 +4152,7 @@ function admin_apply_default_settings($node=NULL, $unconditional=true) {
* @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;
@ -4193,7 +4193,7 @@ function admin_write_settings($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);

View File

@ -1864,37 +1864,6 @@ function dayofweek($day, $month, $year) {
/// 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.
*
@ -1945,10 +1914,22 @@ function get_login_url($loginguest=false) {
* 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()) {

View File

@ -32,6 +32,118 @@
* @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.
@ -58,7 +170,7 @@ function page_create_instance($instance) {
* 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;
@ -75,6 +187,7 @@ function page_create_object($type, $id = NULL) {
}
$object->init_quick($data);
$object->set_course($PAGE->course);
return $object;
}
@ -115,7 +228,7 @@ function page_map_class($type, $classname = NULL) {
* @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

View File

@ -852,7 +852,7 @@ function session_unloginas() {
* @return void
*/
function cron_setup_user($user=null, $course=null) {
global $CFG, $SITE;
global $CFG, $SITE, $PAGE;
static $cronuser = null;
static $cronsession = null;
@ -882,9 +882,9 @@ function cron_setup_user($user=null, $course=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 ;-)

View File

@ -57,6 +57,14 @@ global $SESSION;
*/
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
@ -263,6 +271,9 @@ global $SCRIPT;
get_system_context();
}
/// Create the $PAGE global.
$PAGE = new moodle_page();
/// Set error reporting back to normal
if ($originaldatabasedebug == -1) {
$CFG->debug = DEBUG_MINIMAL;
@ -491,8 +502,11 @@ global $SCRIPT;
}
}
// 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

View File

@ -745,7 +745,7 @@ function upgrade_log($type, $plugin, $info, $details=null, $backtrace=null) {
* 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;
@ -757,7 +757,7 @@ function upgrade_started($preinstall=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,

View File

@ -609,9 +609,9 @@ function close_window_button($name='closewindow', $return=false, $reloadopener =
* 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);
@ -2134,13 +2134,15 @@ function print_header ($title='', $heading='', $navigation='', $focus='',
$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) {
@ -2153,14 +2155,6 @@ function print_header ($title='', $heading='', $navigation='', $focus='',
}
}
/// 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) {
@ -2390,6 +2384,8 @@ function print_header ($title='', $heading='', $navigation='', $focus='',
$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 {
@ -2741,13 +2737,15 @@ function print_header_simple($title='', $heading='', $navigation='', $focus='',
* @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') {
@ -2846,6 +2844,8 @@ function print_footer($course=NULL, $usercourse=NULL, $return=false) {
$output = ob_get_contents();
ob_end_clean();
$PAGE->set_state(moodle_page::STATE_DONE);
if ($return) {
return $output;
} else {
@ -3000,35 +3000,35 @@ function style_sheet_setup($lastmodified=0, $lifetime=300, $themename='', $force
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;
@ -3041,7 +3041,6 @@ function style_sheet_setup($lastmodified=0, $lifetime=300, $themename='', $force
}
/// 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');
@ -3051,7 +3050,6 @@ function style_sheet_setup($lastmodified=0, $lifetime=300, $themename='', $force
}
}
/// Get a list of all the files we want to include
$files = array();
@ -3159,10 +3157,10 @@ function style_sheet_setup($lastmodified=0, $lifetime=300, $themename='', $force
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;
}
@ -3193,7 +3191,6 @@ function theme_setup($theme = '', $params=NULL) {
$params[] = 'lang='.current_language();
}
/// Convert params to string
if ($params) {
$paramstring = '?'.implode('&', $params);
@ -5597,7 +5594,7 @@ function print_error($errorcode, $module='error', $link='', $a=NULL) {
* 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
@ -5639,7 +5636,7 @@ function _print_normal_error($errorcode, $module, $a, $link, $backtrace, $debugi
$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'));
@ -5949,7 +5946,7 @@ function editorshortcutshelpbutton() {
* @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
@ -5959,7 +5956,7 @@ function notice ($message, $link='', $course=NULL) {
die;
}
if (! defined('HEADER_PRINTED')) {
if (!$PAGE->headerprinted) {
//header not yet printed
print_header(get_string('notice'));
} else {
@ -6015,7 +6012,7 @@ function notice_yesno ($message, $linkyes, $linkno, $optionsyes=NULL, $optionsno
* 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);
@ -6045,7 +6042,7 @@ function redirect($url, $message='', $delay=-1) {
}
/// 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
@ -6084,7 +6081,7 @@ function redirect($url, $message='', $delay=-1) {
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

View File

@ -225,13 +225,12 @@ class ChatDaemon {
}
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();
@ -702,6 +701,8 @@ EOD;
}
function message_broadcast($message, $sender) {
global $PAGE;
if(empty($this->conn_sets)) {
return true;
}
@ -718,7 +719,7 @@ EOD;
{
// 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]);

View File

@ -30,7 +30,7 @@
$USER = $DB->get_record('user', array('id'=>$chatuser->userid));
//Setup course, lang and theme
course_setup($chatuser->course);
$PAGE->set_course($course);
ob_start();
?>

View File

@ -14,7 +14,7 @@
}
//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');
}
@ -25,7 +25,7 @@
$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) {

View File

@ -36,7 +36,7 @@
}
//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');
}
@ -48,7 +48,7 @@
$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) {

View File

@ -13,7 +13,7 @@
}
//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');
}
@ -24,7 +24,7 @@
$USER->description = '';
//Setup course, lang and theme
course_setup($course);
$PAGE->set_course($course);
$courseid = $chatuser->course;

View File

@ -15,7 +15,7 @@
$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();
?>

View File

@ -134,8 +134,8 @@
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);
@ -441,7 +441,7 @@
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
@ -452,9 +452,6 @@
$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));

View File

@ -13,7 +13,7 @@ if (!$course = $DB->get_record('course', array('id'=>$id))) {
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))) {