PageRenderTime 226ms CodeModel.GetById 150ms app.highlight 60ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/pagelib.php

https://bitbucket.org/ngmares/moodle
PHP | 2220 lines | 963 code | 239 blank | 1018 comment | 209 complexity | 6cf33fe2ccd873f6b92dd54cbe5d1294 MD5 | raw file
   1<?php
   2// This file is part of Moodle - http://moodle.org/
   3//
   4// Moodle is free software: you can redistribute it and/or modify
   5// it under the terms of the GNU General Public License as published by
   6// the Free Software Foundation, either version 3 of the License, or
   7// (at your option) any later version.
   8//
   9// Moodle is distributed in the hope that it will be useful,
  10// but WITHOUT ANY WARRANTY; without even the implied warranty of
  11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12// GNU General Public License for more details.
  13//
  14// You should have received a copy of the GNU General Public License
  15// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16
  17/**
  18 * This file contains the moodle_page class. There is normally a single instance
  19 * of this class in the $PAGE global variable. This class is a central repository
  20 * of information about the page we are building up to send back to the user.
  21 *
  22 * @package core
  23 * @category page
  24 * @copyright  1999 onwards Martin Dougiamas  {@link http://moodle.com}
  25 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  26 */
  27
  28defined('MOODLE_INTERNAL') || die();
  29
  30/**
  31 * $PAGE is a central store of information about the current page we are
  32 * generating in response to the user's request.
  33 *
  34 * It does not do very much itself
  35 * except keep track of information, however, it serves as the access point to
  36 * some more significant components like $PAGE->theme, $PAGE->requires,
  37 * $PAGE->blocks, etc.
  38 *
  39 * @copyright 2009 Tim Hunt
  40 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  41 * @since Moodle 2.0
  42 * @package core
  43 * @category page
  44 *
  45 * The following properties are alphabetical. Please keep it that way so that its
  46 * easy to maintain.
  47 *
  48 * @property-read string $activityname The type of activity we are in, for example 'forum' or 'quiz'.
  49 *      Will be null if this page is not within a module.
  50 * @property-read stdClass $activityrecord The row from the activities own database table (for example
  51 *      the forum or quiz table) that this page belongs to. Will be null
  52 *      if this page is not within a module.
  53 * @property-read array $alternativeversions Mime type => object with ->url and ->title.
  54 * @property-read blocks_manager $blocks The blocks manager object for this page.
  55 * @property-read string $bodyclasses A string to use within the class attribute on the body tag.
  56 * @property-read string $bodyid A string to use as the id of the body tag.
  57 * @property-read string $button The HTML to go where the Turn editing on button normally goes.
  58 * @property-read bool $cacheable Defaults to true. Set to false to stop the page being cached at all.
  59 * @property-read array $categories An array of all the categories the page course belongs to,
  60 *      starting with the immediately containing category, and working out to
  61 *      the top-level category. This may be the empty array if we are in the
  62 *      front page course.
  63 * @property-read mixed $category The category that the page course belongs to.
  64 * @property-read cm_info $cm The course_module that this page belongs to. Will be null
  65 *      if this page is not within a module. This is a full cm object, as loaded
  66 *      by get_coursemodule_from_id or get_coursemodule_from_instance,
  67 *      so the extra modname and name fields are present.
  68 * @property-read context $context The main context to which this page belongs.
  69 * @property-read stdClass $course The current course that we are inside - a row from the
  70 *      course table. (Also available as $COURSE global.) If we are not inside
  71 *      an actual course, this will be the site course.
  72 * @property-read string $devicetypeinuse The name of the device type in use
  73 * @property-read string $docspath The path to the Moodle docs for this page.
  74 * @property-read string $focuscontrol The id of the HTML element to be focused when the page has loaded.
  75 * @property-read bool $headerprinted True if the page header has already been printed.
  76 * @property-read string $heading The main heading that should be displayed at the top of the <body>.
  77 * @property-read string $headingmenu The menu (or actions) to display in the heading
  78 * @property-read array $layout_options An arrays with options for the layout file.
  79 * @property-read array $legacythemeinuse True if the legacy browser theme is in use.
  80 * @property-read navbar $navbar The navbar object used to display the navbar
  81 * @property-read global_navigation $navigation The navigation structure for this page.
  82 * @property-read xml_container_stack $opencontainers Tracks XHTML tags on this page that have been opened but not closed.
  83 *      mainly for internal use by the rendering code.
  84 * @property-read string $pagelayout The general type of page this is. For example 'normal', 'popup', 'home'.
  85 *      Allows the theme to display things differently, if it wishes to.
  86 * @property-read string $pagetype The page type string, should be used as the id for the body tag in the theme.
  87 * @property-read int $periodicrefreshdelay The periodic refresh delay to use with meta refresh
  88 * @property-read page_requirements_manager $requires Tracks the JavaScript, CSS files, etc. required by this page.
  89 * @property-read settings_navigation $settingsnav The settings navigation
  90 * @property-read int $state One of the STATE_... constants
  91 * @property-read string $subpage The subpage identifier, if any.
  92 * @property-read theme_config $theme The theme for this page.
  93 * @property-read string $title The title that should go in the <head> section of the HTML of this page.
  94 * @property-read moodle_url $url The moodle url object for this page.
  95 */
  96class moodle_page {
  97
  98    /** The state of the page before it has printed the header **/
  99    const STATE_BEFORE_HEADER = 0;
 100
 101    /** The state the page is in temporarily while the header is being printed **/
 102    const STATE_PRINTING_HEADER = 1;
 103
 104    /** The state the page is in while content is presumably being printed **/
 105    const STATE_IN_BODY = 2;
 106
 107    /**
 108     * The state the page is when the footer has been printed and its function is
 109     * complete.
 110     */
 111    const STATE_DONE = 3;
 112
 113    /**
 114     * @var int The current state of the page. The state a page is within
 115     * determines what actions are possible for it.
 116     */
 117    protected $_state = self::STATE_BEFORE_HEADER;
 118
 119    /**
 120     * @var stdClass The course currently associated with this page.
 121     * If not has been provided the front page course is used.
 122     */
 123    protected $_course = null;
 124
 125    /**
 126     * @var cm_info If this page belongs to a module, this is the cm_info module
 127     * description object.
 128     */
 129    protected $_cm = null;
 130
 131    /**
 132     * @var stdClass If $_cm is not null, then this will hold the corresponding
 133     * row from the modname table. For example, if $_cm->modname is 'quiz', this
 134     * will be a row from the quiz table.
 135     */
 136    protected $_module = null;
 137
 138    /**
 139     * @var context The context that this page belongs to.
 140     */
 141    protected $_context = null;
 142
 143    /**
 144     * @var array This holds any categories that $_course belongs to, starting with the
 145     * particular category it belongs to, and working out through any parent
 146     * categories to the top level. These are loaded progressively, if needed.
 147     * There are three states. $_categories = null initially when nothing is
 148     * loaded; $_categories = array($id => $cat, $parentid => null) when we have
 149     * loaded $_course->category, but not any parents; and a complete array once
 150     * everything is loaded.
 151     */
 152    protected $_categories = null;
 153
 154    /**
 155     * @var array An array of CSS classes that should be added to the body tag in HTML.
 156     */
 157    protected $_bodyclasses = array();
 158
 159    /**
 160     * @var string The title for the page. Used within the title tag in the HTML head.
 161     */
 162    protected $_title = '';
 163
 164    /**
 165     * @var string The string to use as the heading of the page. Shown near the top of the
 166     * page within most themes.
 167     */
 168    protected $_heading = '';
 169
 170    /**
 171     * @var string The pagetype is used to describe the page and defaults to a representation
 172     * of the physical path to the page e.g. my-index, mod-quiz-attempt
 173     */
 174    protected $_pagetype = null;
 175
 176    /**
 177     * @var string The pagelayout to use when displaying this page. The
 178     * pagelayout needs to have been defined by the theme in use, or one of its
 179     * parents. By default base is used however standard is the more common layout.
 180     * Note that this gets automatically set by core during operations like
 181     * require_login.
 182     */
 183    protected $_pagelayout = 'base';
 184
 185    /**
 186     * @var array List of theme layout options, these are ignored by core.
 187     * To be used in individual theme layout files only.
 188     */
 189    protected $_layout_options = array();
 190
 191    /**
 192     * @var string An optional arbitrary parameter that can be set on pages where the context
 193     * and pagetype is not enough to identify the page.
 194     */
 195    protected $_subpage = '';
 196
 197    /**
 198     * @var string Set a different path to use for the 'Moodle docs for this page' link.
 199     * By default, it uses the path of the file for instance mod/quiz/attempt.
 200     */
 201    protected $_docspath = null;
 202
 203    /**
 204     * @var string A legacy class that will be added to the body tag
 205     */
 206    protected $_legacyclass = null;
 207
 208    /**
 209     * @var moodle_url The URL for this page. This is mandatory and must be set
 210     * before output is started.
 211     */
 212    protected $_url = null;
 213
 214    /**
 215     * @var array An array of links to alternative versions of this page.
 216     * Primarily used for RSS versions of the current page.
 217     */
 218    protected $_alternateversions = array();
 219
 220    /**
 221     * @var block_manager The blocks manager for this page. It is reponsible for
 222     * the blocks and there content on this page.
 223     */
 224    protected $_blocks = null;
 225
 226    /**
 227     * @var page_requirements_manager Page requirements manager. It is reponsible
 228     * for all JavaScript and CSS resources required by this page.
 229     */
 230    protected $_requires = null;
 231
 232    /**
 233     * @var string The capability required by the user in order to edit blocks
 234     * and block settings on this page.
 235     */
 236    protected $_blockseditingcap = 'moodle/site:manageblocks';
 237
 238    /**
 239     * @var bool An internal flag to record when block actions have been processed.
 240     * Remember block actions occur on the current URL and it is important that
 241     * even they are never executed more than once.
 242     */
 243    protected $_block_actions_done = false;
 244
 245    /**
 246     * @var array An array of any other capabilities the current user must have
 247     * in order to editing the page and/or its content (not just blocks).
 248     */
 249    protected $_othereditingcaps = array();
 250
 251    /**
 252     * @var bool Sets whether this page should be cached by the browser or not.
 253     * If it is set to true (default) the page is served with caching headers.
 254     */
 255    protected $_cacheable = true;
 256
 257    /**
 258     * @var string Can be set to the ID of an element on the page, if done that
 259     * element receives focus when the page loads.
 260     */
 261    protected $_focuscontrol = '';
 262
 263    /**
 264     * @var string HTML to go where the turn on editing button is located. This
 265     * is nearly a legacy item and not used very often any more.
 266     */
 267    protected $_button = '';
 268
 269    /**
 270     * @var theme_config The theme to use with this page. This has to be properly
 271     * initialised via {@link moodle_page::initialise_theme_and_output()} which
 272     * happens magically before any operation that requires it.
 273     */
 274    protected $_theme = null;
 275
 276    /**
 277     * @var global_navigation Contains the global navigation structure.
 278     */
 279    protected $_navigation = null;
 280
 281    /**
 282     * @var settings_navigation Contains the settings navigation structure.
 283     */
 284    protected $_settingsnav = null;
 285
 286    /**
 287     * @var navbar Contains the navbar structure.
 288     */
 289    protected $_navbar = null;
 290
 291    /**
 292     * @var string The menu (or actions) to display in the heading.
 293     */
 294    protected $_headingmenu = null;
 295
 296    /**
 297     * @var array stack trace. Then the theme is initialised, we save the stack
 298     * trace, for use in error messages.
 299     */
 300    protected $_wherethemewasinitialised = null;
 301
 302    /**
 303     * @var xhtml_container_stack Tracks XHTML tags on this page that have been
 304     * opened but not closed.
 305     */
 306    protected $_opencontainers;
 307
 308    /**
 309     * @var int Sets the page to refresh after a given delay (in seconds) using
 310     * meta refresh in {@link standard_head_html()} in outputlib.php
 311     * If set to null(default) the page is not refreshed
 312     */
 313    protected $_periodicrefreshdelay = null;
 314
 315    /**
 316     * @var stdClass This is simply to improve backwards compatibility. If old
 317     * code relies on a page class that implements print_header, or complex logic
 318     * in user_allowed_editing then we stash an instance of that other class here,
 319     * and delegate to it in certain situations.
 320     */
 321    protected $_legacypageobject = null;
 322
 323    /**
 324     * @var array Associative array of browser shortnames (as used by check_browser_version)
 325     * and their minimum required versions
 326     */
 327    protected $_legacybrowsers = array('MSIE' => 6.0);
 328
 329    /**
 330     * @var string Is set to the name of the device type in use.
 331     * This will we worked out when it is first used.
 332     */
 333    protected $_devicetypeinuse = null;
 334
 335    /**
 336     * @var bool Used to determine if HTTPS should be required for login.
 337     */
 338    protected $_https_login_required = false;
 339
 340    /**
 341     * @var bool Determines if popup notifications allowed on this page.
 342     * Code such as the quiz module disables popup notifications in situations
 343     * such as upgrading or completing a quiz.
 344     */
 345    protected $_popup_notification_allowed = true;
 346
 347    // Magic getter methods =============================================================
 348    // Due to the __get magic below, you normally do not call these as $PAGE->magic_get_x
 349    // methods, but instead use the $PAGE->x syntax.
 350
 351    /**
 352     * Please do not call this method directly, use the ->state syntax. {@link moodle_page::__get()}.
 353     * @return integer one of the STATE_XXX constants. You should not normally need
 354     * to use this in your code. It is intended for internal use by this class
 355     * and its friends like print_header, to check that everything is working as
 356     * expected. Also accessible as $PAGE->state.
 357     */
 358    protected function magic_get_state() {
 359        return $this->_state;
 360    }
 361
 362    /**
 363     * Please do not call this method directly, use the ->headerprinted syntax. {@link moodle_page::__get()}.
 364     * @return bool has the header already been printed?
 365     */
 366    protected function magic_get_headerprinted() {
 367        return $this->_state >= self::STATE_IN_BODY;
 368    }
 369
 370    /**
 371     * Please do not call this method directly, use the ->course syntax. {@link moodle_page::__get()}.
 372     * @return stdClass the current course that we are inside - a row from the
 373     * course table. (Also available as $COURSE global.) If we are not inside
 374     * an actual course, this will be the site course.
 375     */
 376    protected function magic_get_course() {
 377        global $SITE;
 378        if (is_null($this->_course)) {
 379            return $SITE;
 380        }
 381        return $this->_course;
 382    }
 383
 384    /**
 385     * Please do not call this method directly, use the ->cm syntax. {@link moodle_page::__get()}.
 386     * @return cm_info the course_module that this page belongs to. Will be null
 387     * if this page is not within a module. This is a full cm object, as loaded
 388     * by get_coursemodule_from_id or get_coursemodule_from_instance,
 389     * so the extra modname and name fields are present.
 390     */
 391    protected function magic_get_cm() {
 392        return $this->_cm;
 393    }
 394
 395    /**
 396     * Please do not call this method directly, use the ->activityrecord syntax. {@link moodle_page::__get()}.
 397     * @return stdClass the row from the activities own database table (for example
 398     * the forum or quiz table) that this page belongs to. Will be null
 399     * if this page is not within a module.
 400     */
 401    protected function magic_get_activityrecord() {
 402        if (is_null($this->_module) && !is_null($this->_cm)) {
 403            $this->load_activity_record();
 404        }
 405        return $this->_module;
 406    }
 407
 408    /**
 409     * Please do not call this method directly, use the ->activityname syntax. {@link moodle_page::__get()}.
 410     * @return string the The type of activity we are in, for example 'forum' or 'quiz'.
 411     * Will be null if this page is not within a module.
 412     */
 413    protected function magic_get_activityname() {
 414        if (is_null($this->_cm)) {
 415            return null;
 416        }
 417        return $this->_cm->modname;
 418    }
 419
 420    /**
 421     * Please do not call this method directly, use the ->category syntax. {@link moodle_page::__get()}.
 422     * @return stdClass the category that the page course belongs to. If there isn't one
 423     * (that is, if this is the front page course) returns null.
 424     */
 425    protected function magic_get_category() {
 426        $this->ensure_category_loaded();
 427        if (!empty($this->_categories)) {
 428            return reset($this->_categories);
 429        } else {
 430            return null;
 431        }
 432    }
 433
 434    /**
 435     * Please do not call this method directly, use the ->categories syntax. {@link moodle_page::__get()}.
 436     * @return array an array of all the categories the page course belongs to,
 437     * starting with the immediately containing category, and working out to
 438     * the top-level category. This may be the empty array if we are in the
 439     * front page course.
 440     */
 441    protected function magic_get_categories() {
 442        $this->ensure_categories_loaded();
 443        return $this->_categories;
 444    }
 445
 446    /**
 447     * Please do not call this method directly, use the ->context syntax. {@link moodle_page::__get()}.
 448     * @return context the main context to which this page belongs.
 449     */
 450    protected function magic_get_context() {
 451        if (is_null($this->_context)) {
 452            if (CLI_SCRIPT or NO_MOODLE_COOKIES) {
 453                // cli scripts work in system context, do not annoy devs with debug info
 454                // very few scripts do not use cookies, we can safely use system as default context there
 455            } else {
 456                debugging('Coding problem: $PAGE->context was not set. You may have forgotten '
 457                    .'to call require_login() or $PAGE->set_context(). The page may not display '
 458                    .'correctly as a result');
 459            }
 460            $this->_context = get_context_instance(CONTEXT_SYSTEM);
 461        }
 462        return $this->_context;
 463    }
 464
 465    /**
 466     * Please do not call this method directly, use the ->pagetype syntax. {@link moodle_page::__get()}.
 467     * @return string e.g. 'my-index' or 'mod-quiz-attempt'.
 468     */
 469    protected function magic_get_pagetype() {
 470        global $CFG;
 471        if (is_null($this->_pagetype) || isset($CFG->pagepath)) {
 472            $this->initialise_default_pagetype();
 473        }
 474        return $this->_pagetype;
 475    }
 476
 477    /**
 478     * Please do not call this method directly, use the ->pagetype syntax. {@link moodle_page::__get()}.
 479     * @return string The id to use on the body tag, uses {@link magic_get_pagetype()}.
 480     */
 481    protected function magic_get_bodyid() {
 482        return 'page-'.$this->pagetype;
 483    }
 484
 485    /**
 486     * Please do not call this method directly, use the ->pagelayout syntax. {@link moodle_page::__get()}.
 487     * @return string the general type of page this is. For example 'standard', 'popup', 'home'.
 488     *      Allows the theme to display things differently, if it wishes to.
 489     */
 490    protected function magic_get_pagelayout() {
 491        return $this->_pagelayout;
 492    }
 493
 494    /**
 495     * Please do not call this method directly, use the ->layout_tions syntax. {@link moodle_page::__get()}.
 496     * @return array returns arrys with options for layout file
 497     */
 498    protected function magic_get_layout_options() {
 499        return $this->_layout_options;
 500    }
 501
 502    /**
 503     * Please do not call this method directly, use the ->subpage syntax. {@link moodle_page::__get()}.
 504     * @return string The subpage identifier, if any.
 505     */
 506    protected function magic_get_subpage() {
 507        return $this->_subpage;
 508    }
 509
 510    /**
 511     * Please do not call this method directly, use the ->bodyclasses syntax. {@link moodle_page::__get()}.
 512     * @return string the class names to put on the body element in the HTML.
 513     */
 514    protected function magic_get_bodyclasses() {
 515        return implode(' ', array_keys($this->_bodyclasses));
 516    }
 517
 518    /**
 519     * Please do not call this method directly, use the ->title syntax. {@link moodle_page::__get()}.
 520     * @return string the title that should go in the <head> section of the HTML of this page.
 521     */
 522    protected function magic_get_title() {
 523        return $this->_title;
 524    }
 525
 526    /**
 527     * Please do not call this method directly, use the ->heading syntax. {@link moodle_page::__get()}.
 528     * @return string the main heading that should be displayed at the top of the <body>.
 529     */
 530    protected function magic_get_heading() {
 531        return $this->_heading;
 532    }
 533
 534    /**
 535     * Please do not call this method directly, use the ->heading syntax. {@link moodle_page::__get()}.
 536     * @return string The menu (or actions) to display in the heading
 537     */
 538    protected function magic_get_headingmenu() {
 539        return $this->_headingmenu;
 540    }
 541
 542    /**
 543     * Please do not call this method directly, use the ->docspath syntax. {@link moodle_page::__get()}.
 544     * @return string the path to the Moodle docs for this page.
 545     */
 546    protected function magic_get_docspath() {
 547        if (is_string($this->_docspath)) {
 548            return $this->_docspath;
 549        } else {
 550            return str_replace('-', '/', $this->pagetype);
 551        }
 552    }
 553
 554    /**
 555     * Please do not call this method directly, use the ->url syntax. {@link moodle_page::__get()}.
 556     * @return moodle_url the clean URL required to load the current page. (You
 557     * should normally use this in preference to $ME or $FULLME.)
 558     */
 559    protected function magic_get_url() {
 560        global $FULLME;
 561        if (is_null($this->_url)) {
 562            debugging('This page did not call $PAGE->set_url(...). Using '.s($FULLME), DEBUG_DEVELOPER);
 563            $this->_url = new moodle_url($FULLME);
 564            // Make sure the guessed URL cannot lead to dangerous redirects.
 565            $this->_url->remove_params('sesskey');
 566        }
 567        return new moodle_url($this->_url); // Return a clone for safety.
 568    }
 569
 570    /**
 571     * The list of alternate versions of this page.
 572     * @return array mime type => object with ->url and ->title.
 573     */
 574    protected function magic_get_alternateversions() {
 575        return $this->_alternateversions;
 576    }
 577
 578    /**
 579     * Please do not call this method directly, use the ->blocks syntax. {@link moodle_page::__get()}.
 580     * @return blocks_manager the blocks manager object for this page.
 581     */
 582    protected function magic_get_blocks() {
 583        global $CFG;
 584        if (is_null($this->_blocks)) {
 585            if (!empty($CFG->blockmanagerclass)) {
 586                $classname = $CFG->blockmanagerclass;
 587            } else {
 588                $classname = 'block_manager';
 589            }
 590            $this->_blocks = new $classname($this);
 591        }
 592        return $this->_blocks;
 593    }
 594
 595    /**
 596     * Please do not call this method directly, use the ->requires syntax. {@link moodle_page::__get()}.
 597     * @return page_requirements_manager tracks the JavaScript, CSS files, etc. required by this page.
 598     */
 599    protected function magic_get_requires() {
 600        global $CFG;
 601        if (is_null($this->_requires)) {
 602            $this->_requires = new page_requirements_manager();
 603        }
 604        return $this->_requires;
 605    }
 606
 607    /**
 608     * Please do not call this method directly, use the ->cacheable syntax. {@link moodle_page::__get()}.
 609     * @return bool can this page be cached by the user's browser.
 610     */
 611    protected function magic_get_cacheable() {
 612        return $this->_cacheable;
 613    }
 614
 615    /**
 616     * Please do not call this method directly, use the ->focuscontrol syntax. {@link moodle_page::__get()}.
 617     * @return string the id of the HTML element to be focused when the page has loaded.
 618     */
 619    protected function magic_get_focuscontrol() {
 620        return $this->_focuscontrol;
 621    }
 622
 623    /**
 624     * Please do not call this method directly, use the ->button syntax. {@link moodle_page::__get()}.
 625     * @return string the HTML to go where the Turn editing on button normally goes.
 626     */
 627    protected function magic_get_button() {
 628        return $this->_button;
 629    }
 630
 631    /**
 632     * Please do not call this method directly, use the ->theme syntax. {@link moodle_page::__get()}.
 633     * @return theme_config the initialised theme for this page.
 634     */
 635    protected function magic_get_theme() {
 636        if (is_null($this->_theme)) {
 637            $this->initialise_theme_and_output();
 638        }
 639        return $this->_theme;
 640    }
 641
 642    /**
 643     * Please do not call this method directly, use the ->devicetypeinuse syntax. {@link moodle_page::__get()}.
 644     * @return string The device type being used.
 645     */
 646    protected function magic_get_devicetypeinuse() {
 647        if (empty($this->_devicetypeinuse)) {
 648            $this->_devicetypeinuse = get_user_device_type();
 649        }
 650        return $this->_devicetypeinuse;
 651    }
 652
 653    /**
 654     * Please do not call this method directly, use the ->legacythemeinuse syntax. {@link moodle_page::__get()}.
 655     * @deprecated since 2.1
 656     * @return bool
 657     */
 658    protected function magic_get_legacythemeinuse() {
 659        debugging('$PAGE->legacythemeinuse is a deprecated property - please use $PAGE->devicetypeinuse and check if it is equal to legacy.', DEBUG_DEVELOPER);
 660        return ($this->devicetypeinuse == 'legacy');
 661    }
 662
 663    /**
 664     * Please do not call this method directly use the ->periodicrefreshdelay syntax
 665     * {@link moodle_page::__get()}
 666     * @return int The periodic refresh delay to use with meta refresh
 667     */
 668    protected function magic_get_periodicrefreshdelay() {
 669        return $this->_periodicrefreshdelay;
 670    }
 671
 672    /**
 673     * Please do not call this method directly use the ->opencontainers syntax. {@link moodle_page::__get()}
 674     * @return xhtml_container_stack tracks XHTML tags on this page that have been opened but not closed.
 675     *      mainly for internal use by the rendering code.
 676     */
 677    protected function magic_get_opencontainers() {
 678        if (is_null($this->_opencontainers)) {
 679            $this->_opencontainers = new xhtml_container_stack();
 680        }
 681        return $this->_opencontainers;
 682    }
 683
 684    /**
 685     * Return the navigation object
 686     * @return global_navigation
 687     */
 688    protected function magic_get_navigation() {
 689        if ($this->_navigation === null) {
 690            $this->_navigation = new global_navigation($this);
 691        }
 692        return $this->_navigation;
 693    }
 694
 695    /**
 696     * Return a navbar object
 697     * @return navbar
 698     */
 699    protected function magic_get_navbar() {
 700        if ($this->_navbar === null) {
 701            $this->_navbar = new navbar($this);
 702        }
 703        return $this->_navbar;
 704    }
 705
 706    /**
 707     * Returns the settings navigation object
 708     * @return settings_navigation
 709     */
 710    protected function magic_get_settingsnav() {
 711        if ($this->_settingsnav === null) {
 712            $this->_settingsnav = new settings_navigation($this);
 713            $this->_settingsnav->initialise();
 714        }
 715        return $this->_settingsnav;
 716    }
 717
 718    /**
 719     * PHP overloading magic to make the $PAGE->course syntax work by redirecting
 720     * it to the corresponding $PAGE->magic_get_course() method if there is one, and
 721     * throwing an exception if not.
 722     *
 723     * @param string $name property name
 724     * @return mixed
 725     */
 726    public function __get($name) {
 727        $getmethod = 'magic_get_' . $name;
 728        if (method_exists($this, $getmethod)) {
 729            return $this->$getmethod();
 730        } else {
 731            throw new coding_exception('Unknown property ' . $name . ' of $PAGE.');
 732        }
 733    }
 734
 735    /**
 736     * PHP overloading magic to catch obvious coding errors.
 737     *
 738     * This method has been created to catch obvious coding errors where the
 739     * developer has tried to set a page property using $PAGE->key = $value.
 740     * In the moodle_page class all properties must be set using the appropriate
 741     * $PAGE->set_something($value) method.
 742     *
 743     * @param string $name property name
 744     * @param mixed $value Value
 745     * @return void Throws exception if field not defined in page class
 746     */
 747    public function __set($name, $value) {
 748        if (method_exists($this, 'set_' . $name)) {
 749            throw new coding_exception('Invalid attempt to modify page object', "Use \$PAGE->set_$name() instead.");
 750        } else {
 751            throw new coding_exception('Invalid attempt to modify page object', "Unknown property $name");
 752        }
 753    }
 754
 755    // Other information getting methods ==========================================
 756
 757    /**
 758     * Returns instance of page renderer
 759     *
 760     * @param string $component name such as 'core', 'mod_forum' or 'qtype_multichoice'.
 761     * @param string $subtype optional subtype such as 'news' resulting to 'mod_forum_news'
 762     * @param string $target one of rendering target constants
 763     * @return renderer_base
 764     */
 765    public function get_renderer($component, $subtype = null, $target = null) {
 766        return $this->magic_get_theme()->get_renderer($this, $component, $subtype, $target);
 767    }
 768
 769    /**
 770     * Checks to see if there are any items on the navbar object
 771     *
 772     * @return bool true if there are, false if not
 773     */
 774    public function has_navbar() {
 775        if ($this->_navbar === null) {
 776            $this->_navbar = new navbar($this);
 777        }
 778        return $this->_navbar->has_items();
 779    }
 780
 781    /**
 782     * Should the current user see this page in editing mode.
 783     * That is, are they allowed to edit this page, and are they currently in
 784     * editing mode.
 785     * @return bool
 786     */
 787    public function user_is_editing() {
 788        global $USER;
 789        return !empty($USER->editing) && $this->user_allowed_editing();
 790    }
 791
 792    /**
 793     * Does the user have permission to edit blocks on this page.
 794     * @return bool
 795     */
 796    public function user_can_edit_blocks() {
 797        return has_capability($this->_blockseditingcap, $this->_context);
 798    }
 799
 800    /**
 801     * Does the user have permission to see this page in editing mode.
 802     * @return bool
 803     */
 804    public function user_allowed_editing() {
 805        if ($this->_legacypageobject) {
 806            return $this->_legacypageobject->user_allowed_editing();
 807        }
 808        return has_any_capability($this->all_editing_caps(), $this->_context);
 809    }
 810
 811    /**
 812     * Get a description of this page. Normally displayed in the footer in
 813     * developer debug mode.
 814     * @return string
 815     */
 816    public function debug_summary() {
 817        $summary = '';
 818        $summary .= 'General type: ' . $this->pagelayout . '. ';
 819        if (!during_initial_install()) {
 820            $summary .= 'Context ' . print_context_name($this->_context) . ' (context id ' . $this->_context->id . '). ';
 821        }
 822        $summary .= 'Page type ' . $this->pagetype .  '. ';
 823        if ($this->subpage) {
 824            'Sub-page ' . $this->subpage .  '. ';
 825        }
 826        return $summary;
 827    }
 828
 829    // Setter methods =============================================================
 830
 831    /**
 832     * Set the state. The state must be one of that STATE_... constants, and
 833     * the state is only allowed to advance one step at a time.
 834     *
 835     * @param integer $state The new state.
 836     */
 837    public function set_state($state) {
 838        if ($state != $this->_state + 1 || $state > self::STATE_DONE) {
 839            throw new coding_exception('Invalid state passed to moodle_page::set_state. We are in state ' .
 840                    $this->_state . ' and state ' . $state . ' was requested.');
 841        }
 842
 843        if ($state == self::STATE_PRINTING_HEADER) {
 844            $this->starting_output();
 845        }
 846
 847        $this->_state = $state;
 848    }
 849
 850    /**
 851     * Set the current course. This sets both $PAGE->course and $COURSE. It also
 852     * sets the right theme and locale.
 853     *
 854     * Normally you don't need to call this function yourself, require_login will
 855     * call it for you if you pass a $course to it. You can use this function
 856     * on pages that do need to call require_login().
 857     *
 858     * Sets $PAGE->context to the course context, if it is not already set.
 859     *
 860     * @param stdClass $course the course to set as the global course.
 861     */
 862    public function set_course($course) {
 863        global $COURSE, $PAGE;
 864
 865        if (empty($course->id)) {
 866            throw new coding_exception('$course passed to moodle_page::set_course does not look like a proper course object.');
 867        }
 868
 869        $this->ensure_theme_not_set();
 870
 871        if (!empty($this->_course->id) && $this->_course->id != $course->id) {
 872            $this->_categories = null;
 873        }
 874
 875        $this->_course = clone($course);
 876
 877        if ($this === $PAGE) {
 878            $COURSE = $this->_course;
 879            moodle_setlocale();
 880        }
 881
 882        if (!$this->_context) {
 883            $this->set_context(get_context_instance(CONTEXT_COURSE, $this->_course->id));
 884        }
 885    }
 886
 887    /**
 888     * Set the main context to which this page belongs.
 889     *
 890     * @param context $context a context object, normally obtained with get_context_instance.
 891     */
 892    public function set_context($context) {
 893        if ($context === null) {
 894            // extremely ugly hack which sets context to some value in order to prevent warnings,
 895            // use only for core error handling!!!!
 896            if (!$this->_context) {
 897                $this->_context = get_context_instance(CONTEXT_SYSTEM);
 898            }
 899            return;
 900        }
 901
 902        // ideally we should set context only once
 903        if (isset($this->_context)) {
 904            if ($context->id == $this->_context->id) {
 905                // fine - no change needed
 906            } else if ($this->_context->contextlevel == CONTEXT_SYSTEM or $this->_context->contextlevel == CONTEXT_COURSE) {
 907                // hmm - not ideal, but it might produce too many warnings due to the design of require_login
 908            } else if ($this->_context->contextlevel == CONTEXT_MODULE and $this->_context->id == get_parent_contextid($context)) {
 909                // hmm - most probably somebody did require_login() and after that set the block context
 910            } else {
 911                // we do not want devs to do weird switching of context levels on the fly,
 912                // because we might have used the context already such as in text filter in page title
 913                debugging('Coding problem: unsupported modification of PAGE->context from '.$this->_context->contextlevel.' to '.$context->contextlevel);
 914            }
 915        }
 916
 917        $this->_context = $context;
 918    }
 919
 920    /**
 921     * The course module that this page belongs to (if it does belong to one).
 922     *
 923     * @param stdClass|cm_info $cm a record from course_modules table or cm_info from get_fast_modinfo().
 924     * @param stdClass $course
 925     * @param stdClass $module
 926     * @return void
 927     */
 928    public function set_cm($cm, $course = null, $module = null) {
 929        global $DB;
 930
 931        if (!isset($cm->id) || !isset($cm->course)) {
 932            throw new coding_exception('Invalid $cm parameter for $PAGE object, it has to be instance of cm_info or record from the course_modules table.');
 933        }
 934
 935        if (!$this->_course || $this->_course->id != $cm->course) {
 936            if (!$course) {
 937                $course = $DB->get_record('course', array('id' => $cm->course), '*', MUST_EXIST);
 938            }
 939            if ($course->id != $cm->course) {
 940                throw new coding_exception('The course you passed to $PAGE->set_cm does not correspond to the $cm.');
 941            }
 942            $this->set_course($course);
 943        }
 944
 945        // make sure we have a $cm from get_fast_modinfo as this contains activity access details
 946        if (!($cm instanceof cm_info)) {
 947            $modinfo = get_fast_modinfo($this->_course);
 948            $cm = $modinfo->get_cm($cm->id);
 949        }
 950        $this->_cm = $cm;
 951
 952        // unfortunately the context setting is a mess, let's try to work around some common block problems and show some debug messages
 953        if (empty($this->_context) or $this->_context->contextlevel != CONTEXT_BLOCK) {
 954            $context = get_context_instance(CONTEXT_MODULE, $cm->id);
 955            $this->set_context($context);
 956        }
 957
 958        if ($module) {
 959            $this->set_activity_record($module);
 960        }
 961    }
 962
 963    /**
 964     * Sets the activity record. This could be a row from the main table for a
 965     * module. For instance if the current module (cm) is a forum this should be a row
 966     * from the forum table.
 967     *
 968     * @param stdClass $module A row from the main database table for the module that this
 969     * page belongs to.
 970     * @return void
 971     */
 972    public function set_activity_record($module) {
 973        if (is_null($this->_cm)) {
 974            throw new coding_exception('You cannot call $PAGE->set_activity_record until after $PAGE->cm has been set.');
 975        }
 976        if ($module->id != $this->_cm->instance || $module->course != $this->_course->id) {
 977            throw new coding_exception('The activity record your are trying to set does not seem to correspond to the cm that has been set.');
 978        }
 979        $this->_module = $module;
 980    }
 981
 982    /**
 983     * Sets the pagetype to use for this page.
 984     *
 985     * Normally you do not need to set this manually, it is automatically created
 986     * from the script name. However, on some pages this is overridden.
 987     * For example the page type for course/view.php includes the course format,
 988     * for example 'course-view-weeks'. This gets used as the id attribute on
 989     * <body> and also for determining which blocks are displayed.
 990     *
 991     * @param string $pagetype e.g. 'my-index' or 'mod-quiz-attempt'.
 992     */
 993    public function set_pagetype($pagetype) {
 994        $this->_pagetype = $pagetype;
 995    }
 996
 997    /**
 998     * Sets the layout to use for this page.
 999     *
1000     * The page layout determines how the page will be displayed, things such as
1001     * block regions, content areas, etc are controlled by the layout.
1002     * The theme in use for the page will determine that the layout contains.
1003     *
1004     * This properly defaults to 'base', so you only need to call this function if
1005     * you want something different. The exact range of supported layouts is specified
1006     * in the standard theme.
1007     *
1008     * For an idea of the common page layouts see
1009     * {@link http://docs.moodle.org/dev/Themes_2.0#The_different_layouts_as_of_August_17th.2C_2010}
1010     * But please keep in mind that it may be (and normally is) out of date.
1011     * The only place to find an accurate up-to-date list of the page layouts
1012     * available for your version of Moodle is {@link theme/base/config.php}
1013     *
1014     * @param string $pagelayout the page layout this is. For example 'popup', 'home'.
1015     */
1016    public function set_pagelayout($pagelayout) {
1017        /**
1018         * Uncomment this to debug theme pagelayout issues like missing blocks.
1019         *
1020         * if (!empty($this->_wherethemewasinitialised) && $pagelayout != $this->_pagelayout) {
1021         *     debugging('Page layout has already been set and cannot be changed.', DEBUG_DEVELOPER);
1022         * }
1023         */
1024        $this->_pagelayout = $pagelayout;
1025    }
1026
1027    /**
1028     * If context->id and pagetype are not enough to uniquely identify this page,
1029     * then you can set a subpage id as well. For example, the tags page sets
1030     *
1031     * @param string $subpage an arbitrary identifier that, along with context->id
1032     *      and pagetype, uniquely identifies this page.
1033     */
1034    public function set_subpage($subpage) {
1035        if (empty($subpage)) {
1036            $this->_subpage = '';
1037        } else {
1038            $this->_subpage = $subpage;
1039        }
1040    }
1041
1042    /**
1043     * Adds a CSS class to the body tag of the page.
1044     *
1045     * @param string $class add this class name ot the class attribute on the body tag.
1046     */
1047    public function add_body_class($class) {
1048        if ($this->_state > self::STATE_BEFORE_HEADER) {
1049            throw new coding_exception('Cannot call moodle_page::add_body_class after output has been started.');
1050        }
1051        $this->_bodyclasses[$class] = 1;
1052    }
1053
1054    /**
1055     * Adds an array of body classes to the body tag of this page.
1056     *
1057     * @param array $classes this utility method calls add_body_class for each array element.
1058     */
1059    public function add_body_classes($classes) {
1060        foreach ($classes as $class) {
1061            $this->add_body_class($class);
1062        }
1063    }
1064
1065    /**
1066     * Sets the title for the page.
1067     * This is normally used within the title tag in the head of the page.
1068     *
1069     * @param string $title the title that should go in the <head> section of the HTML of this page.
1070     */
1071    public function set_title($title) {
1072        $title = format_string($title);
1073        $title = str_replace('"', '&quot;', $title);
1074        $this->_title = $title;
1075    }
1076
1077    /**
1078     * Sets the heading to use for the page.
1079     * This is normally used as the main heading at the top of the content.
1080     *
1081     * @param string $heading the main heading that should be displayed at the top of the <body>.
1082     */
1083    public function set_heading($heading) {
1084        $this->_heading = format_string($heading);
1085    }
1086
1087    /**
1088     * Sets some HTML to use next to the heading {@link moodle_page::set_heading()}
1089     *
1090     * @param string $menu The menu/content to show in the heading
1091     */
1092    public function set_headingmenu($menu) {
1093        $this->_headingmenu = $menu;
1094    }
1095
1096    /**
1097     * Set the course category this page belongs to manually.
1098     *
1099     * This automatically sets $PAGE->course to be the site course. You cannot
1100     * use this method if you have already set $PAGE->course - in that case,
1101     * the category must be the one that the course belongs to. This also
1102     * automatically sets the page context to the category context.
1103     *
1104     * @param integer $categoryid The id of the category to set.
1105     */
1106    public function set_category_by_id($categoryid) {
1107        global $SITE, $DB;
1108        if (!is_null($this->_course)) {
1109            throw new coding_exception('Attempt to manually set the course category when the course has been set. This is not allowed.');
1110        }
1111        if (is_array($this->_categories)) {
1112            throw new coding_exception('Course category has already been set. You are not allowed to change it.');
1113        }
1114        $this->ensure_theme_not_set();
1115        $this->set_course($SITE);
1116        $this->load_category($categoryid);
1117        $this->set_context(get_context_instance(CONTEXT_COURSECAT, $categoryid));
1118    }
1119
1120    /**
1121     * Set a different path to use for the 'Moodle docs for this page' link.
1122     *
1123     * By default, it uses the pagetype, which is normally the same as the
1124     * script name. So, for example, for mod/quiz/attempt.php, pagetype is
1125     * mod-quiz-attempt, and so docspath is mod/quiz/attempt.
1126     *
1127     * @param string $path the path to use at the end of the moodle docs URL.
1128     */
1129    public function set_docs_path($path) {
1130        $this->_docspath = $path;
1131    }
1132
1133    /**
1134     * You should call this method from every page to set the cleaned-up URL
1135     * that should be used to return to this page.
1136     *
1137     * Used, for example, by the blocks editing UI to know where to return the
1138     * user after an action.
1139     * For example, course/view.php does:
1140     *      $id = optional_param('id', 0, PARAM_INT);
1141     *      $PAGE->set_url('/course/view.php', array('id' => $id));
1142     *
1143     * @param moodle_url|string $url URL relative to $CFG->wwwroot or {@link moodle_url} instance
1144     * @param array $params parameters to add to the URL
1145     */
1146    public function set_url($url, array $params = null) {
1147        global $CFG;
1148
1149        if (is_string($url)) {
1150            if (strpos($url, 'http') === 0) {
1151                // ok
1152            } else if (strpos($url, '/') === 0) {
1153                // we have to use httpswwwroot here, because of loginhttps pages
1154                $url = $CFG->httpswwwroot . $url;
1155            } else {
1156                throw new coding_exception('Invalid parameter $url, has to be full url or in shortened form starting with /.');
1157            }
1158        }
1159
1160        $this->_url = new moodle_url($url, $params);
1161
1162        $fullurl = $this->_url->out_omit_querystring();
1163        if (strpos($fullurl, "$CFG->httpswwwroot/") !== 0) {
1164            debugging('Most probably incorrect set_page() url argument, it does not match the httpswwwroot!');
1165        }
1166        $shorturl = str_replace("$CFG->httpswwwroot/", '', $fullurl);
1167
1168        if (is_null($this->_pagetype)) {
1169            $this->initialise_default_pagetype($shorturl);
1170        }
1171        if (!is_null($this->_legacypageobject)) {
1172            $this->_legacypageobject->set_url($url, $params);
1173        }
1174    }
1175
1176    /**
1177     * Make sure page URL does not contain the given URL parameter.
1178     *
1179     * This should not be necessary if the script has called set_url properly.
1180     * However, in some situations like the block editing actions; when the URL
1181     * has been guessed, it will contain dangerous block-related actions.
1182     * Therefore, the blocks code calls this function to clean up such parameters
1183     * before doing any redirect.
1184     *
1185     * @param string $param the name of the parameter to make sure is not in the
1186     * page URL.
1187     */
1188    public function ensure_param_not_in_url($param) {
1189        $discard = $this->url; // Make sure $this->url is lazy-loaded;
1190        $this->_url->remove_params($param);
1191    }
1192
1193    /**
1194     * There can be alternate versions of some pages (for example an RSS feed version).
1195     * If such other version exist, call this method, and a link to the alternate
1196     * version will be included in the <head> of the page.
1197     *
1198     * @param string $title The title to give the alternate version.
1199     * @param string|moodle_url $url The URL of the alternate version.
1200     * @param string $mimetype The mime-type of the alternate version.
1201     */
1202    public function add_alternate_version($title, $url, $mimetype) {
1203        if ($this->_state > self::STATE_BEFORE_HEADER) {
1204            throw new coding_exception('Cannot call moodle_page::add_alternate_version after output has been started.');
1205        }
1206        $alt = new stdClass;
1207        $alt->title = $title;
1208        $alt->url = $url;
1209        $this->_alternateversions[$mimetype] = $alt;
1210    }
1211
1212    /**
1213     * Specify a form control should be focused when the page has loaded.
1214     *
1215     * @param string $controlid the id of the HTML element to be focused.
1216     */
1217    public function set_focuscontrol($controlid) {
1218        $this->_focuscontrol = $controlid;
1219    }
1220
1221    /**
1222     * Specify a fragment of HTML that goes where the 'Turn editing on' button normally goes.
1223     *
1224     * @param string $html the HTML to display there.
1225     */
1226    public function set_button($html) {
1227        $this->_button = $html;
1228    }
1229
1230    /**
1231     * Set the capability that allows users to edit blocks on this page.
1232     *
1233     * Normally the default of 'moodle/site:manageblocks' is used, but a few
1234     * pages like the My Moodle page need to use a different capability
1235     * like 'moodle/my:manageblocks'.
1236     *
1237     * @param string $capability a capability.
1238     */
1239    public function set_blocks_editing_capability($capability) {
1240        $this->_blockseditingcap = $capability;
1241    }
1242
1243    /**
1244     * Some pages let you turn editing on for reasons other than editing blocks.
1245     * If that is the case, you can pass other capabilities that let the user
1246     * edit this page here.
1247     *
1248     * @param string|array $capability either a capability, or an array of capabilities.
1249     */
1250    public function set_other_editing_capability($capability) {
1251        if (is_array($capability)) {
1252            $this->_othereditingcaps = array_unique($this->_othereditingcaps + $capability);
1253        } else {
1254            $this->_othereditingcaps[] = $capability;
1255        }
1256    }
1257
1258    /**
1259     * Sets whether the browser should cache this page or not.
1260     *
1261     * @return bool $cacheable can this page be cached by the user's browser.
1262     */
1263    public function set_cacheable($cacheable) {
1264        $this->_cacheable = $cacheable;
1265    }
1266
1267    /**
1268     * Sets the page to periodically refresh
1269     *
1270     * This function must be called before $OUTPUT->header has been called or
1271     * a coding exception will be thrown.
1272     *
1273     * @param int $delay Sets the delay before refreshing the page, if set to null
1274     *     refresh is cancelled
1275     */
1276    public function set_periodic_refresh_delay($delay=null) {
1277        if ($this->_state > self::STATE_BEFORE_HEADER) {
1278            throw new coding_exception('You cannot set a periodic refresh delay after the header has been printed');
1279        }
1280        if ($delay===null) {
1281            $this->_periodicrefreshdelay = null;
1282        } else if (is_int($delay)) {
1283            $this->_periodicrefreshdelay = $delay;
1284        }
1285    }
1286
1287    /**
1288     * Force this page to use a particular theme.
1289     *
1290     * Please use this cautiously.
1291     * It is only intended to be used by the themes selector admin page.
1292     *
1293     * @param string $themename the name of the theme to use.
1294     */
1295    public function force_theme($themename) {
1296        $this->ensure_theme_not_set();
1297        $this->_theme = theme_config::load($themename);
1298    }
1299
1300    /**
1301     * This function indicates that current page requires the https
1302     * when $CFG->loginhttps enabled.
1303     *
1304     * By using this function properly, we can ensure 100% https-ized pages
1305     * at our entire discretion (login, forgot_password, change_password)
1306     * @return void
1307     */
1308    public function https_required() {
1309        global $CFG;
1310
1311        if (!is_null($this->_url)) {
1312            throw new coding_exception('https_required() must be used before setting page url!');
1313        }
1314
1315        $this->ensure_theme_not_set();
1316
1317        $this->_https_login_required = true;
1318
1319        if (!empty($CFG->loginhttps)) {
1320            $CFG->httpswwwroot = str_replace('http:', 'https:', $CFG->wwwroot);
1321        } else {
1322            $CFG->httpswwwroot = $CFG->wwwroot;
1323        }
1324    }
1325
1326    /**
1327     * Makes sure that page previously marked with https_required()
1328     * is really using https://, if not it redirects to https://
1329     *
1330     * @return void (may redirect to https://self)
1331     */
1332    public function verify_https_required() {
1333        global $CFG, $FULLME;
1334
1335        if (is_null($this->_url)) {
1336            throw new coding_exception('verify_https_required() must be called after setting page url!');
1337        }
1338
1339        if (!$this->_https_login_required) {
1340            throw new coding_exception('verify_https_required() must be called only after https_required()!');
1341        }
1342
1343        if (empty($CFG->loginhttps)) {
1344            // https not required, so stop checking
1345            return;
1346        }
1347
1348        if (strpos($this->_url, 'https://')) {
1349            // detect if incorrect PAGE->set_url() used, it is recommended to use root-relative paths there
1350            throw new coding_exception('Invalid page url specified, it must start with https:// for pages that set https_required()!');
1351        }
1352
1353        if (!empty($CFG->sslproxy)) {
1354            // it does not make much sense to use sslproxy and loginhttps at the same time
1355            return;
1356        }
1357
1358        // now the real test and redirect!
1359        // NOTE: do NOT use this test for detection of https on current page because this code is not compatible with SSL proxies,
1360        //       instead use strpos($CFG->httpswwwroot, 'https:') === 0
1361        if (strpos($FULLME, 'https:') !== 0) {
1362            // this may lead to infinite redirect on misconfigured sites, in that case use $CFG->loginhttps=0; in /config.php
1363            redirect($this->_url);
1364        }
1365    }
1366
1367    // Initialisation methods =====================================================
1368    // These set various things up in a default way.
1369
1370    /**
1371     * This method is called when the page first moves out of the STATE_BEFORE_HEADER
1372     * state. This is our last change to initialise things.
1373     */
1374    protected function starting_output() {
1375        global $CFG;
1376
1377        if (!during_initial_install()) {
1378            $this->blocks->load_blocks();
1379            if (empty($this->_block_actions_done)) {
1380                $this->_block_actions_done = true;
1381                if ($this->blocks->process_url_actions($this)) {
1382                    redirect($this->url->out(false));
1383                }
1384            }
1385            $this->blocks->create_all_block_instances();
1386        }
1387
1388        // If maintenance mode is on, change the page header.
1389        if (!empty($CFG->maintenance_enabled)) {
1390            $this->set_button('<a href="' . $CFG->wwwroot . '/' . $CFG->admin .
1391                    '/settings.php?section=maintenancemode">' . get_string('maintenancemode', 'admin') .
1392                    '</a> ' . $this->button);
1393
1394            $title = $this->title;
1395            if ($title) {
1396                $title .= ' - ';
1397            }
1398            $this->set_title($title . get_string('maintenancemode', 'admin'));
1399        } else {
1400            // Show the messaging popup if there are messages
1401            message_popup_window();
1402        }
1403
1404        $this->initialise_standard_body_classes();
1405    }
1406
1407    /**
1408     * Method for use by Moodle core to set up the theme. Do not
1409     * use this in your own code.
1410     *
1411     * Make sure the right theme for this page is loaded. Tell our
1412     * blocks_manager about the theme block regions, and then, if
1413     * we are $PAGE, set up the global $OUTPUT.
1414     *
1415     * @return void
1416     */
1417    public function initialise_theme_and_output() {
1418        global $OUTPUT, $PAGE, $SITE;
1419
1420        if (!empty($this->_wherethemewasinitialised)) {
1421            return;
1422        }
1423
1424        if (!during_initial_install()) {
1425            // detect PAGE->context mess
1426            $this->magic_get_context();
1427        }
1428
1429        if (!$this->_course && !during_initial_install()) {
1430            $this->set_course($SITE);
1431        }
1432
1433        if (is_null($this->_theme)) {
1434            $themename = $this->resolve_theme();
1435            $this->_theme = theme_config::load($themename);
1436            $this->_layout_options = $this->_theme->pagelayout_options($this->pagelayout);
1437        }
1438
1439        $this->_theme->setup_blocks($this->pagelayout, $this->blocks);
1440
1441        if ($this === $PAGE) {
1442            $OUTPUT = $this->get_renderer('core');
1443        }
1444
1445        $this->_wherethemewasinitialised = debug_backtrace();
1446    }
1447
1448    /**
1449     * Work out the theme this page should use.
1450     *
1451     * This depends on numerous $CFG settings, and the properties of this page.
1452     *
1453     * @return string the name of the theme that should be used on this page.
1454     */
1455    protected function resolve_theme() {
1456        global $CFG, $USER, $SESSION;
1457
1458        if (empty($CFG->themeorder)) {
1459            $themeorder = array('course', 'category', 'session', 'user', 'site');
1460        } else {
1461            $themeorder = $CFG->themeorder;
1462            // Just in case, make sure we always use the site theme if nothing else matched.
1463            $themeorder[] = 'site';
1464        }
1465
1466        $mnetpeertheme = '';
1467        if (isloggedin() and isset($CFG->mnet_localhost_id) and $USER->mnethostid != $CFG->mnet_localhost_id) {
1468            require_once($CFG->dirroot.'/mnet/peer.php');
1469            $mnetpeer = new mnet_peer();
1470            $mnetpeer->set_id($USER->mnethostid);
1471            if ($mnetpeer->force_theme == 1 && $mnetpeer->theme != '') {
1472                $mnetpeertheme = $mnetpeer->theme;
1473            }
1474        }
1475
1476        foreach ($themeorder as $themetype) {
1477            switch ($themetype) {
1478                case 'course':
1479                    if (!empty($CFG->allowcoursethemes) && !empty($this->_course->theme) && $this->devicetypeinuse == 'default') {
1480                        return $this->_course->theme;
1481                    }
1482                break;
1483
1484                case 'category':
1485                    if (!empty($CFG->allowcategorythemes) && $this->devicetypeinuse == 'default') {
1486                        $categories = $this->categories;
1487                        foreach ($categories as $category) {
1488                            if (!empty($category->theme)) {
1489                                return $category->theme;
1490                            }
1491                        }
1492                    }
1493                break;
1494
1495                case 'session':
1496                    if (!empty($SESSION->theme)) {
1497                        return $SESSION->theme;
1498                    }
1499                break;
1500
1501                case 'user':
1502                    if (!empty($CFG->allowuserthemes) && !empty($USER->theme) && $this->devicetypeinuse == 'default') {
1503                        if ($mnetpeertheme) {
1504                            return $mnetpeertheme;
1505                        } else {
1506                            return $USER->theme;
1507                        }
1508                    }
1509                break;
1510
1511                case 'site':
1512                    if ($mnetpeertheme) {
1513                        return $mnetpeertheme;
1514                    }
1515                    // First try for the device the user is using.
1516                    $devicetheme = get_selected_theme_for_device_type($this->devicetypeinuse);
1517                    if (!empty($devicetheme)) {
1518                        return $devicetheme;
1519                    }
1520                    // Next try for the default device (as a fallback)
1521                    $devicetheme = get_selected_theme_for_device_type('default');
1522                    if (!empty($devicetheme)) {
1523                        return $devicetheme;
1524                    }
1525                    // The default device theme isn't set up - use the overall default theme.
1526                    return theme_config::DEFAULT_THEME;
1527            }
1528        }
1529    }
1530
1531
1532    /**
1533     * Sets ->pagetype from the script name. For example, if the script that was
1534     * run is mod/quiz/view.php, ->pagetype will be set to 'mod-quiz-view'.
1535     *
1536     * @param string $script the path to the script that should be used to
1537     * initialise ->pagetype. If not passed the $SCRIPT global will be used.
1538     * If legacy code has set $CFG->pagepath that will be used instead, and a
1539     * developer warning issued.
1540     */
1541    protected function initialise_default_pagetype($script = null) {
1542        global $CFG, $SCRIPT;
1543
1544        if (isset($CFG->pagepath)) {
1545            debugging('Some code appears to have set $CFG->pagepath. That was a horrible deprecated thing. ' .
1546                    'Don\'t do it! Try calling $PAGE->set_pagetype() instead.');
1547            $script = $CFG->pagepath;
1548            unset($CFG->pagepath);
1549        }
1550
1551        if (is_null($script)) {
1552            $script = ltrim($SCRIPT, '/');
1553            $len = strlen($CFG->admin);
1554            if (substr($script, 0, $len) == $CFG->admin) {
1555                $script = 'admin' . substr($script, $len);
1556            }
1557        }
1558
1559        $path = str_replace('.php', '', $script);
1560        if (substr($path, -1) == '/') {
1561            $path .= 'index';
1562        }
1563
1564        if (empty($path) || $path == 'index') {
1565            $this->_pagetype = 'site-index';
1566        } else {
1567            $this->_pagetype = str_replace('/', '-', $path);
1568        }
1569    }
1570
1571    /**
1572     * Initialises the CSS classes that will be added to body tag of the page.
1573     *
1574     * The function is responsible for adding all of the critical CSS classes
1575     * that describe the current page, and its state.
1576     * This includes classes that describe the following for example:
1577     *    - Current language
1578     *    - Language direction
1579     *    - YUI CSS initialisation
1580     *    - Pagelayout
1581     * These are commonly used in CSS to target specific types of pages.
1582     */
1583    protected function initialise_standard_body_classes() {
1584        global $CFG, $USER;
1585
1586        $pagetype = $this->pagetype;
1587        if ($pagetype == 'site-index') {
1588            $this->_legacyclass = 'course';
1589        } else if (substr($pagetype, 0, 6) == 'admin-') {
1590            $this->_legacyclass = 'admin';
1591        }
1592        $this->add_body_class($this->_legacyclass);
1593
1594        $pathbits = explode('-', trim($pagetype));
1595        for ($i=1;$i<count($pathbits);$i++) {
1596            $this->add_body_class('path-'.join('-',array_slice($pathbits, 0, $i)));
1597        }
1598
1599        $this->add_body_classes(get_browser_version_classes());
1600        $this->add_body_class('dir-' . get_string('thisdirection', 'langconfig'));
1601        $this->add_body_class('lang-' . current_language());
1602        $this->add_body_class('yui-skin-sam'); // Make YUI happy, if it is used.
1603        $this->add_body_class('yui3-skin-sam'); // Make YUI3 happy, if it is used.
1604        $this->add_body_class($this->url_to_class_name($CFG->wwwroot));
1605
1606        $this->add_body_class('pagelayout-' . $this->_pagelayout); // extra class describing current page layout
1607
1608        if (!during_initial_install()) {
1609            $this->add_body_class('course-' . $this->_course->id);
1610            $this->add_body_class('context-' . $this->_context->id);
1611        }
1612
1613        if (!empty($this->_cm)) {
1614            $this->add_body_class('cmid-' . $this->_cm->id);
1615        }
1616
1617        if (!empty($CFG->allowcategorythemes)) {
1618            $this->ensure_category_loaded();
1619            foreach ($this->_categories as $catid => $notused) {
1620                $this->add_body_class('category-' . $catid);
1621            }
1622        } else {
1623            $catid = 0;
1624            if (is_array($this->_categories)) {
1625                $catids = array_keys($this->_categories);
1626                $catid = reset($catids);
1627            } else if (!empty($this->_course->category)) {
1628                $catid = $this->_course->category;
1629            }
1630            if ($catid) {
1631                $this->add_body_class('category-' . $catid);
1632            }
1633        }
1634
1635        if (!isloggedin()) {
1636            $this->add_body_class('notloggedin');
1637        }
1638
1639        if (!empty($USER->editing)) {
1640            $this->add_body_class('editing');
1641            if (optional_param('bui_moveid', false, PARAM_INT)) {
1642               $this->add_body_class('blocks-moving');
1643        }
1644        }
1645
1646        if (!empty($CFG->blocksdrag)) {
1647            $this->add_body_class('drag');
1648        }
1649
1650        if ($this->_devicetypeinuse != 'default') {
1651            $this->add_body_class($this->_devicetypeinuse . 'theme');
1652        }
1653    }
1654
1655    /**
1656     * Loads the activity record for the current CM object associated with this
1657     * page.
1658     *
1659     * This will load {@link moodle_page::$_module} with a row from the related
1660     * module table in the database.
1661     * For instance if {@link moodle_page::$_cm} is a forum then a row from the
1662     * forum table will be loaded.
1663     */
1664    protected function load_activity_record() {
1665        global $DB;
1666        if (is_null($this->_cm)) {
1667            return;
1668        }
1669        $this->_module = $DB->get_record($this->_cm->modname, array('id' => $this->_cm->instance));
1670    }
1671
1672    /**
1673     * This function ensures that the category of the current course has been
1674     * loaded, and if not, the function loads it now.
1675     *
1676     * @return void
1677     * @throws coding_exception
1678     */
1679    protected function ensure_category_loaded() {
1680        if (is_array($this->_categories)) {
1681            return; // Already done.
1682        }
1683        if (is_null($this->_course)) {
1684            throw new coding_exception('Attempt to get the course category for this page before the course was set.');
1685        }
1686        if ($this->_course->category == 0) {
1687            $this->_categories = array();
1688        } else {
1689            $this->load_category($this->_course->category);
1690        }
1691    }
1692
1693    /**
1694     * Loads the requested category into the pages categories array.
1695     *
1696     * @param ing $categoryid
1697     * @throws moodle_exception
1698     */
1699    protected function load_category($categoryid) {
1700        global $DB;
1701        $category = $DB->get_record('course_categories', array('id' => $categoryid));
1702        if (!$category) {
1703            throw new moodle_exception('unknowncategory');
1704        }
1705        $this->_categories[$category->id] = $category;
1706        $parentcategoryids = explode('/', trim($category->path, '/'));
1707        array_pop($parentcategoryids);
1708        foreach (array_reverse($parentcategoryids) as $catid) {
1709            $this->_categories[$catid] = null;
1710        }
1711    }
1712
1713    /**
1714     * Ensures that the category the current course is within, as well as all of
1715     * its parent categories, have been loaded.
1716     *
1717     * @return void
1718     */
1719    protected function ensure_categories_loaded() {
1720        global $DB;
1721        $this->ensure_category_loaded();
1722        if (!is_null(end($this->_categories))) {
1723            return; // Already done.
1724        }
1725        $idstoload = array_keys($this->_categories);
1726        array_shift($idstoload);
1727        $categories = $DB->get_records_list('course_categories', 'id', $idstoload);
1728        foreach ($idstoload as $catid) {
1729            $this->_categories[$catid] = $categories[$catid];
1730        }
1731    }
1732
1733    /**
1734     * Ensure the theme has not been loaded yet. If it has an exception is thrown.
1735     * @source
1736     *
1737     * @throws coding_exception
1738     */
1739    protected function ensure_theme_not_set() {
1740        if (!is_null($this->_theme)) {
1741            throw new coding_exception('The theme has already been set up for this page ready for output. ' .
1742                    'Therefore, you can no longer change the theme, or anything that might affect what ' .
1743                    'the current theme is, for example, the course.',
1744                    'Stack trace when the theme was set up: ' . format_backtrace($this->_wherethemewasinitialised));
1745        }
1746    }
1747
1748    /**
1749     * Converts the provided URL into a CSS class that be used within the page.
1750     * This is primarily used to add the wwwroot to the body tag as a CSS class.
1751     *
1752     * @param string $url
1753     * @return string
1754     */
1755    protected function url_to_class_name($url) {
1756        $bits = parse_url($url);
1757        $class = str_replace('.', '-', $bits['host']);
1758        if (!empty($bits['port'])) {
1759            $class .= '--' . $bits['port'];
1760        }
1761        if (!empty($bits['path'])) {
1762            $path = trim($bits['path'], '/');
1763            if ($path) {
1764                $class .= '--' . str_replace('/', '-', $path);
1765            }
1766        }
1767        return $class;
1768    }
1769
1770    /**
1771     * Combines all of the required editing caps for the page and returns them
1772     * as an array.
1773     *
1774     * @return array
1775     */
1776    protected function all_editing_caps() {
1777        $caps = $this->_othereditingcaps;
1778        $caps[] = $this->_blockseditingcap;
1779        return $caps;
1780    }
1781
1782    // Deprecated fields and methods for backwards compatibility ==================
1783
1784    /**
1785     * Returns the page type.
1786     *
1787     * @deprecated since Moodle 2.0 - use $PAGE->pagetype instead.
1788     * @return string page type.
1789     */
1790    public function get_type() {
1791        debugging('Call to deprecated method moodle_page::get_type. Please use $PAGE->pagetype instead.');
1792        return $this->get_pagetype();
1793    }
1794
1795    /**
1796     * Returns the page type.
1797     *
1798     * @deprecated since Moodle 2.0 - use $PAGE->pagetype instead.
1799     * @return string this is what page_id_and_class used to return via the $getclass parameter.
1800     */
1801    public function get_format_name() {
1802        return $this->get_pagetype();
1803    }
1804
1805    /**
1806     * Returns the course associated with this page.
1807     *
1808     * @deprecated since Moodle 2.0 - use $PAGE->course instead.
1809     * @return stdClass course.
1810     */
1811    public function get_courserecord() {
1812        debugging('Call to deprecated method moodle_page::get_courserecord. Please use $PAGE->course instead.');
1813        return $this->get_course();
1814    }
1815
1816    /**
1817     * Returns the legacy page class.
1818     *
1819     * @deprecated since Moodle 2.0
1820     * @return string this is what page_id_and_class used to return via the $getclass parameter.
1821     */
1822    public function get_legacyclass() {
1823        if (is_null($this->_legacyclass)) {
1824            $this->initialise_standard_body_classes();
1825        }
1826        debugging('Call to deprecated method moodle_page::get_legacyclass.');
1827        return $this->_legacyclass;
1828    }
1829
1830    /**
1831     * Returns an array of block regions on this page.
1832     *
1833     * @deprecated since Moodle 2.0 - use $PAGE->blocks->get_regions() instead
1834     * @return array the places on this page where blocks can go.
1835     */
1836    function blocks_get_positions() {
1837        debugging('Call to deprecated method moodle_page::blocks_get_positions. Use $PAGE->blocks->get_regions() instead.');
1838        return $this->blocks->get_regions();
1839    }
1840
1841    /**
1842     * Returns the default block region.
1843     *
1844     * @deprecated since Moodle 2.0 - use $PAGE->blocks->get_default_region() instead
1845     * @return string the default place for blocks on this page.
1846     */
1847    function blocks_default_position() {
1848        debugging('Call to deprecated method moodle_page::blocks_default_position. Use $PAGE->blocks->get_default_region() instead.');
1849        return $this->blocks->get_default_region();
1850    }
1851
1852    /**
1853     * Returns the default block to use of the page.
1854     * This function no longer does anything. DO NOT USE.
1855     *
1856     * @deprecated since Moodle 2.0 - no longer used.
1857     */
1858    function blocks_get_default() {
1859        debugging('Call to deprecated method moodle_page::blocks_get_default. This method has no function any more.');
1860    }
1861
1862    /**
1863     * Moves a block.
1864     * This function no longer does anything. DO NOT USE.
1865     *
1866     * @deprecated since Moodle 2.0 - no longer used.
1867     */
1868    function blocks_move_position(&$instance, $move) {
1869        debugging('Call to deprecated method moodle_page::blocks_move_position. This method has no function any more.');
1870    }
1871
1872    /**
1873     * Returns the URL parameters for the current page.
1874     *
1875     * @deprecated since Moodle 2.0 - use $this->url->params() instead.
1876     * @return array URL parameters for this page.
1877     */
1878    function url_get_parameters() {
1879        debugging('Call to deprecated method moodle_page::url_get_parameters. Use $this->url->params() instead.');
1880        return $this->url->params();
1881    }
1882
1883    /**
1884     * Returns the URL path of the current page.
1885     *
1886     * @deprecated since Moodle 2.0 - use $this->url->params() instead.
1887     * @return string URL for this page without parameters.
1888     */
1889    function url_get_path() {
1890        debugging('Call to deprecated method moodle_page::url_get_path. Use $this->url->out() instead.');
1891        return $this->url->out();
1892    }
1893
1894    /**
1895     * Returns the full URL for this page.
1896     *
1897     * @deprecated since Moodle 2.0 - use $this->url->out() instead.
1898     * @return string full URL for this page.
1899     */
1900    function url_get_full($extraparams = array()) {
1901        debugging('Call to deprecated method moodle_page::url_get_full. Use $this->url->out() instead.');
1902        return $this->url->out(true, $extraparams);
1903    }
1904
1905    /**
1906     * Returns the legacy page object.
1907     *
1908     * @deprecated since Moodle 2.0 - just a backwards compatibility hook.
1909     * @return moodle_page
1910     */
1911    function set_legacy_page_object($pageobject) {
1912        return $this->_legacypageobject = $pageobject;
1913    }
1914
1915    /**
1916     * Prints a header... DO NOT USE!
1917     *
1918     * @deprecated since Moodle 2.0 - page objects should no longer be doing print_header.
1919     * @param mixed $_ ...
1920     */
1921    function print_header($_) {
1922        if (is_null($this->_legacypageobject)) {
1923            throw new coding_exception('You have called print_header on $PAGE when there is not a legacy page class present.');
1924        }
1925        debugging('You should not longer be doing print_header via a page class.', DEBUG_DEVELOPER);
1926        $args = func_get_args();
1927        call_user_func_array(array($this->_legacypageobject, 'print_header'), $args);
1928    }
1929
1930    /**
1931     * Returns the ID for this page. DO NOT USE!
1932     *
1933     * @deprecated since Moodle 2.0
1934     * @return the 'page id'. This concept no longer exists.
1935     */
1936    function get_id() {
1937        debugging('Call to deprecated method moodle_page::get_id(). It should not be necessary any more.', DEBUG_DEVELOPER);
1938        if (!is_null($this->_legacypageobject)) {
1939            return $this->_legacypageobject->get_id();
1940        }
1941        return 0;
1942    }
1943
1944    /**
1945     * Returns the ID for this page. DO NOT USE!
1946     *
1947     * @deprecated since Moodle 2.0
1948     * @return the 'page id'. This concept no longer exists.
1949     */
1950    function get_pageid() {
1951        debugging('Call to deprecated method moodle_page::get_pageid(). It should not be necessary any more.', DEBUG_DEVELOPER);
1952        if (!is_null($this->_legacypageobject)) {
1953            return $this->_legacypageobject->get_id();
1954        }
1955        return 0;
1956    }
1957
1958    /**
1959     * Returns the module record for this page.
1960     *
1961     * @deprecated since Moodle 2.0 - user $PAGE->cm instead.
1962     * @return $this->cm;
1963     */
1964    function get_modulerecord() {
1965        return $this->cm;
1966    }
1967
1968    /**
1969     * Returns true if the page URL has beem set.
1970     *
1971     * @return bool
1972     */
1973    public function has_set_url() {
1974        return ($this->_url!==null);
1975    }
1976
1977    /**
1978     * Gets set when the block actions for the page have been processed.
1979     *
1980     * @param bool $setting
1981     */
1982    public function set_block_actions_done($setting = true) {
1983        $this->_block_actions_done = $setting;
1984    }
1985
1986    /**
1987     * Are popup notifications allowed on this page?
1988     * Popup notifications may be disallowed in situations such as while upgrading or completing a quiz
1989     *
1990     * @return bool true if popup notifications may be displayed
1991     */
1992    public function get_popup_notification_allowed() {
1993        return $this->_popup_notification_allowed;
1994    }
1995
1996    /**
1997     * Allow or disallow popup notifications on this page. Popups are allowed by default.
1998     *
1999     * @param bool $allowed true if notifications are allowed. False if not allowed. They are allowed by default.
2000     */
2001    public function set_popup_notification_allowed($allowed) {
2002        $this->_popup_notification_allowed = $allowed;
2003    }
2004}
2005
2006/**
2007 * Not needed any more. DO NOT USE!
2008 *
2009 * @deprecated since Moodle 2.0
2010 * @param string $path the folder path
2011 * @return array an array of page types.
2012 */
2013function page_import_types($path) {
2014    global $CFG;
2015    debugging('Call to deprecated function page_import_types.', DEBUG_DEVELOPER);
2016}
2017
2018/**
2019 * Do not use this any more. The global $PAGE is automatically created for you.
2020 * If you need custom behaviour, you should just set properties of that object.
2021 *
2022 * @deprecated since Moodle 2.0
2023 * @param integer $instance legacy page instance id.
2024 * @return moodle_page The global $PAGE object.
2025 */
2026function page_create_instance($instance) {
2027    global $PAGE;
2028    return page_create_object($PAGE->pagetype, $instance);
2029}
2030
2031/**
2032 * Do not use this any more. The global $PAGE is automatically created for you.
2033 * If you need custom behaviour, you should just set properties of that object.
2034 *
2035 * @deprecated since Moodle 2.0
2036 * @return moodle_page The global $PAGE object.
2037 */
2038function page_create_object($type, $id = NULL) {
2039    global $CFG, $PAGE, $SITE, $ME;
2040    debugging('Call to deprecated function page_create_object.', DEBUG_DEVELOPER);
2041
2042    $data = new stdClass;
2043    $data->pagetype = $type;
2044    $data->pageid = $id;
2045
2046    $classname = page_map_class($type);
2047    if (!$classname) {
2048        return $PAGE;
2049    }
2050    $legacypage = new $classname;
2051    $legacypage->init_quick($data);
2052
2053    $course = $PAGE->course;
2054    if ($course->id != $SITE->id) {
2055        $legacypage->set_course($course);
2056    } else {
2057        try {
2058            $category = $PAGE->category;
2059        } catch (coding_exception $e) {
2060            // Was not set before, so no need to try to set it again.
2061            $category = false;
2062        }
2063        if ($category) {
2064            $legacypage->set_category_by_id($category->id);
2065        } else {
2066            $legacypage->set_course($SITE);
2067        }
2068    }
2069
2070    $legacypage->set_pagetype($type);
2071
2072    $legacypage->set_url($ME);
2073    $PAGE->set_url(str_replace($CFG->wwwroot . '/', '', $legacypage->url_get_full()));
2074
2075    $PAGE->set_pagetype($type);
2076    $PAGE->set_legacy_page_object($legacypage);
2077    return $PAGE;
2078}
2079
2080/**
2081 * You should not be writing page subclasses any more. Just set properties on the
2082 * global $PAGE object to control its behaviour.
2083 *
2084 * @deprecated since Moodle 2.0
2085 * @return mixed Null if there is not a valid page mapping, or the mapping if
2086 *     it has been set.
2087 */
2088function page_map_class($type, $classname = NULL) {
2089    global $CFG;
2090
2091    static $mappings = array(
2092        PAGE_COURSE_VIEW => 'page_course',
2093    );
2094
2095    if (!empty($type) && !empty($classname)) {
2096        $mappings[$type] = $classname;
2097    }
2098
2099    if (!isset($mappings[$type])) {
2100        debugging('Page class mapping requested for unknown type: '.$type);
2101        return null;
2102    } else if (empty($classname) && !class_exists($mappings[$type])) {
2103        debugging('Page class mapping for id "'.$type.'" exists but class "'.$mappings[$type].'" is not defined');
2104        return null;
2105    }
2106
2107    return $mappings[$type];
2108}
2109
2110/**
2111 * Parent class from which all Moodle page classes derive
2112 *
2113 * @deprecated since Moodle 2.0
2114 * @package core
2115 * @category page
2116 * @copyright  1999 onwards Martin Dougiamas  {@link http://moodle.com}
2117 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2118 */
2119class page_base extends moodle_page {
2120    /**
2121     * @var int The numeric identifier of the page being described.
2122     */
2123    public $id = null;
2124
2125    /**
2126     * Returns the page id
2127     * @deprecated since Moodle 2.0
2128     * @return int Returns the id of the page.
2129     */
2130    public function get_id() {
2131        return $this->id;
2132    }
2133
2134    /**
2135     * Initialize the data members of the parent class
2136     * @param scalar $data
2137     */
2138    public function init_quick($data) {
2139        $this->id   = $data->pageid;
2140    }
2141
2142    /**
2143     * DOES NOTHING... DO NOT USE.
2144     * @deprecated since Moodle 2.0
2145     */
2146    public function init_full() {}
2147}
2148
2149/**
2150 * Class that models the behavior of a moodle course.
2151 * Although this does nothing, this class declaration should be left for now
2152 * since there may be legacy class doing class page_... extends page_course
2153 *
2154 * @deprecated since Moodle 2.0
2155 * @package core
2156 * @category page
2157 * @copyright  1999 onwards Martin Dougiamas  {@link http://moodle.com}
2158 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2159 */
2160class page_course extends page_base {}
2161
2162/**
2163 * Class that models the common parts of all activity modules
2164 *
2165 * @deprecated since Moodle 2.0
2166 * @package core
2167 * @category page
2168 * @copyright  1999 onwards Martin Dougiamas  {@link http://moodle.com}
2169 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2170 */
2171class page_generic_activity extends page_base {
2172
2173    /**
2174     * Although this function is deprecated, it should be left here because
2175     * people upgrading legacy code need to copy it. See
2176     * http://docs.moodle.org/dev/Migrating_your_code_to_the_2.0_rendering_API
2177     *
2178     * @param string $title
2179     * @param array $morenavlinks
2180     * @param string $bodytags
2181     * @param string $meta
2182     */
2183    function print_header($title, $morenavlinks = NULL, $bodytags = '', $meta = '') {
2184        global $USER, $CFG, $PAGE, $OUTPUT;
2185
2186        $this->init_full();
2187        $replacements = array(
2188            '%fullname%' => format_string($this->activityrecord->name)
2189        );
2190        foreach ($replacements as $search => $replace) {
2191            $title = str_replace($search, $replace, $title);
2192        }
2193
2194        $buttons = '<table><tr><td>'.$OUTPUT->update_module_button($this->modulerecord->id, $this->activityname).'</td>';
2195        if ($this->user_allowed_editing()) {
2196            $buttons .= '<td><form method="get" action="view.php"><div>'.
2197                '<input type="hidden" name="id" value="'.$this->modulerecord->id.'" />'.
2198                '<input type="hidden" name="edit" value="'.($this->user_is_editing()?'off':'on').'" />'.
2199                '<input type="submit" value="'.get_string($this->user_is_editing()?'blockseditoff':'blocksediton').'" /></div></form></td>';
2200        }
2201        $buttons .= '</tr></table>';
2202
2203        if (!empty($morenavlinks) && is_array($morenavlinks)) {
2204            foreach ($morenavlinks as $navitem) {
2205                if (is_array($navitem) && array_key_exists('name', $navitem)) {
2206                    $link = null;
2207                    if (array_key_exists('link', $navitem)) {
2208                        $link = $navitem['link'];
2209                    }
2210                    $PAGE->navbar->add($navitem['name'], $link);
2211                }
2212            }
2213        }
2214
2215        $PAGE->set_title($title);
2216        $PAGE->set_heading($this->course->fullname);
2217        $PAGE->set_button($buttons);
2218        echo $OUTPUT->header();
2219    }
2220}