/** * Test the way in which notifications are added to the session in different stages of the page load. */ public function test_add_during_output_stages() { global $PAGE, $SESSION; \core\notification::add('Example before header', \core\notification::INFO); $this->assertCount(1, $SESSION->notifications); $PAGE->set_state(\moodle_page::STATE_PRINTING_HEADER); \core\notification::add('Example during header', \core\notification::INFO); $this->assertCount(2, $SESSION->notifications); $PAGE->set_state(\moodle_page::STATE_IN_BODY); \core\notification::add('Example in body', \core\notification::INFO); $this->expectOutputRegex('/Example in body/'); $this->assertCount(2, $SESSION->notifications); $PAGE->set_state(\moodle_page::STATE_DONE); \core\notification::add('Example after page', \core\notification::INFO); $this->assertCount(3, $SESSION->notifications); }
/** * Prints the page headers, breadcrumb trail, page heading, (optional) dropdown navigation menu and * (optional) navigation tabs for any gradebook page. All gradebook pages MUST use these functions * in favour of the usual print_header(), print_header_simple(), print_heading() etc. * !IMPORTANT! Use of tabs.php file in gradebook pages is forbidden unless tabs are switched off at * the site level for the gradebook ($CFG->grade_navmethod = GRADE_NAVMETHOD_DROPDOWN). * * @param int $courseid Course id * @param string $active_type The type of the current page (report, settings, * import, export, scales, outcomes, letters) * @param string $active_plugin The plugin of the current page (grader, fullview etc...) * @param string $heading The heading of the page. Tries to guess if none is given * @param boolean $return Whether to return (true) or echo (false) the HTML generated by this function * @param string $bodytags Additional attributes that will be added to the <body> tag * @param string $buttons Additional buttons to display on the page * @param boolean $shownavigation should the gradebook navigation drop down (or tabs) be shown? * @param string $headerhelpidentifier The help string identifier if required. * @param string $headerhelpcomponent The component for the help string. * @param stdClass $user The user object for use with the user context header. * * @return string HTML code or nothing if $return == false */ function print_grade_page_head($courseid, $active_type, $active_plugin=null, $heading = false, $return=false, $buttons=false, $shownavigation=true, $headerhelpidentifier = null, $headerhelpcomponent = null, $user = null) { global $CFG, $OUTPUT, $PAGE; // Put a warning on all gradebook pages if the course has modules currently scheduled for background deletion. require_once($CFG->dirroot . '/course/lib.php'); if (course_modules_pending_deletion($courseid)) { \core\notification::add(get_string('gradesmoduledeletionpendingwarning', 'grades'), \core\output\notification::NOTIFY_WARNING); } if ($active_type === 'preferences') { // In Moodle 2.8 report preferences were moved under 'settings'. Allow backward compatibility for 3rd party grade reports. $active_type = 'settings'; } $plugin_info = grade_get_plugin_info($courseid, $active_type, $active_plugin); // Determine the string of the active plugin $stractive_plugin = ($active_plugin) ? $plugin_info['strings']['active_plugin_str'] : $heading; $stractive_type = $plugin_info['strings'][$active_type]; if (empty($plugin_info[$active_type]->id) || !empty($plugin_info[$active_type]->parent)) { $title = $PAGE->course->fullname.': ' . $stractive_type . ': ' . $stractive_plugin; } else { $title = $PAGE->course->fullname.': ' . $stractive_plugin; } if ($active_type == 'report') { $PAGE->set_pagelayout('report'); } else { $PAGE->set_pagelayout('admin'); } $PAGE->set_title(get_string('grades') . ': ' . $stractive_type); $PAGE->set_heading($title); if ($buttons instanceof single_button) { $buttons = $OUTPUT->render($buttons); } $PAGE->set_button($buttons); if ($courseid != SITEID) { grade_extend_settings($plugin_info, $courseid); } // Set the current report as active in the breadcrumbs. if ($active_plugin !== null && $reportnav = $PAGE->settingsnav->find($active_plugin, navigation_node::TYPE_SETTING)) { $reportnav->make_active(); } $returnval = $OUTPUT->header(); if (!$return) { echo $returnval; } // Guess heading if not given explicitly if (!$heading) { $heading = $stractive_plugin; } if ($shownavigation) { $navselector = null; if ($courseid != SITEID && ($CFG->grade_navmethod == GRADE_NAVMETHOD_COMBO || $CFG->grade_navmethod == GRADE_NAVMETHOD_DROPDOWN)) { // It's absolutely essential that this grade plugin selector is shown after the user header. Just ask Fred. $navselector = print_grade_plugin_selector($plugin_info, $active_type, $active_plugin, true); if ($return) { $returnval .= $navselector; } else if (!isset($user)) { echo $navselector; } } $output = ''; // Add a help dialogue box if provided. if (isset($headerhelpidentifier)) { $output = $OUTPUT->heading_with_help($heading, $headerhelpidentifier, $headerhelpcomponent); } else { if (isset($user)) { $output = $OUTPUT->context_header( array( 'heading' => html_writer::link(new moodle_url('/user/view.php', array('id' => $user->id, 'course' => $courseid)), fullname($user)), 'user' => $user, 'usercontext' => context_user::instance($user->id) ), 2 ) . $navselector; } else { $output = $OUTPUT->heading($heading); } } if ($return) { $returnval .= $output; } else { echo $output; } if ($courseid != SITEID && ($CFG->grade_navmethod == GRADE_NAVMETHOD_COMBO || $CFG->grade_navmethod == GRADE_NAVMETHOD_TABS)) { $returnval .= grade_print_tabs($active_type, $active_plugin, $plugin_info, $return); } } $returnval .= print_natural_aggregation_upgrade_notice($courseid, context_course::instance($courseid), $PAGE->url, $return); if ($return) { return $returnval; } }
/** * Redirects the user to another page, after printing a notice. * * This function calls the OUTPUT redirect method, echo's the output and then dies to ensure nothing else happens. * * <strong>Good practice:</strong> You should call this method before starting page * output by using any of the OUTPUT methods. * * @param moodle_url|string $url A moodle_url to redirect to. Strings are not to be trusted! * @param string $message The message to display to the user * @param int $delay The delay before redirecting * @param string $messagetype The type of notification to show the message in. See constants on \core\output\notification. * @throws moodle_exception */ function redirect($url, $message='', $delay=null, $messagetype = \core\output\notification::NOTIFY_INFO) { global $OUTPUT, $PAGE, $CFG; if (CLI_SCRIPT or AJAX_SCRIPT) { // This is wrong - developers should not use redirect in these scripts but it should not be very likely. throw new moodle_exception('redirecterrordetected', 'error'); } if ($delay === null) { $delay = -1; } // Prevent debug errors - make sure context is properly initialised. if ($PAGE) { $PAGE->set_context(null); $PAGE->set_pagelayout('redirect'); // No header and footer needed. $PAGE->set_title(get_string('pageshouldredirect', 'moodle')); } if ($url instanceof moodle_url) { $url = $url->out(false); } $debugdisableredirect = false; do { if (defined('DEBUGGING_PRINTED')) { // Some debugging already printed, no need to look more. $debugdisableredirect = true; break; } if (core_useragent::is_msword()) { // Clicking a URL from MS Word sends a request to the server without cookies. If that // causes a redirect Word will open a browser pointing the new URL. If not, the URL that // was clicked is opened. Because the request from Word is without cookies, it almost // always results in a redirect to the login page, even if the user is logged in in their // browser. This is not what we want, so prevent the redirect for requests from Word. $debugdisableredirect = true; break; } if (empty($CFG->debugdisplay) or empty($CFG->debug)) { // No errors should be displayed. break; } if (!function_exists('error_get_last') or !$lasterror = error_get_last()) { break; } if (!($lasterror['type'] & $CFG->debug)) { // Last error not interesting. break; } // Watch out here, @hidden() errors are returned from error_get_last() too. if (headers_sent()) { // We already started printing something - that means errors likely printed. $debugdisableredirect = true; break; } if (ob_get_level() and ob_get_contents()) { // There is something waiting to be printed, hopefully it is the errors, // but it might be some error hidden by @ too - such as the timezone mess from setup.php. $debugdisableredirect = true; break; } } while (false); // Technically, HTTP/1.1 requires Location: header to contain the absolute path. // (In practice browsers accept relative paths - but still, might as well do it properly.) // This code turns relative into absolute. if (!preg_match('|^[a-z]+:|i', $url)) { // Get host name http://www.wherever.com. $hostpart = preg_replace('|^(.*?[^:/])/.*$|', '$1', $CFG->wwwroot); if (preg_match('|^/|', $url)) { // URLs beginning with / are relative to web server root so we just add them in. $url = $hostpart.$url; } else { // URLs not beginning with / are relative to path of current script, so add that on. $url = $hostpart.preg_replace('|\?.*$|', '', me()).'/../'.$url; } // Replace all ..s. while (true) { $newurl = preg_replace('|/(?!\.\.)[^/]*/\.\./|', '/', $url); if ($newurl == $url) { break; } $url = $newurl; } } // Sanitise url - we can not rely on moodle_url or our URL cleaning // because they do not support all valid external URLs. $url = preg_replace('/[\x00-\x1F\x7F]/', '', $url); $url = str_replace('"', '%22', $url); $encodedurl = preg_replace("/\&(?![a-zA-Z0-9#]{1,8};)/", "&", $url); $encodedurl = preg_replace('/^.*href="([^"]*)".*$/', "\\1", clean_text('<a href="'.$encodedurl.'" />', FORMAT_HTML)); $url = str_replace('&', '&', $encodedurl); if (!empty($message)) { if (!$debugdisableredirect && !headers_sent()) { // A message has been provided, and the headers have not yet been sent. // Display the message as a notification on the subsequent page. \core\notification::add($message, $messagetype); $message = null; $delay = 0; } else { if ($delay === -1 || !is_numeric($delay)) { $delay = 3; } $message = clean_text($message); } } else { $message = get_string('pageshouldredirect'); $delay = 0; } // Make sure the session is closed properly, this prevents problems in IIS // and also some potential PHP shutdown issues. \core\session\manager::write_close(); if ($delay == 0 && !$debugdisableredirect && !headers_sent()) { // 302 might not work for POST requests, 303 is ignored by obsolete clients. @header($_SERVER['SERVER_PROTOCOL'] . ' 303 See Other'); @header('Location: '.$url); echo bootstrap_renderer::plain_redirect_message($encodedurl); exit; } // Include a redirect message, even with a HTTP redirect, because that is recommended practice. if ($PAGE) { $CFG->docroot = false; // To prevent the link to moodle docs from being displayed on redirect page. echo $OUTPUT->redirect_message($encodedurl, $message, $delay, $debugdisableredirect, $messagetype); exit; } else { echo bootstrap_renderer::early_redirect_message($encodedurl, $message, $delay); exit; } }
/** * Display the edit step form for the specified step. * * @param int $id The step to edit. */ protected function edit_step($id) { global $PAGE; if (isset($id)) { $step = step::instance($id); } else { $step = new step(); $step->set_tourid(required_param('tourid', PARAM_INT)); } $tour = $step->get_tour(); if (!empty($tour->get_config(self::CONFIG_SHIPPED_TOUR))) { notification::add(get_string('modifyshippedtourwarning', 'tool_usertours'), notification::WARNING); } $PAGE->navbar->add($tour->get_name(), $tour->get_view_link()); if (isset($id)) { $PAGE->navbar->add($step->get_title(), $step->get_edit_link()); } else { $PAGE->navbar->add(get_string('newstep', 'tool_usertours'), $step->get_edit_link()); } $form = new forms\editstep($step->get_edit_link(), $step); if ($form->is_cancelled()) { redirect($step->get_tour()->get_view_link()); } else { if ($data = $form->get_data()) { $step->handle_form_submission($form, $data); $step->get_tour()->reset_step_sortorder(); redirect($step->get_tour()->get_view_link()); } else { if (empty($id)) { $this->header(get_string('newstep', 'tool_usertours')); } else { $this->header(get_string('editstep', 'tool_usertours', $step->get_title())); } $form->set_data($step->prepare_data_for_form()); $form->display(); $this->footer(); } } }