Пример #1
0
 /**
  * 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);
 }
Пример #2
0
/**
 * 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;
    }
}
Пример #3
0
/**
 * 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};)/", "&amp;", $url);
    $encodedurl = preg_replace('/^.*href="([^"]*)".*$/', "\\1", clean_text('<a href="'.$encodedurl.'" />', FORMAT_HTML));
    $url = str_replace('&amp;', '&', $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;
    }
}
Пример #4
0
 /**
  * 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();
         }
     }
 }