Merge branch 'MDL-60570-master' of git://github.com/andrewnicols/moodle
[moodle.git] / admin / renderer.php
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/>.
17 /**
18  * Renderer for core_admin subsystem
19  *
20  * @package    core
21  * @subpackage admin
22  * @copyright  2011 David Mudrak <david@moodle.com>
23  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24  */
26 defined('MOODLE_INTERNAL') || die();
29 /**
30  * Standard HTML output renderer for core_admin subsystem
31  */
32 class core_admin_renderer extends plugin_renderer_base {
34     /**
35      * Display the 'Do you acknowledge the terms of the GPL' page. The first page
36      * during install.
37      * @return string HTML to output.
38      */
39     public function install_licence_page() {
40         global $CFG;
41         $output = '';
43         $copyrightnotice = text_to_html(get_string('gpl3'));
44         $copyrightnotice = str_replace('target="_blank"', 'onclick="this.target=\'_blank\'"', $copyrightnotice); // extremely ugly validation hack
46         $continue = new single_button(new moodle_url($this->page->url, array(
47             'lang' => $CFG->lang, 'agreelicense' => 1)), get_string('continue'), 'get');
49         $output .= $this->header();
50         $output .= $this->heading('<a href="http://moodle.org">Moodle</a> - Modular Object-Oriented Dynamic Learning Environment');
51         $output .= $this->heading(get_string('copyrightnotice'));
52         $output .= $this->box($copyrightnotice, 'copyrightnotice');
53         $output .= html_writer::empty_tag('br');
54         $output .= $this->confirm(get_string('doyouagree'), $continue, "http://docs.moodle.org/dev/License");
55         $output .= $this->footer();
57         return $output;
58     }
60     /**
61      * Display page explaining proper upgrade process,
62      * there can not be any PHP file leftovers...
63      *
64      * @return string HTML to output.
65      */
66     public function upgrade_stale_php_files_page() {
67         $output = '';
68         $output .= $this->header();
69         $output .= $this->heading(get_string('upgradestalefiles', 'admin'));
70         $output .= $this->box_start('generalbox', 'notice');
71         $output .= format_text(get_string('upgradestalefilesinfo', 'admin', get_docs_url('Upgrading')), FORMAT_MARKDOWN);
72         $output .= html_writer::empty_tag('br');
73         $output .= html_writer::tag('div', $this->single_button($this->page->url, get_string('reload'), 'get'), array('class' => 'buttons'));
74         $output .= $this->box_end();
75         $output .= $this->footer();
77         return $output;
78     }
80     /**
81      * Display the 'environment check' page that is displayed during install.
82      * @param int $maturity
83      * @param boolean $envstatus final result of the check (true/false)
84      * @param array $environment_results array of results gathered
85      * @param string $release moodle release
86      * @return string HTML to output.
87      */
88     public function install_environment_page($maturity, $envstatus, $environment_results, $release) {
89         global $CFG;
90         $output = '';
92         $output .= $this->header();
93         $output .= $this->maturity_warning($maturity);
94         $output .= $this->heading("Moodle $release");
95         $output .= $this->release_notes_link();
97         $output .= $this->environment_check_table($envstatus, $environment_results);
99         if (!$envstatus) {
100             $output .= $this->upgrade_reload(new moodle_url($this->page->url, array('agreelicense' => 1, 'lang' => $CFG->lang)));
101         } else {
102             $output .= $this->notification(get_string('environmentok', 'admin'), 'notifysuccess');
103             $output .= $this->continue_button(new moodle_url($this->page->url, array(
104                 'agreelicense' => 1, 'confirmrelease' => 1, 'lang' => $CFG->lang)));
105         }
107         $output .= $this->footer();
108         return $output;
109     }
111     /**
112      * Displays the list of plugins with unsatisfied dependencies
113      *
114      * @param double|string|int $version Moodle on-disk version
115      * @param array $failed list of plugins with unsatisfied dependecies
116      * @param moodle_url $reloadurl URL of the page to recheck the dependencies
117      * @return string HTML
118      */
119     public function unsatisfied_dependencies_page($version, array $failed, moodle_url $reloadurl) {
120         $output = '';
122         $output .= $this->header();
123         $output .= $this->heading(get_string('pluginscheck', 'admin'));
124         $output .= $this->warning(get_string('pluginscheckfailed', 'admin', array('pluginslist' => implode(', ', array_unique($failed)))));
125         $output .= $this->plugins_check_table(core_plugin_manager::instance(), $version, array('xdep' => true));
126         $output .= $this->warning(get_string('pluginschecktodo', 'admin'));
127         $output .= $this->continue_button($reloadurl);
129         $output .= $this->footer();
131         return $output;
132     }
134     /**
135      * Display the 'You are about to upgrade Moodle' page. The first page
136      * during upgrade.
137      * @param string $strnewversion
138      * @param int $maturity
139      * @param string $testsite
140      * @return string HTML to output.
141      */
142     public function upgrade_confirm_page($strnewversion, $maturity, $testsite) {
143         $output = '';
145         $continueurl = new moodle_url($this->page->url, array('confirmupgrade' => 1, 'cache' => 0));
146         $continue = new single_button($continueurl, get_string('continue'), 'get');
147         $cancelurl = new moodle_url('/admin/index.php');
149         $output .= $this->header();
150         $output .= $this->maturity_warning($maturity);
151         $output .= $this->test_site_warning($testsite);
152         $output .= $this->confirm(get_string('upgradesure', 'admin', $strnewversion), $continue, $cancelurl);
153         $output .= $this->footer();
155         return $output;
156     }
158     /**
159      * Display the environment page during the upgrade process.
160      * @param string $release
161      * @param boolean $envstatus final result of env check (true/false)
162      * @param array $environment_results array of results gathered
163      * @return string HTML to output.
164      */
165     public function upgrade_environment_page($release, $envstatus, $environment_results) {
166         global $CFG;
167         $output = '';
169         $output .= $this->header();
170         $output .= $this->heading("Moodle $release");
171         $output .= $this->release_notes_link();
172         $output .= $this->environment_check_table($envstatus, $environment_results);
174         if (!$envstatus) {
175             $output .= $this->upgrade_reload(new moodle_url($this->page->url, array('confirmupgrade' => 1, 'cache' => 0)));
177         } else {
178             $output .= $this->notification(get_string('environmentok', 'admin'), 'notifysuccess');
180             if (empty($CFG->skiplangupgrade) and current_language() !== 'en') {
181                 $output .= $this->box(get_string('langpackwillbeupdated', 'admin'), 'generalbox', 'notice');
182             }
184             $output .= $this->continue_button(new moodle_url($this->page->url, array(
185                 'confirmupgrade' => 1, 'confirmrelease' => 1, 'cache' => 0)));
186         }
188         $output .= $this->footer();
190         return $output;
191     }
193     /**
194      * Display the upgrade page that lists all the plugins that require attention.
195      * @param core_plugin_manager $pluginman provides information about the plugins.
196      * @param \core\update\checker $checker provides information about available updates.
197      * @param int $version the version of the Moodle code from version.php.
198      * @param bool $showallplugins
199      * @param moodle_url $reloadurl
200      * @param moodle_url $continueurl
201      * @return string HTML to output.
202      */
203     public function upgrade_plugin_check_page(core_plugin_manager $pluginman, \core\update\checker $checker,
204             $version, $showallplugins, $reloadurl, $continueurl) {
206         $output = '';
208         $output .= $this->header();
209         $output .= $this->box_start('generalbox', 'plugins-check-page');
210         $output .= html_writer::tag('p', get_string('pluginchecknotice', 'core_plugin'), array('class' => 'page-description'));
211         $output .= $this->check_for_updates_button($checker, $reloadurl);
212         $output .= $this->missing_dependencies($pluginman);
213         $output .= $this->plugins_check_table($pluginman, $version, array('full' => $showallplugins));
214         $output .= $this->box_end();
215         $output .= $this->upgrade_reload($reloadurl);
217         if ($pluginman->some_plugins_updatable()) {
218             $output .= $this->container_start('upgradepluginsinfo');
219             $output .= $this->help_icon('upgradepluginsinfo', 'core_admin', get_string('upgradepluginsfirst', 'core_admin'));
220             $output .= $this->container_end();
221         }
223         $button = new single_button($continueurl, get_string('upgradestart', 'admin'), 'get');
224         $button->class = 'continuebutton';
225         $output .= $this->render($button);
226         $output .= $this->footer();
228         return $output;
229     }
231     /**
232      * Display a page to confirm plugin installation cancelation.
233      *
234      * @param array $abortable list of \core\update\plugininfo
235      * @param moodle_url $continue
236      * @return string
237      */
238     public function upgrade_confirm_abort_install_page(array $abortable, moodle_url $continue) {
240         $pluginman = core_plugin_manager::instance();
242         if (empty($abortable)) {
243             // The UI should not allow this.
244             throw new moodle_exception('err_no_plugin_install_abortable', 'core_plugin');
245         }
247         $out = $this->output->header();
248         $out .= $this->output->heading(get_string('cancelinstallhead', 'core_plugin'), 3);
249         $out .= $this->output->container(get_string('cancelinstallinfo', 'core_plugin'), 'cancelinstallinfo');
251         foreach ($abortable as $pluginfo) {
252             $out .= $this->output->heading($pluginfo->displayname.' ('.$pluginfo->component.')', 4);
253             $out .= $this->output->container(get_string('cancelinstallinfodir', 'core_plugin', $pluginfo->rootdir));
254             if ($repotype = $pluginman->plugin_external_source($pluginfo->component)) {
255                 $out .= $this->output->container(get_string('uninstalldeleteconfirmexternal', 'core_plugin', $repotype),
256                     'uninstalldeleteconfirmexternal');
257             }
258         }
260         $out .= $this->plugins_management_confirm_buttons($continue, $this->page->url);
261         $out .= $this->output->footer();
263         return $out;
264     }
266     /**
267      * Display the admin notifications page.
268      * @param int $maturity
269      * @param bool $insecuredataroot warn dataroot is invalid
270      * @param bool $errorsdisplayed warn invalid dispaly error setting
271      * @param bool $cronoverdue warn cron not running
272      * @param bool $dbproblems warn db has problems
273      * @param bool $maintenancemode warn in maintenance mode
274      * @param bool $buggyiconvnomb warn iconv problems
275      * @param array|null $availableupdates array of \core\update\info objects or null
276      * @param int|null $availableupdatesfetch timestamp of the most recent updates fetch or null (unknown)
277      * @param string[] $cachewarnings An array containing warnings from the Cache API.
278      * @param array $eventshandlers Events 1 API handlers.
279      * @param bool $themedesignermode Warn about the theme designer mode.
280      * @param bool $devlibdir Warn about development libs directory presence.
281      * @param bool $mobileconfigured Whether the mobile web services have been enabled
282      * @param bool $overridetossl Whether or not ssl is being forced.
283      * @param bool $invalidforgottenpasswordurl Whether the forgotten password URL does not link to a valid URL.
284      *
285      * @return string HTML to output.
286      */
287     public function admin_notifications_page($maturity, $insecuredataroot, $errorsdisplayed,
288             $cronoverdue, $dbproblems, $maintenancemode, $availableupdates, $availableupdatesfetch,
289             $buggyiconvnomb, $registered, array $cachewarnings = array(), $eventshandlers = 0,
290             $themedesignermode = false, $devlibdir = false, $mobileconfigured = false,
291             $overridetossl = false, $invalidforgottenpasswordurl = false) {
292         global $CFG;
293         $output = '';
295         $output .= $this->header();
296         $output .= $this->maturity_info($maturity);
297         $output .= $this->legacy_log_store_writing_error();
298         $output .= empty($CFG->disableupdatenotifications) ? $this->available_updates($availableupdates, $availableupdatesfetch) : '';
299         $output .= $this->insecure_dataroot_warning($insecuredataroot);
300         $output .= $this->development_libs_directories_warning($devlibdir);
301         $output .= $this->themedesignermode_warning($themedesignermode);
302         $output .= $this->display_errors_warning($errorsdisplayed);
303         $output .= $this->buggy_iconv_warning($buggyiconvnomb);
304         $output .= $this->cron_overdue_warning($cronoverdue);
305         $output .= $this->db_problems($dbproblems);
306         $output .= $this->maintenance_mode_warning($maintenancemode);
307         $output .= $this->overridetossl_warning($overridetossl);
308         $output .= $this->cache_warnings($cachewarnings);
309         $output .= $this->events_handlers($eventshandlers);
310         $output .= $this->registration_warning($registered);
311         $output .= $this->mobile_configuration_warning($mobileconfigured);
312         $output .= $this->forgotten_password_url_warning($invalidforgottenpasswordurl);
314         //////////////////////////////////////////////////////////////////////////////////////////////////
315         ////  IT IS ILLEGAL AND A VIOLATION OF THE GPL TO HIDE, REMOVE OR MODIFY THIS COPYRIGHT NOTICE ///
316         $output .= $this->moodle_copyright();
317         //////////////////////////////////////////////////////////////////////////////////////////////////
319         $output .= $this->footer();
321         return $output;
322     }
324     /**
325      * Display the plugin management page (admin/plugins.php).
326      *
327      * The filtering options array may contain following items:
328      *  bool contribonly - show only contributed extensions
329      *  bool updatesonly - show only plugins with an available update
330      *
331      * @param core_plugin_manager $pluginman
332      * @param \core\update\checker $checker
333      * @param array $options filtering options
334      * @return string HTML to output.
335      */
336     public function plugin_management_page(core_plugin_manager $pluginman, \core\update\checker $checker, array $options = array()) {
338         $output = '';
340         $output .= $this->header();
341         $output .= $this->heading(get_string('pluginsoverview', 'core_admin'));
342         $output .= $this->check_for_updates_button($checker, $this->page->url);
343         $output .= $this->plugins_overview_panel($pluginman, $options);
344         $output .= $this->plugins_control_panel($pluginman, $options);
345         $output .= $this->footer();
347         return $output;
348     }
350     /**
351      * Renders a button to fetch for available updates.
352      *
353      * @param \core\update\checker $checker
354      * @param moodle_url $reloadurl
355      * @return string HTML
356      */
357     public function check_for_updates_button(\core\update\checker $checker, $reloadurl) {
359         $output = '';
361         if ($checker->enabled()) {
362             $output .= $this->container_start('checkforupdates');
363             $output .= $this->single_button(
364                 new moodle_url($reloadurl, array('fetchupdates' => 1)),
365                 get_string('checkforupdates', 'core_plugin')
366             );
367             if ($timefetched = $checker->get_last_timefetched()) {
368                 $timefetched = userdate($timefetched, get_string('strftimedatetime', 'core_langconfig'));
369                 $output .= $this->container(get_string('checkforupdateslast', 'core_plugin', $timefetched), 'lasttimefetched');
370             }
371             $output .= $this->container_end();
372         }
374         return $output;
375     }
377     /**
378      * Display a page to confirm the plugin uninstallation.
379      *
380      * @param core_plugin_manager $pluginman
381      * @param \core\plugininfo\base $pluginfo
382      * @param moodle_url $continueurl URL to continue after confirmation
383      * @param moodle_url $cancelurl URL to to go if cancelled
384      * @return string
385      */
386     public function plugin_uninstall_confirm_page(core_plugin_manager $pluginman, \core\plugininfo\base $pluginfo, moodle_url $continueurl, moodle_url $cancelurl) {
387         $output = '';
389         $pluginname = $pluginman->plugin_name($pluginfo->component);
391         $confirm = '<p>' . get_string('uninstallconfirm', 'core_plugin', array('name' => $pluginname)) . '</p>';
392         if ($extraconfirm = $pluginfo->get_uninstall_extra_warning()) {
393             $confirm .= $extraconfirm;
394         }
396         $output .= $this->output->header();
397         $output .= $this->output->heading(get_string('uninstalling', 'core_plugin', array('name' => $pluginname)));
398         $output .= $this->output->confirm($confirm, $continueurl, $cancelurl);
399         $output .= $this->output->footer();
401         return $output;
402     }
404     /**
405      * Display a page with results of plugin uninstallation and offer removal of plugin files.
406      *
407      * @param core_plugin_manager $pluginman
408      * @param \core\plugininfo\base $pluginfo
409      * @param progress_trace_buffer $progress
410      * @param moodle_url $continueurl URL to continue to remove the plugin folder
411      * @return string
412      */
413     public function plugin_uninstall_results_removable_page(core_plugin_manager $pluginman, \core\plugininfo\base $pluginfo,
414                                                             progress_trace_buffer $progress, moodle_url $continueurl) {
415         $output = '';
417         $pluginname = $pluginman->plugin_name($pluginfo->component);
419         // Do not show navigation here, they must click one of the buttons.
420         $this->page->set_pagelayout('maintenance');
421         $this->page->set_cacheable(false);
423         $output .= $this->output->header();
424         $output .= $this->output->heading(get_string('uninstalling', 'core_plugin', array('name' => $pluginname)));
426         $output .= $this->output->box($progress->get_buffer(), 'generalbox uninstallresultmessage');
428         $confirm = $this->output->container(get_string('uninstalldeleteconfirm', 'core_plugin',
429             array('name' => $pluginname, 'rootdir' => $pluginfo->rootdir)), 'uninstalldeleteconfirm');
431         if ($repotype = $pluginman->plugin_external_source($pluginfo->component)) {
432             $confirm .= $this->output->container(get_string('uninstalldeleteconfirmexternal', 'core_plugin', $repotype),
433                 'uninstalldeleteconfirmexternal');
434         }
436         // After any uninstall we must execute full upgrade to finish the cleanup!
437         $output .= $this->output->confirm($confirm, $continueurl, new moodle_url('/admin/index.php'));
438         $output .= $this->output->footer();
440         return $output;
441     }
443     /**
444      * Display a page with results of plugin uninstallation and inform about the need to remove plugin files manually.
445      *
446      * @param core_plugin_manager $pluginman
447      * @param \core\plugininfo\base $pluginfo
448      * @param progress_trace_buffer $progress
449      * @return string
450      */
451     public function plugin_uninstall_results_page(core_plugin_manager $pluginman, \core\plugininfo\base $pluginfo, progress_trace_buffer $progress) {
452         $output = '';
454         $pluginname = $pluginfo->component;
456         $output .= $this->output->header();
457         $output .= $this->output->heading(get_string('uninstalling', 'core_plugin', array('name' => $pluginname)));
459         $output .= $this->output->box($progress->get_buffer(), 'generalbox uninstallresultmessage');
461         $output .= $this->output->box(get_string('uninstalldelete', 'core_plugin',
462             array('name' => $pluginname, 'rootdir' => $pluginfo->rootdir)), 'generalbox uninstalldelete');
463         $output .= $this->output->continue_button(new moodle_url('/admin/index.php'));
464         $output .= $this->output->footer();
466         return $output;
467     }
469     /**
470      * Display the plugin management page (admin/environment.php).
471      * @param array $versions
472      * @param string $version
473      * @param boolean $envstatus final result of env check (true/false)
474      * @param array $environment_results array of results gathered
475      * @return string HTML to output.
476      */
477     public function environment_check_page($versions, $version, $envstatus, $environment_results) {
478         $output = '';
479         $output .= $this->header();
481         // Print the component download link
482         $output .= html_writer::tag('div', html_writer::link(
483                     new moodle_url('/admin/environment.php', array('action' => 'updatecomponent', 'sesskey' => sesskey())),
484                     get_string('updatecomponent', 'admin')),
485                 array('class' => 'reportlink'));
487         // Heading.
488         $output .= $this->heading(get_string('environment', 'admin'));
490         // Box with info and a menu to choose the version.
491         $output .= $this->box_start();
492         $output .= html_writer::tag('div', get_string('adminhelpenvironment'));
493         $select = new single_select(new moodle_url('/admin/environment.php'), 'version', $versions, $version, null);
494         $select->label = get_string('moodleversion');
495         $output .= $this->render($select);
496         $output .= $this->box_end();
498         // The results
499         $output .= $this->environment_check_table($envstatus, $environment_results);
501         $output .= $this->footer();
502         return $output;
503     }
505     /**
506      * Output a warning message, of the type that appears on the admin notifications page.
507      * @param string $message the message to display.
508      * @param string $type type class
509      * @return string HTML to output.
510      */
511     protected function warning($message, $type = 'warning') {
512         return $this->box($message, 'generalbox admin' . $type);
513     }
515     /**
516      * Render an appropriate message if dataroot is insecure.
517      * @param bool $insecuredataroot
518      * @return string HTML to output.
519      */
520     protected function insecure_dataroot_warning($insecuredataroot) {
521         global $CFG;
523         if ($insecuredataroot == INSECURE_DATAROOT_WARNING) {
524             return $this->warning(get_string('datarootsecuritywarning', 'admin', $CFG->dataroot));
526         } else if ($insecuredataroot == INSECURE_DATAROOT_ERROR) {
527             return $this->warning(get_string('datarootsecurityerror', 'admin', $CFG->dataroot), 'error');
529         } else {
530             return '';
531         }
532     }
534     /**
535      * Render a warning that a directory with development libs is present.
536      *
537      * @param bool $devlibdir True if the warning should be displayed.
538      * @return string
539      */
540     protected function development_libs_directories_warning($devlibdir) {
542         if ($devlibdir) {
543             $moreinfo = new moodle_url('/report/security/index.php');
544             $warning = get_string('devlibdirpresent', 'core_admin', ['moreinfourl' => $moreinfo->out()]);
545             return $this->warning($warning, 'error');
547         } else {
548             return '';
549         }
550     }
552     /**
553      * Render an appropriate message if dataroot is insecure.
554      * @param bool $errorsdisplayed
555      * @return string HTML to output.
556      */
557     protected function display_errors_warning($errorsdisplayed) {
558         if (!$errorsdisplayed) {
559             return '';
560         }
562         return $this->warning(get_string('displayerrorswarning', 'admin'));
563     }
565     /**
566      * Render an appropriate message if themdesignermode is enabled.
567      * @param bool $themedesignermode true if enabled
568      * @return string HTML to output.
569      */
570     protected function themedesignermode_warning($themedesignermode) {
571         if (!$themedesignermode) {
572             return '';
573         }
575         return $this->warning(get_string('themedesignermodewarning', 'admin'));
576     }
578     /**
579      * Render an appropriate message if iconv is buggy and mbstring missing.
580      * @param bool $buggyiconvnomb
581      * @return string HTML to output.
582      */
583     protected function buggy_iconv_warning($buggyiconvnomb) {
584         if (!$buggyiconvnomb) {
585             return '';
586         }
588         return $this->warning(get_string('warningiconvbuggy', 'admin'));
589     }
591     /**
592      * Render an appropriate message if cron has not been run recently.
593      * @param bool $cronoverdue
594      * @return string HTML to output.
595      */
596     public function cron_overdue_warning($cronoverdue) {
597         global $CFG;
598         if (!$cronoverdue) {
599             return '';
600         }
602         if (empty($CFG->cronclionly)) {
603             $url = new moodle_url('/admin/cron.php');
604             if (!empty($CFG->cronremotepassword)) {
605                 $url = new moodle_url('/admin/cron.php', array('password' => $CFG->cronremotepassword));
606             }
608             return $this->warning(get_string('cronwarning', 'admin', $url->out()) . '&nbsp;' .
609                     $this->help_icon('cron', 'admin'));
610         }
612         // $CFG->cronclionly is not empty: cron can run only from CLI.
613         return $this->warning(get_string('cronwarningcli', 'admin') . '&nbsp;' .
614                 $this->help_icon('cron', 'admin'));
615     }
617     /**
618      * Render an appropriate message if there are any problems with the DB set-up.
619      * @param bool $dbproblems
620      * @return string HTML to output.
621      */
622     public function db_problems($dbproblems) {
623         if (!$dbproblems) {
624             return '';
625         }
627         return $this->warning($dbproblems);
628     }
630     /**
631      * Renders cache warnings if there are any.
632      *
633      * @param string[] $cachewarnings
634      * @return string
635      */
636     public function cache_warnings(array $cachewarnings) {
637         if (!count($cachewarnings)) {
638             return '';
639         }
640         return join("\n", array_map(array($this, 'warning'), $cachewarnings));
641     }
643     /**
644      * Renders events 1 API handlers warning.
645      *
646      * @param array $eventshandlers
647      * @return string
648      */
649     public function events_handlers($eventshandlers) {
650         if ($eventshandlers) {
651             $components = '';
652             foreach ($eventshandlers as $eventhandler) {
653                 $components .= $eventhandler->component . ', ';
654             }
655             $components = rtrim($components, ', ');
656             return $this->warning(get_string('eventshandlersinuse', 'admin', $components));
657         }
658     }
660     /**
661      * Render an appropriate message if the site in in maintenance mode.
662      * @param bool $maintenancemode
663      * @return string HTML to output.
664      */
665     public function maintenance_mode_warning($maintenancemode) {
666         if (!$maintenancemode) {
667             return '';
668         }
670         $url = new moodle_url('/admin/settings.php', array('section' => 'maintenancemode'));
671         $url = $url->out(); // get_string() does not support objects in params
673         return $this->warning(get_string('sitemaintenancewarning2', 'admin', $url));
674     }
676     /**
677      * Render a warning that ssl is forced because the site was on loginhttps.
678      *
679      * @param bool $overridetossl Whether or not ssl is being forced.
680      * @return string
681      */
682     protected function overridetossl_warning($overridetossl) {
683         if (!$overridetossl) {
684             return '';
685         }
686         $warning = get_string('overridetossl', 'core_admin');
687         return $this->warning($warning, 'warning');
688     }
690     /**
691      * Display a warning about installing development code if necesary.
692      * @param int $maturity
693      * @return string HTML to output.
694      */
695     protected function maturity_warning($maturity) {
696         if ($maturity == MATURITY_STABLE) {
697             return ''; // No worries.
698         }
700         $maturitylevel = get_string('maturity' . $maturity, 'admin');
701         return $this->warning(
702                     $this->container(get_string('maturitycorewarning', 'admin', $maturitylevel)) .
703                     $this->container($this->doc_link('admin/versions', get_string('morehelp'))),
704                 'error');
705     }
707     /*
708      * If necessary, displays a warning about upgrading a test site.
709      *
710      * @param string $testsite
711      * @return string HTML
712      */
713     protected function test_site_warning($testsite) {
715         if (!$testsite) {
716             return '';
717         }
719         $warning = (get_string('testsiteupgradewarning', 'admin', $testsite));
720         return $this->warning($warning, 'error');
721     }
723     /**
724      * Output the copyright notice.
725      * @return string HTML to output.
726      */
727     protected function moodle_copyright() {
728         global $CFG;
730         //////////////////////////////////////////////////////////////////////////////////////////////////
731         ////  IT IS ILLEGAL AND A VIOLATION OF THE GPL TO HIDE, REMOVE OR MODIFY THIS COPYRIGHT NOTICE ///
732         $copyrighttext = '<a href="http://moodle.org/">Moodle</a> '.
733                          '<a href="http://docs.moodle.org/dev/Releases" title="'.$CFG->version.'">'.$CFG->release.'</a><br />'.
734                          'Copyright &copy; 1999 onwards, Martin Dougiamas<br />'.
735                          'and <a href="http://moodle.org/dev">many other contributors</a>.<br />'.
736                          '<a href="http://docs.moodle.org/dev/License">GNU Public License</a>';
737         //////////////////////////////////////////////////////////////////////////////////////////////////
739         return $this->box($copyrighttext, 'copyright');
740     }
742     /**
743      * Display a warning about installing development code if necesary.
744      * @param int $maturity
745      * @return string HTML to output.
746      */
747     protected function maturity_info($maturity) {
748         if ($maturity == MATURITY_STABLE) {
749             return ''; // No worries.
750         }
752         $level = 'warning';
754         if ($maturity == MATURITY_ALPHA) {
755             $level = 'error';
756         }
758         $maturitylevel = get_string('maturity' . $maturity, 'admin');
759         $warningtext = get_string('maturitycoreinfo', 'admin', $maturitylevel);
760         $warningtext .= ' ' . $this->doc_link('admin/versions', get_string('morehelp'));
761         return $this->warning($warningtext, $level);
762     }
764     /**
765      * Displays the info about available Moodle core and plugin updates
766      *
767      * The structure of the $updates param has changed since 2.4. It contains not only updates
768      * for the core itself, but also for all other installed plugins.
769      *
770      * @param array|null $updates array of (string)component => array of \core\update\info objects or null
771      * @param int|null $fetch timestamp of the most recent updates fetch or null (unknown)
772      * @return string
773      */
774     protected function available_updates($updates, $fetch) {
776         $updateinfo = '';
777         $someupdateavailable = false;
778         if (is_array($updates)) {
779             if (is_array($updates['core'])) {
780                 $someupdateavailable = true;
781                 $updateinfo .= $this->heading(get_string('updateavailable', 'core_admin'), 3);
782                 foreach ($updates['core'] as $update) {
783                     $updateinfo .= $this->moodle_available_update_info($update);
784                 }
785                 $updateinfo .= html_writer::tag('p', get_string('updateavailablerecommendation', 'core_admin'),
786                     array('class' => 'updateavailablerecommendation'));
787             }
788             unset($updates['core']);
789             // If something has left in the $updates array now, it is updates for plugins.
790             if (!empty($updates)) {
791                 $someupdateavailable = true;
792                 $updateinfo .= $this->heading(get_string('updateavailableforplugin', 'core_admin'), 3);
793                 $pluginsoverviewurl = new moodle_url('/admin/plugins.php', array('updatesonly' => 1));
794                 $updateinfo .= $this->container(get_string('pluginsoverviewsee', 'core_admin',
795                     array('url' => $pluginsoverviewurl->out())));
796             }
797         }
799         if (!$someupdateavailable) {
800             $now = time();
801             if ($fetch and ($fetch <= $now) and ($now - $fetch < HOURSECS)) {
802                 $updateinfo .= $this->heading(get_string('updateavailablenot', 'core_admin'), 3);
803             }
804         }
806         $updateinfo .= $this->container_start('checkforupdates');
807         $fetchurl = new moodle_url('/admin/index.php', array('fetchupdates' => 1, 'sesskey' => sesskey(), 'cache' => 0));
808         $updateinfo .= $this->single_button($fetchurl, get_string('checkforupdates', 'core_plugin'));
809         if ($fetch) {
810             $updateinfo .= $this->container(get_string('checkforupdateslast', 'core_plugin',
811                 userdate($fetch, get_string('strftimedatetime', 'core_langconfig'))));
812         }
813         $updateinfo .= $this->container_end();
815         return $this->warning($updateinfo);
816     }
818     /**
819      * Display a warning about not being registered on Moodle.org if necesary.
820      *
821      * @param boolean $registered true if the site is registered on Moodle.org
822      * @return string HTML to output.
823      */
824     protected function registration_warning($registered) {
826         if (!$registered) {
828             if (has_capability('moodle/site:config', context_system::instance())) {
829                 $registerbutton = $this->single_button(new moodle_url('/admin/registration/index.php'),
830                     get_string('register', 'admin'));
831                 $str = 'registrationwarning';
832             } else {
833                 $registerbutton = '';
834                 $str = 'registrationwarningcontactadmin';
835             }
837             return $this->warning( get_string($str, 'admin')
838                     . '&nbsp;' . $this->help_icon('registration', 'admin') . $registerbutton ,
839                 'error alert alert-danger');
840         }
842         return '';
843     }
845     /**
846      * Return an admin page warning if site is not registered with moodle.org
847      *
848      * @return string
849      */
850     public function warn_if_not_registered() {
851         return $this->registration_warning(\core\hub\registration::is_registered());
852     }
854     /**
855      * Display a warning about the Mobile Web Services being disabled.
856      *
857      * @param boolean $mobileconfigured true if mobile web services are enabled
858      * @return string HTML to output.
859      */
860     protected function mobile_configuration_warning($mobileconfigured) {
861         $output = '';
862         if (!$mobileconfigured) {
863             $settingslink = new moodle_url('/admin/settings.php', ['section' => 'mobilesettings']);
864             $configurebutton = $this->single_button($settingslink, get_string('enablemobilewebservice', 'admin'));
865             $output .= $this->warning(get_string('mobilenotconfiguredwarning', 'admin') . '&nbsp;' . $configurebutton);
866         }
868         return $output;
869     }
871     /**
872      * Display a warning about the forgotten password URL not linking to a valid URL.
873      *
874      * @param boolean $invalidforgottenpasswordurl true if the forgotten password URL is not valid
875      * @return string HTML to output.
876      */
877     protected function forgotten_password_url_warning($invalidforgottenpasswordurl) {
878         $output = '';
879         if ($invalidforgottenpasswordurl) {
880             $settingslink = new moodle_url('/admin/settings.php', ['section' => 'manageauths']);
881             $configurebutton = $this->single_button($settingslink, get_string('check', 'moodle'));
882             $output .= $this->warning(get_string('invalidforgottenpasswordurl', 'admin') . '&nbsp;' . $configurebutton,
883                 'error alert alert-danger');
884         }
886         return $output;
887     }
889     /**
890      * Helper method to render the information about the available Moodle update
891      *
892      * @param \core\update\info $updateinfo information about the available Moodle core update
893      */
894     protected function moodle_available_update_info(\core\update\info $updateinfo) {
896         $boxclasses = 'moodleupdateinfo';
897         $info = array();
899         if (isset($updateinfo->release)) {
900             $info[] = html_writer::tag('span', get_string('updateavailable_release', 'core_admin', $updateinfo->release),
901                 array('class' => 'info release'));
902         }
904         if (isset($updateinfo->version)) {
905             $info[] = html_writer::tag('span', get_string('updateavailable_version', 'core_admin', $updateinfo->version),
906                 array('class' => 'info version'));
907         }
909         if (isset($updateinfo->maturity)) {
910             $info[] = html_writer::tag('span', get_string('maturity'.$updateinfo->maturity, 'core_admin'),
911                 array('class' => 'info maturity'));
912             $boxclasses .= ' maturity'.$updateinfo->maturity;
913         }
915         if (isset($updateinfo->download)) {
916             $info[] = html_writer::link($updateinfo->download, get_string('download'), array('class' => 'info download'));
917         }
919         if (isset($updateinfo->url)) {
920             $info[] = html_writer::link($updateinfo->url, get_string('updateavailable_moreinfo', 'core_plugin'),
921                 array('class' => 'info more'));
922         }
924         $box  = $this->output->box_start($boxclasses);
925         $box .= $this->output->box(implode(html_writer::tag('span', ' ', array('class' => 'separator')), $info), '');
926         $box .= $this->output->box_end();
928         return $box;
929     }
931     /**
932      * Display a link to the release notes.
933      * @return string HTML to output.
934      */
935     protected function release_notes_link() {
936         $releasenoteslink = get_string('releasenoteslink', 'admin', 'http://docs.moodle.org/dev/Releases');
937         $releasenoteslink = str_replace('target="_blank"', 'onclick="this.target=\'_blank\'"', $releasenoteslink); // extremely ugly validation hack
938         return $this->box($releasenoteslink, 'generalbox releasenoteslink');
939     }
941     /**
942      * Display the reload link that appears on several upgrade/install pages.
943      * @return string HTML to output.
944      */
945     function upgrade_reload($url) {
946         return html_writer::empty_tag('br') .
947                 html_writer::tag('div',
948                     html_writer::link($url, $this->pix_icon('i/reload', '', '', array('class' => 'icon icon-pre')) .
949                             get_string('reload'), array('title' => get_string('reload'))),
950                 array('class' => 'continuebutton')) . html_writer::empty_tag('br');
951     }
953     /**
954      * Displays all known plugins and information about their installation or upgrade
955      *
956      * This default implementation renders all plugins into one big table. The rendering
957      * options support:
958      *     (bool)full = false: whether to display up-to-date plugins, too
959      *     (bool)xdep = false: display the plugins with unsatisified dependecies only
960      *
961      * @param core_plugin_manager $pluginman provides information about the plugins.
962      * @param int $version the version of the Moodle code from version.php.
963      * @param array $options rendering options
964      * @return string HTML code
965      */
966     public function plugins_check_table(core_plugin_manager $pluginman, $version, array $options = array()) {
968         $plugininfo = $pluginman->get_plugins();
970         if (empty($plugininfo)) {
971             return '';
972         }
974         $options['full'] = isset($options['full']) ? (bool)$options['full'] : false;
975         $options['xdep'] = isset($options['xdep']) ? (bool)$options['xdep'] : false;
977         $table = new html_table();
978         $table->id = 'plugins-check';
979         $table->head = array(
980             get_string('displayname', 'core_plugin').' / '.get_string('rootdir', 'core_plugin'),
981             get_string('versiondb', 'core_plugin'),
982             get_string('versiondisk', 'core_plugin'),
983             get_string('requires', 'core_plugin'),
984             get_string('source', 'core_plugin').' / '.get_string('status', 'core_plugin'),
985         );
986         $table->colclasses = array(
987             'displayname', 'versiondb', 'versiondisk', 'requires', 'status',
988         );
989         $table->data = array();
991         // Number of displayed plugins per type.
992         $numdisplayed = array();
993         // Number of plugins known to the plugin manager.
994         $sumtotal = 0;
995         // Number of plugins requiring attention.
996         $sumattention = 0;
997         // List of all components we can cancel installation of.
998         $installabortable = $pluginman->list_cancellable_installations();
999         // List of all components we can cancel upgrade of.
1000         $upgradeabortable = $pluginman->list_restorable_archives();
1002         foreach ($plugininfo as $type => $plugins) {
1004             $header = new html_table_cell($pluginman->plugintype_name_plural($type));
1005             $header->header = true;
1006             $header->colspan = count($table->head);
1007             $header = new html_table_row(array($header));
1008             $header->attributes['class'] = 'plugintypeheader type-' . $type;
1010             $numdisplayed[$type] = 0;
1012             if (empty($plugins) and $options['full']) {
1013                 $msg = new html_table_cell(get_string('noneinstalled', 'core_plugin'));
1014                 $msg->colspan = count($table->head);
1015                 $row = new html_table_row(array($msg));
1016                 $row->attributes['class'] .= 'msg msg-noneinstalled';
1017                 $table->data[] = $header;
1018                 $table->data[] = $row;
1019                 continue;
1020             }
1022             $plugintyperows = array();
1024             foreach ($plugins as $name => $plugin) {
1025                 $sumtotal++;
1026                 $row = new html_table_row();
1027                 $row->attributes['class'] = 'type-' . $plugin->type . ' name-' . $plugin->type . '_' . $plugin->name;
1029                 if ($this->page->theme->resolve_image_location('icon', $plugin->type . '_' . $plugin->name, null)) {
1030                     $icon = $this->output->pix_icon('icon', '', $plugin->type . '_' . $plugin->name, array('class' => 'smallicon pluginicon'));
1031                 } else {
1032                     $icon = '';
1033                 }
1035                 $displayname = new html_table_cell(
1036                     $icon.
1037                     html_writer::span($plugin->displayname, 'pluginname').
1038                     html_writer::div($plugin->get_dir(), 'plugindir')
1039                 );
1041                 $versiondb = new html_table_cell($plugin->versiondb);
1042                 $versiondisk = new html_table_cell($plugin->versiondisk);
1044                 if ($isstandard = $plugin->is_standard()) {
1045                     $row->attributes['class'] .= ' standard';
1046                     $sourcelabel = html_writer::span(get_string('sourcestd', 'core_plugin'), 'sourcetext label');
1047                 } else {
1048                     $row->attributes['class'] .= ' extension';
1049                     $sourcelabel = html_writer::span(get_string('sourceext', 'core_plugin'), 'sourcetext label label-info');
1050                 }
1052                 $coredependency = $plugin->is_core_dependency_satisfied($version);
1053                 $otherpluginsdependencies = $pluginman->are_dependencies_satisfied($plugin->get_other_required_plugins());
1054                 $dependenciesok = $coredependency && $otherpluginsdependencies;
1056                 $statuscode = $plugin->get_status();
1057                 $row->attributes['class'] .= ' status-' . $statuscode;
1058                 $statusclass = 'statustext label ';
1059                 switch ($statuscode) {
1060                     case core_plugin_manager::PLUGIN_STATUS_NEW:
1061                         $statusclass .= $dependenciesok ? 'label-success' : 'label-warning';
1062                         break;
1063                     case core_plugin_manager::PLUGIN_STATUS_UPGRADE:
1064                         $statusclass .= $dependenciesok ? 'label-info' : 'label-warning';
1065                         break;
1066                     case core_plugin_manager::PLUGIN_STATUS_MISSING:
1067                     case core_plugin_manager::PLUGIN_STATUS_DOWNGRADE:
1068                     case core_plugin_manager::PLUGIN_STATUS_DELETE:
1069                         $statusclass .= 'label-important';
1070                         break;
1071                     case core_plugin_manager::PLUGIN_STATUS_NODB:
1072                     case core_plugin_manager::PLUGIN_STATUS_UPTODATE:
1073                         $statusclass .= $dependenciesok ? '' : 'label-warning';
1074                         break;
1075                 }
1076                 $status = html_writer::span(get_string('status_' . $statuscode, 'core_plugin'), $statusclass);
1078                 if (!empty($installabortable[$plugin->component])) {
1079                     $status .= $this->output->single_button(
1080                         new moodle_url($this->page->url, array('abortinstall' => $plugin->component)),
1081                         get_string('cancelinstallone', 'core_plugin'),
1082                         'post',
1083                         array('class' => 'actionbutton cancelinstallone')
1084                     );
1085                 }
1087                 if (!empty($upgradeabortable[$plugin->component])) {
1088                     $status .= $this->output->single_button(
1089                         new moodle_url($this->page->url, array('abortupgrade' => $plugin->component)),
1090                         get_string('cancelupgradeone', 'core_plugin'),
1091                         'post',
1092                         array('class' => 'actionbutton cancelupgradeone')
1093                     );
1094                 }
1096                 $availableupdates = $plugin->available_updates();
1097                 if (!empty($availableupdates)) {
1098                     foreach ($availableupdates as $availableupdate) {
1099                         $status .= $this->plugin_available_update_info($pluginman, $availableupdate);
1100                     }
1101                 }
1103                 $status = new html_table_cell($sourcelabel.' '.$status);
1105                 $requires = new html_table_cell($this->required_column($plugin, $pluginman, $version));
1107                 $statusisboring = in_array($statuscode, array(
1108                         core_plugin_manager::PLUGIN_STATUS_NODB, core_plugin_manager::PLUGIN_STATUS_UPTODATE));
1110                 if ($options['xdep']) {
1111                     // we want to see only plugins with failed dependencies
1112                     if ($dependenciesok) {
1113                         continue;
1114                     }
1116                 } else if ($statusisboring and $dependenciesok and empty($availableupdates)) {
1117                     // no change is going to happen to the plugin - display it only
1118                     // if the user wants to see the full list
1119                     if (empty($options['full'])) {
1120                         continue;
1121                     }
1123                 } else {
1124                     $sumattention++;
1125                 }
1127                 // The plugin should be displayed.
1128                 $numdisplayed[$type]++;
1129                 $row->cells = array($displayname, $versiondb, $versiondisk, $requires, $status);
1130                 $plugintyperows[] = $row;
1131             }
1133             if (empty($numdisplayed[$type]) and empty($options['full'])) {
1134                 continue;
1135             }
1137             $table->data[] = $header;
1138             $table->data = array_merge($table->data, $plugintyperows);
1139         }
1141         // Total number of displayed plugins.
1142         $sumdisplayed = array_sum($numdisplayed);
1144         if ($options['xdep']) {
1145             // At the plugins dependencies check page, display the table only.
1146             return html_writer::table($table);
1147         }
1149         $out = $this->output->container_start('', 'plugins-check-info');
1151         if ($sumdisplayed == 0) {
1152             $out .= $this->output->heading(get_string('pluginchecknone', 'core_plugin'));
1154         } else {
1155             if (empty($options['full'])) {
1156                 $out .= $this->output->heading(get_string('plugincheckattention', 'core_plugin'));
1157             } else {
1158                 $out .= $this->output->heading(get_string('plugincheckall', 'core_plugin'));
1159             }
1160         }
1162         $out .= $this->output->container_start('actions');
1164         $installableupdates = $pluginman->filter_installable($pluginman->available_updates());
1165         if ($installableupdates) {
1166             $out .= $this->output->single_button(
1167                 new moodle_url($this->page->url, array('installupdatex' => 1)),
1168                 get_string('updateavailableinstallall', 'core_admin', count($installableupdates)),
1169                 'post',
1170                 array('class' => 'singlebutton updateavailableinstallall')
1171             );
1172         }
1174         if ($installabortable) {
1175             $out .= $this->output->single_button(
1176                 new moodle_url($this->page->url, array('abortinstallx' => 1)),
1177                 get_string('cancelinstallall', 'core_plugin', count($installabortable)),
1178                 'post',
1179                 array('class' => 'singlebutton cancelinstallall')
1180             );
1181         }
1183         if ($upgradeabortable) {
1184             $out .= $this->output->single_button(
1185                 new moodle_url($this->page->url, array('abortupgradex' => 1)),
1186                 get_string('cancelupgradeall', 'core_plugin', count($upgradeabortable)),
1187                 'post',
1188                 array('class' => 'singlebutton cancelupgradeall')
1189             );
1190         }
1192         $out .= html_writer::div(html_writer::link(new moodle_url($this->page->url, array('showallplugins' => 0)),
1193             get_string('plugincheckattention', 'core_plugin')).' '.html_writer::span($sumattention, 'badge'));
1195         $out .= html_writer::div(html_writer::link(new moodle_url($this->page->url, array('showallplugins' => 1)),
1196             get_string('plugincheckall', 'core_plugin')).' '.html_writer::span($sumtotal, 'badge'));
1198         $out .= $this->output->container_end(); // End of .actions container.
1199         $out .= $this->output->container_end(); // End of #plugins-check-info container.
1201         if ($sumdisplayed > 0 or $options['full']) {
1202             $out .= html_writer::table($table);
1203         }
1205         return $out;
1206     }
1208     /**
1209      * Display the continue / cancel widgets for the plugins management pages.
1210      *
1211      * @param null|moodle_url $continue URL for the continue button, should it be displayed
1212      * @param null|moodle_url $cancel URL for the cancel link, defaults to the current page
1213      * @return string HTML
1214      */
1215     public function plugins_management_confirm_buttons(moodle_url $continue=null, moodle_url $cancel=null) {
1217         $out = html_writer::start_div('plugins-management-confirm-buttons');
1219         if (!empty($continue)) {
1220             $out .= $this->output->single_button($continue, get_string('continue'), 'post', array('class' => 'continue'));
1221         }
1223         if (empty($cancel)) {
1224             $cancel = $this->page->url;
1225         }
1226         $out .= html_writer::div(html_writer::link($cancel, get_string('cancel')), 'cancel');
1228         return $out;
1229     }
1231     /**
1232      * Displays the information about missing dependencies
1233      *
1234      * @param core_plugin_manager $pluginman
1235      * @return string
1236      */
1237     protected function missing_dependencies(core_plugin_manager $pluginman) {
1239         $dependencies = $pluginman->missing_dependencies();
1241         if (empty($dependencies)) {
1242             return '';
1243         }
1245         $available = array();
1246         $unavailable = array();
1247         $unknown = array();
1249         foreach ($dependencies as $component => $remoteinfo) {
1250             if ($remoteinfo === false) {
1251                 // The required version is not available. Let us check if there
1252                 // is at least some version in the plugins directory.
1253                 $remoteinfoanyversion = $pluginman->get_remote_plugin_info($component, ANY_VERSION, false);
1254                 if ($remoteinfoanyversion === false) {
1255                     $unknown[$component] = $component;
1256                 } else {
1257                     $unavailable[$component] = $remoteinfoanyversion;
1258                 }
1259             } else {
1260                 $available[$component] = $remoteinfo;
1261             }
1262         }
1264         $out  = $this->output->container_start('plugins-check-dependencies');
1266         if ($unavailable or $unknown) {
1267             $out .= $this->output->heading(get_string('misdepsunavail', 'core_plugin'));
1268             if ($unknown) {
1269                 $out .= $this->output->notification(get_string('misdepsunknownlist', 'core_plugin', implode($unknown, ', ')));
1270             }
1271             if ($unavailable) {
1272                 $unavailablelist = array();
1273                 foreach ($unavailable as $component => $remoteinfoanyversion) {
1274                     $unavailablelistitem = html_writer::link('https://moodle.org/plugins/view.php?plugin='.$component,
1275                         '<strong>'.$remoteinfoanyversion->name.'</strong>');
1276                     if ($remoteinfoanyversion->version) {
1277                         $unavailablelistitem .= ' ('.$component.' &gt; '.$remoteinfoanyversion->version->version.')';
1278                     } else {
1279                         $unavailablelistitem .= ' ('.$component.')';
1280                     }
1281                     $unavailablelist[] = $unavailablelistitem;
1282                 }
1283                 $out .= $this->output->notification(get_string('misdepsunavaillist', 'core_plugin',
1284                     implode($unavailablelist, ', ')));
1285             }
1286             $out .= $this->output->container_start('plugins-check-dependencies-actions');
1287             $out .= ' '.html_writer::link(new moodle_url('/admin/tool/installaddon/'),
1288                 get_string('dependencyuploadmissing', 'core_plugin'));
1289             $out .= $this->output->container_end(); // End of .plugins-check-dependencies-actions container.
1290         }
1292         if ($available) {
1293             $out .= $this->output->heading(get_string('misdepsavail', 'core_plugin'));
1294             $out .= $this->output->container_start('plugins-check-dependencies-actions');
1296             $installable = $pluginman->filter_installable($available);
1297             if ($installable) {
1298                 $out .= $this->output->single_button(
1299                     new moodle_url($this->page->url, array('installdepx' => 1)),
1300                     get_string('dependencyinstallmissing', 'core_plugin', count($installable)),
1301                     'post',
1302                     array('class' => 'singlebutton dependencyinstallmissing')
1303                 );
1304             }
1306             $out .= html_writer::div(html_writer::link(new moodle_url('/admin/tool/installaddon/'),
1307                 get_string('dependencyuploadmissing', 'core_plugin')), 'dependencyuploadmissing');
1309             $out .= $this->output->container_end(); // End of .plugins-check-dependencies-actions container.
1311             $out .= $this->available_missing_dependencies_list($pluginman, $available);
1312         }
1314         $out .= $this->output->container_end(); // End of .plugins-check-dependencies container.
1316         return $out;
1317     }
1319     /**
1320      * Displays the list if available missing dependencies.
1321      *
1322      * @param core_plugin_manager $pluginman
1323      * @param array $dependencies
1324      * @return string
1325      */
1326     protected function available_missing_dependencies_list(core_plugin_manager $pluginman, array $dependencies) {
1327         global $CFG;
1329         $table = new html_table();
1330         $table->id = 'plugins-check-available-dependencies';
1331         $table->head = array(
1332             get_string('displayname', 'core_plugin'),
1333             get_string('release', 'core_plugin'),
1334             get_string('version', 'core_plugin'),
1335             get_string('supportedmoodleversions', 'core_plugin'),
1336             get_string('info', 'core'),
1337         );
1338         $table->colclasses = array('displayname', 'release', 'version', 'supportedmoodleversions', 'info');
1339         $table->data = array();
1341         foreach ($dependencies as $plugin) {
1343             $supportedmoodles = array();
1344             foreach ($plugin->version->supportedmoodles as $moodle) {
1345                 if ($CFG->branch == str_replace('.', '', $moodle->release)) {
1346                     $supportedmoodles[] = html_writer::span($moodle->release, 'label label-success');
1347                 } else {
1348                     $supportedmoodles[] = html_writer::span($moodle->release, 'label');
1349                 }
1350             }
1352             $requriedby = $pluginman->other_plugins_that_require($plugin->component);
1353             if ($requriedby) {
1354                 foreach ($requriedby as $ix => $val) {
1355                     $inf = $pluginman->get_plugin_info($val);
1356                     if ($inf) {
1357                         $requriedby[$ix] = $inf->displayname.' ('.$inf->component.')';
1358                     }
1359                 }
1360                 $info = html_writer::div(
1361                     get_string('requiredby', 'core_plugin', implode(', ', $requriedby)),
1362                     'requiredby'
1363                 );
1364             } else {
1365                 $info = '';
1366             }
1368             $info .= $this->output->container_start('actions');
1370             $info .= html_writer::div(
1371                 html_writer::link('https://moodle.org/plugins/view.php?plugin='.$plugin->component,
1372                     get_string('misdepinfoplugin', 'core_plugin')),
1373                 'misdepinfoplugin'
1374             );
1376             $info .= html_writer::div(
1377                 html_writer::link('https://moodle.org/plugins/pluginversion.php?id='.$plugin->version->id,
1378                     get_string('misdepinfoversion', 'core_plugin')),
1379                 'misdepinfoversion'
1380             );
1382             $info .= html_writer::div(html_writer::link($plugin->version->downloadurl, get_string('download')), 'misdepdownload');
1384             if ($pluginman->is_remote_plugin_installable($plugin->component, $plugin->version->version, $reason)) {
1385                 $info .= $this->output->single_button(
1386                     new moodle_url($this->page->url, array('installdep' => $plugin->component)),
1387                     get_string('dependencyinstall', 'core_plugin'),
1388                     'post',
1389                     array('class' => 'singlebutton dependencyinstall')
1390                 );
1391             } else {
1392                 $reasonhelp = $this->info_remote_plugin_not_installable($reason);
1393                 if ($reasonhelp) {
1394                     $info .= html_writer::div($reasonhelp, 'reasonhelp dependencyinstall');
1395                 }
1396             }
1398             $info .= $this->output->container_end(); // End of .actions container.
1400             $table->data[] = array(
1401                 html_writer::div($plugin->name, 'name').' '.html_writer::div($plugin->component, 'component'),
1402                 $plugin->version->release,
1403                 $plugin->version->version,
1404                 implode($supportedmoodles, ' '),
1405                 $info
1406             );
1407         }
1409         return html_writer::table($table);
1410     }
1412     /**
1413      * Explain why {@link core_plugin_manager::is_remote_plugin_installable()} returned false.
1414      *
1415      * @param string $reason the reason code as returned by the plugin manager
1416      * @return string
1417      */
1418     protected function info_remote_plugin_not_installable($reason) {
1420         if ($reason === 'notwritableplugintype' or $reason === 'notwritableplugin') {
1421             return $this->output->help_icon('notwritable', 'core_plugin', get_string('notwritable', 'core_plugin'));
1422         }
1424         if ($reason === 'remoteunavailable') {
1425             return $this->output->help_icon('notdownloadable', 'core_plugin', get_string('notdownloadable', 'core_plugin'));
1426         }
1428         return false;
1429     }
1431     /**
1432      * Formats the information that needs to go in the 'Requires' column.
1433      * @param \core\plugininfo\base $plugin the plugin we are rendering the row for.
1434      * @param core_plugin_manager $pluginman provides data on all the plugins.
1435      * @param string $version
1436      * @return string HTML code
1437      */
1438     protected function required_column(\core\plugininfo\base $plugin, core_plugin_manager $pluginman, $version) {
1440         $requires = array();
1441         $displayuploadlink = false;
1442         $displayupdateslink = false;
1444         foreach ($pluginman->resolve_requirements($plugin, $version) as $reqname => $reqinfo) {
1445             if ($reqname === 'core') {
1446                 if ($reqinfo->status == $pluginman::REQUIREMENT_STATUS_OK) {
1447                     $class = 'requires-ok';
1448                     $label = '';
1449                 } else {
1450                     $class = 'requires-failed';
1451                     $label = html_writer::span(get_string('dependencyfails', 'core_plugin'), 'label label-important');
1452                 }
1453                 $requires[] = html_writer::tag('li',
1454                     html_writer::span(get_string('moodleversion', 'core_plugin', $plugin->versionrequires), 'dep dep-core').
1455                     ' '.$label, array('class' => $class));
1457             } else {
1458                 $actions = array();
1460                 if ($reqinfo->status == $pluginman::REQUIREMENT_STATUS_OK) {
1461                     $label = '';
1462                     $class = 'requires-ok';
1464                 } else if ($reqinfo->status == $pluginman::REQUIREMENT_STATUS_MISSING) {
1465                     if ($reqinfo->availability == $pluginman::REQUIREMENT_AVAILABLE) {
1466                         $label = html_writer::span(get_string('dependencymissing', 'core_plugin'), 'label label-warning');
1467                         $label .= ' '.html_writer::span(get_string('dependencyavailable', 'core_plugin'), 'label label-warning');
1468                         $class = 'requires-failed requires-missing requires-available';
1469                         $actions[] = html_writer::link(
1470                             new moodle_url('https://moodle.org/plugins/view.php', array('plugin' => $reqname)),
1471                             get_string('misdepinfoplugin', 'core_plugin')
1472                         );
1474                     } else {
1475                         $label = html_writer::span(get_string('dependencymissing', 'core_plugin'), 'label label-important');
1476                         $label .= ' '.html_writer::span(get_string('dependencyunavailable', 'core_plugin'),
1477                             'label label-important');
1478                         $class = 'requires-failed requires-missing requires-unavailable';
1479                     }
1480                     $displayuploadlink = true;
1482                 } else if ($reqinfo->status == $pluginman::REQUIREMENT_STATUS_OUTDATED) {
1483                     if ($reqinfo->availability == $pluginman::REQUIREMENT_AVAILABLE) {
1484                         $label = html_writer::span(get_string('dependencyfails', 'core_plugin'), 'label label-warning');
1485                         $label .= ' '.html_writer::span(get_string('dependencyavailable', 'core_plugin'), 'label label-warning');
1486                         $class = 'requires-failed requires-outdated requires-available';
1487                         $displayupdateslink = true;
1489                     } else {
1490                         $label = html_writer::span(get_string('dependencyfails', 'core_plugin'), 'label label-important');
1491                         $label .= ' '.html_writer::span(get_string('dependencyunavailable', 'core_plugin'),
1492                             'label label-important');
1493                         $class = 'requires-failed requires-outdated requires-unavailable';
1494                     }
1495                     $displayuploadlink = true;
1496                 }
1498                 if ($reqinfo->reqver != ANY_VERSION) {
1499                     $str = 'otherpluginversion';
1500                 } else {
1501                     $str = 'otherplugin';
1502                 }
1504                 $requires[] = html_writer::tag('li', html_writer::span(
1505                     get_string($str, 'core_plugin', array('component' => $reqname, 'version' => $reqinfo->reqver)),
1506                     'dep dep-plugin').' '.$label.' '.html_writer::span(implode(' | ', $actions), 'actions'),
1507                     array('class' => $class)
1508                 );
1509             }
1510         }
1512         if (!$requires) {
1513             return '';
1514         }
1516         $out = html_writer::tag('ul', implode("\n", $requires));
1518         if ($displayuploadlink) {
1519             $out .= html_writer::div(
1520                 html_writer::link(
1521                     new moodle_url('/admin/tool/installaddon/'),
1522                     get_string('dependencyuploadmissing', 'core_plugin')
1523                 ),
1524                 'dependencyuploadmissing'
1525             );
1526         }
1528         if ($displayupdateslink) {
1529             $out .= html_writer::div(
1530                 html_writer::link(
1531                     new moodle_url($this->page->url, array('sesskey' => sesskey(), 'fetchupdates' => 1)),
1532                     get_string('checkforupdates', 'core_plugin')
1533                 ),
1534                 'checkforupdates'
1535             );
1536         }
1538         return $out;
1540     }
1542     /**
1543      * Prints an overview about the plugins - number of installed, number of extensions etc.
1544      *
1545      * @param core_plugin_manager $pluginman provides information about the plugins
1546      * @param array $options filtering options
1547      * @return string as usually
1548      */
1549     public function plugins_overview_panel(core_plugin_manager $pluginman, array $options = array()) {
1551         $plugininfo = $pluginman->get_plugins();
1553         $numtotal = $numextension = $numupdatable = 0;
1555         foreach ($plugininfo as $type => $plugins) {
1556             foreach ($plugins as $name => $plugin) {
1557                 if ($plugin->available_updates()) {
1558                     $numupdatable++;
1559                 }
1560                 if ($plugin->get_status() === core_plugin_manager::PLUGIN_STATUS_MISSING) {
1561                     continue;
1562                 }
1563                 $numtotal++;
1564                 if (!$plugin->is_standard()) {
1565                     $numextension++;
1566                 }
1567             }
1568         }
1570         $infoall = html_writer::link(
1571             new moodle_url($this->page->url, array('contribonly' => 0, 'updatesonly' => 0)),
1572             get_string('overviewall', 'core_plugin'),
1573             array('title' => get_string('filterall', 'core_plugin'))
1574         ).' '.html_writer::span($numtotal, 'badge number number-all');
1576         $infoext = html_writer::link(
1577             new moodle_url($this->page->url, array('contribonly' => 1, 'updatesonly' => 0)),
1578             get_string('overviewext', 'core_plugin'),
1579             array('title' => get_string('filtercontribonly', 'core_plugin'))
1580         ).' '.html_writer::span($numextension, 'badge number number-additional');
1582         if ($numupdatable) {
1583             $infoupdatable = html_writer::link(
1584                 new moodle_url($this->page->url, array('contribonly' => 0, 'updatesonly' => 1)),
1585                 get_string('overviewupdatable', 'core_plugin'),
1586                 array('title' => get_string('filterupdatesonly', 'core_plugin'))
1587             ).' '.html_writer::span($numupdatable, 'badge badge-info number number-updatable');
1588         } else {
1589             // No updates, or the notifications disabled.
1590             $infoupdatable = '';
1591         }
1593         $out = html_writer::start_div('', array('id' => 'plugins-overview-panel'));
1595         if (!empty($options['updatesonly'])) {
1596             $out .= $this->output->heading(get_string('overviewupdatable', 'core_plugin'), 3);
1597         } else if (!empty($options['contribonly'])) {
1598             $out .= $this->output->heading(get_string('overviewext', 'core_plugin'), 3);
1599         }
1601         if ($numupdatable) {
1602             $installableupdates = $pluginman->filter_installable($pluginman->available_updates());
1603             if ($installableupdates) {
1604                 $out .= $this->output->single_button(
1605                     new moodle_url($this->page->url, array('installupdatex' => 1)),
1606                     get_string('updateavailableinstallall', 'core_admin', count($installableupdates)),
1607                     'post',
1608                     array('class' => 'singlebutton updateavailableinstallall')
1609                 );
1610             }
1611         }
1613         $out .= html_writer::div($infoall, 'info info-all').
1614             html_writer::div($infoext, 'info info-ext').
1615             html_writer::div($infoupdatable, 'info info-updatable');
1617         $out .= html_writer::end_div(); // End of #plugins-overview-panel block.
1619         return $out;
1620     }
1622     /**
1623      * Displays all known plugins and links to manage them
1624      *
1625      * This default implementation renders all plugins into one big table.
1626      *
1627      * @param core_plugin_manager $pluginman provides information about the plugins.
1628      * @param array $options filtering options
1629      * @return string HTML code
1630      */
1631     public function plugins_control_panel(core_plugin_manager $pluginman, array $options = array()) {
1633         $plugininfo = $pluginman->get_plugins();
1635         // Filter the list of plugins according the options.
1636         if (!empty($options['updatesonly'])) {
1637             $updateable = array();
1638             foreach ($plugininfo as $plugintype => $pluginnames) {
1639                 foreach ($pluginnames as $pluginname => $pluginfo) {
1640                     $pluginavailableupdates = $pluginfo->available_updates();
1641                     if (!empty($pluginavailableupdates)) {
1642                         foreach ($pluginavailableupdates as $pluginavailableupdate) {
1643                             $updateable[$plugintype][$pluginname] = $pluginfo;
1644                         }
1645                     }
1646                 }
1647             }
1648             $plugininfo = $updateable;
1649         }
1651         if (!empty($options['contribonly'])) {
1652             $contribs = array();
1653             foreach ($plugininfo as $plugintype => $pluginnames) {
1654                 foreach ($pluginnames as $pluginname => $pluginfo) {
1655                     if (!$pluginfo->is_standard()) {
1656                         $contribs[$plugintype][$pluginname] = $pluginfo;
1657                     }
1658                 }
1659             }
1660             $plugininfo = $contribs;
1661         }
1663         if (empty($plugininfo)) {
1664             return '';
1665         }
1667         $table = new html_table();
1668         $table->id = 'plugins-control-panel';
1669         $table->head = array(
1670             get_string('displayname', 'core_plugin'),
1671             get_string('version', 'core_plugin'),
1672             get_string('availability', 'core_plugin'),
1673             get_string('actions', 'core_plugin'),
1674             get_string('notes','core_plugin'),
1675         );
1676         $table->headspan = array(1, 1, 1, 2, 1);
1677         $table->colclasses = array(
1678             'pluginname', 'version', 'availability', 'settings', 'uninstall', 'notes'
1679         );
1681         foreach ($plugininfo as $type => $plugins) {
1682             $heading = $pluginman->plugintype_name_plural($type);
1683             $pluginclass = core_plugin_manager::resolve_plugininfo_class($type);
1684             if ($manageurl = $pluginclass::get_manage_url()) {
1685                 $heading .= $this->output->action_icon($manageurl, new pix_icon('i/settings',
1686                     get_string('settings', 'core_plugin')));
1687             }
1688             $header = new html_table_cell(html_writer::tag('span', $heading, array('id'=>'plugin_type_cell_'.$type)));
1689             $header->header = true;
1690             $header->colspan = array_sum($table->headspan);
1691             $header = new html_table_row(array($header));
1692             $header->attributes['class'] = 'plugintypeheader type-' . $type;
1693             $table->data[] = $header;
1695             if (empty($plugins)) {
1696                 $msg = new html_table_cell(get_string('noneinstalled', 'core_plugin'));
1697                 $msg->colspan = array_sum($table->headspan);
1698                 $row = new html_table_row(array($msg));
1699                 $row->attributes['class'] .= 'msg msg-noneinstalled';
1700                 $table->data[] = $row;
1701                 continue;
1702             }
1704             foreach ($plugins as $name => $plugin) {
1705                 $row = new html_table_row();
1706                 $row->attributes['class'] = 'type-' . $plugin->type . ' name-' . $plugin->type . '_' . $plugin->name;
1708                 if ($this->page->theme->resolve_image_location('icon', $plugin->type . '_' . $plugin->name, null)) {
1709                     $icon = $this->output->pix_icon('icon', '', $plugin->type . '_' . $plugin->name, array('class' => 'icon pluginicon'));
1710                 } else {
1711                     $icon = $this->output->spacer();
1712                 }
1713                 $status = $plugin->get_status();
1714                 $row->attributes['class'] .= ' status-'.$status;
1715                 $pluginname  = html_writer::tag('div', $icon.$plugin->displayname, array('class' => 'displayname')).
1716                                html_writer::tag('div', $plugin->component, array('class' => 'componentname'));
1717                 $pluginname  = new html_table_cell($pluginname);
1719                 $version = html_writer::div($plugin->versiondb, 'versionnumber');
1720                 if ((string)$plugin->release !== '') {
1721                     $version = html_writer::div($plugin->release, 'release').$version;
1722                 }
1723                 $version = new html_table_cell($version);
1725                 $isenabled = $plugin->is_enabled();
1726                 if (is_null($isenabled)) {
1727                     $availability = new html_table_cell('');
1728                 } else if ($isenabled) {
1729                     $row->attributes['class'] .= ' enabled';
1730                     $availability = new html_table_cell(get_string('pluginenabled', 'core_plugin'));
1731                 } else {
1732                     $row->attributes['class'] .= ' disabled';
1733                     $availability = new html_table_cell(get_string('plugindisabled', 'core_plugin'));
1734                 }
1736                 $settingsurl = $plugin->get_settings_url();
1737                 if (!is_null($settingsurl)) {
1738                     $settings = html_writer::link($settingsurl, get_string('settings', 'core_plugin'), array('class' => 'settings'));
1739                 } else {
1740                     $settings = '';
1741                 }
1742                 $settings = new html_table_cell($settings);
1744                 if ($uninstallurl = $pluginman->get_uninstall_url($plugin->component, 'overview')) {
1745                     $uninstall = html_writer::link($uninstallurl, get_string('uninstall', 'core_plugin'));
1746                 } else {
1747                     $uninstall = '';
1748                 }
1749                 $uninstall = new html_table_cell($uninstall);
1751                 if ($plugin->is_standard()) {
1752                     $row->attributes['class'] .= ' standard';
1753                     $source = '';
1754                 } else {
1755                     $row->attributes['class'] .= ' extension';
1756                     $source = html_writer::div(get_string('sourceext', 'core_plugin'), 'source label label-info');
1757                 }
1759                 if ($status === core_plugin_manager::PLUGIN_STATUS_MISSING) {
1760                     $msg = html_writer::div(get_string('status_missing', 'core_plugin'), 'statusmsg label label-important');
1761                 } else if ($status === core_plugin_manager::PLUGIN_STATUS_NEW) {
1762                     $msg = html_writer::div(get_string('status_new', 'core_plugin'), 'statusmsg label label-success');
1763                 } else {
1764                     $msg = '';
1765                 }
1767                 $requriedby = $pluginman->other_plugins_that_require($plugin->component);
1768                 if ($requriedby) {
1769                     $requiredby = html_writer::tag('div', get_string('requiredby', 'core_plugin', implode(', ', $requriedby)),
1770                         array('class' => 'requiredby'));
1771                 } else {
1772                     $requiredby = '';
1773                 }
1775                 $updateinfo = '';
1776                 if (is_array($plugin->available_updates())) {
1777                     foreach ($plugin->available_updates() as $availableupdate) {
1778                         $updateinfo .= $this->plugin_available_update_info($pluginman, $availableupdate);
1779                     }
1780                 }
1782                 $notes = new html_table_cell($source.$msg.$requiredby.$updateinfo);
1784                 $row->cells = array(
1785                     $pluginname, $version, $availability, $settings, $uninstall, $notes
1786                 );
1787                 $table->data[] = $row;
1788             }
1789         }
1791         return html_writer::table($table);
1792     }
1794     /**
1795      * Helper method to render the information about the available plugin update
1796      *
1797      * @param core_plugin_manager $pluginman plugin manager instance
1798      * @param \core\update\info $updateinfo information about the available update for the plugin
1799      */
1800     protected function plugin_available_update_info(core_plugin_manager $pluginman, \core\update\info $updateinfo) {
1802         $boxclasses = 'pluginupdateinfo';
1803         $info = array();
1805         if (isset($updateinfo->release)) {
1806             $info[] = html_writer::div(
1807                 get_string('updateavailable_release', 'core_plugin', $updateinfo->release),
1808                 'info release'
1809             );
1810         }
1812         if (isset($updateinfo->maturity)) {
1813             $info[] = html_writer::div(
1814                 get_string('maturity'.$updateinfo->maturity, 'core_admin'),
1815                 'info maturity'
1816             );
1817             $boxclasses .= ' maturity'.$updateinfo->maturity;
1818         }
1820         if (isset($updateinfo->download)) {
1821             $info[] = html_writer::div(
1822                 html_writer::link($updateinfo->download, get_string('download')),
1823                 'info download'
1824             );
1825         }
1827         if (isset($updateinfo->url)) {
1828             $info[] = html_writer::div(
1829                 html_writer::link($updateinfo->url, get_string('updateavailable_moreinfo', 'core_plugin')),
1830                 'info more'
1831             );
1832         }
1834         $box = html_writer::start_div($boxclasses);
1835         $box .= html_writer::div(
1836             get_string('updateavailable', 'core_plugin', $updateinfo->version),
1837             'version'
1838         );
1839         $box .= html_writer::div(
1840             implode(html_writer::span(' ', 'separator'), $info),
1841             'infos'
1842         );
1844         if ($pluginman->is_remote_plugin_installable($updateinfo->component, $updateinfo->version, $reason)) {
1845             $box .= $this->output->single_button(
1846                 new moodle_url($this->page->url, array('installupdate' => $updateinfo->component,
1847                     'installupdateversion' => $updateinfo->version)),
1848                 get_string('updateavailableinstall', 'core_admin'),
1849                 'post',
1850                 array('class' => 'singlebutton updateavailableinstall')
1851             );
1852         } else {
1853             $reasonhelp = $this->info_remote_plugin_not_installable($reason);
1854             if ($reasonhelp) {
1855                 $box .= html_writer::div($reasonhelp, 'reasonhelp updateavailableinstall');
1856             }
1857         }
1858         $box .= html_writer::end_div();
1860         return $box;
1861     }
1863     /**
1864      * This function will render one beautiful table with all the environmental
1865      * configuration and how it suits Moodle needs.
1866      *
1867      * @param boolean $result final result of the check (true/false)
1868      * @param environment_results[] $environment_results array of results gathered
1869      * @return string HTML to output.
1870      */
1871     public function environment_check_table($result, $environment_results) {
1872         global $CFG;
1874         // Table headers
1875         $servertable = new html_table();//table for server checks
1876         $servertable->head  = array(
1877             get_string('name'),
1878             get_string('info'),
1879             get_string('report'),
1880             get_string('plugin'),
1881             get_string('status'),
1882         );
1883         $servertable->colclasses = array('centeralign name', 'centeralign info', 'leftalign report', 'leftalign plugin', 'centeralign status');
1884         $servertable->attributes['class'] = 'admintable environmenttable generaltable';
1885         $servertable->id = 'serverstatus';
1887         $serverdata = array('ok'=>array(), 'warn'=>array(), 'error'=>array());
1889         $othertable = new html_table();//table for custom checks
1890         $othertable->head  = array(
1891             get_string('info'),
1892             get_string('report'),
1893             get_string('plugin'),
1894             get_string('status'),
1895         );
1896         $othertable->colclasses = array('aligncenter info', 'alignleft report', 'alignleft plugin', 'aligncenter status');
1897         $othertable->attributes['class'] = 'admintable environmenttable generaltable';
1898         $othertable->id = 'otherserverstatus';
1900         $otherdata = array('ok'=>array(), 'warn'=>array(), 'error'=>array());
1902         // Iterate over each environment_result
1903         $continue = true;
1904         foreach ($environment_results as $environment_result) {
1905             $errorline   = false;
1906             $warningline = false;
1907             $stringtouse = '';
1908             if ($continue) {
1909                 $type = $environment_result->getPart();
1910                 $info = $environment_result->getInfo();
1911                 $status = $environment_result->getStatus();
1912                 $plugin = $environment_result->getPluginName();
1913                 $error_code = $environment_result->getErrorCode();
1914                 // Process Report field
1915                 $rec = new stdClass();
1916                 // Something has gone wrong at parsing time
1917                 if ($error_code) {
1918                     $stringtouse = 'environmentxmlerror';
1919                     $rec->error_code = $error_code;
1920                     $status = get_string('error');
1921                     $errorline = true;
1922                     $continue = false;
1923                 }
1925                 if ($continue) {
1926                     if ($rec->needed = $environment_result->getNeededVersion()) {
1927                         // We are comparing versions
1928                         $rec->current = $environment_result->getCurrentVersion();
1929                         if ($environment_result->getLevel() == 'required') {
1930                             $stringtouse = 'environmentrequireversion';
1931                         } else {
1932                             $stringtouse = 'environmentrecommendversion';
1933                         }
1935                     } else if ($environment_result->getPart() == 'custom_check') {
1936                         // We are checking installed & enabled things
1937                         if ($environment_result->getLevel() == 'required') {
1938                             $stringtouse = 'environmentrequirecustomcheck';
1939                         } else {
1940                             $stringtouse = 'environmentrecommendcustomcheck';
1941                         }
1943                     } else if ($environment_result->getPart() == 'php_setting') {
1944                         if ($status) {
1945                             $stringtouse = 'environmentsettingok';
1946                         } else if ($environment_result->getLevel() == 'required') {
1947                             $stringtouse = 'environmentmustfixsetting';
1948                         } else {
1949                             $stringtouse = 'environmentshouldfixsetting';
1950                         }
1952                     } else {
1953                         if ($environment_result->getLevel() == 'required') {
1954                             $stringtouse = 'environmentrequireinstall';
1955                         } else {
1956                             $stringtouse = 'environmentrecommendinstall';
1957                         }
1958                     }
1960                     // Calculate the status value
1961                     if ($environment_result->getBypassStr() != '') {            //Handle bypassed result (warning)
1962                         $status = get_string('bypassed');
1963                         $warningline = true;
1964                     } else if ($environment_result->getRestrictStr() != '') {   //Handle restricted result (error)
1965                         $status = get_string('restricted');
1966                         $errorline = true;
1967                     } else {
1968                         if ($status) {                                          //Handle ok result (ok)
1969                             $status = get_string('ok');
1970                         } else {
1971                             if ($environment_result->getLevel() == 'optional') {//Handle check result (warning)
1972                                 $status = get_string('check');
1973                                 $warningline = true;
1974                             } else {                                            //Handle error result (error)
1975                                 $status = get_string('check');
1976                                 $errorline = true;
1977                             }
1978                         }
1979                     }
1980                 }
1982                 // Build the text
1983                 $linkparts = array();
1984                 $linkparts[] = 'admin/environment';
1985                 $linkparts[] = $type;
1986                 if (!empty($info)){
1987                    $linkparts[] = $info;
1988                 }
1989                 // Plugin environments do not have docs pages yet.
1990                 if (empty($CFG->docroot) or $environment_result->plugin) {
1991                     $report = get_string($stringtouse, 'admin', $rec);
1992                 } else {
1993                     $report = $this->doc_link(join($linkparts, '/'), get_string($stringtouse, 'admin', $rec));
1994                 }
1995                 // Enclose report text in div so feedback text will be displayed underneath it.
1996                 $report = html_writer::div($report);
1998                 // Format error or warning line
1999                 if ($errorline) {
2000                     $messagetype = 'error';
2001                     $statusclass = 'label-important';
2002                 } else if ($warningline) {
2003                     $messagetype = 'warn';
2004                     $statusclass = 'label-warning';
2005                 } else {
2006                     $messagetype = 'ok';
2007                     $statusclass = 'label-success';
2008                 }
2009                 $status = html_writer::span($status, 'label ' . $statusclass);
2010                 // Here we'll store all the feedback found
2011                 $feedbacktext = '';
2012                 // Append the feedback if there is some
2013                 $feedbacktext .= $environment_result->strToReport($environment_result->getFeedbackStr(), $messagetype);
2014                 //Append the bypass if there is some
2015                 $feedbacktext .= $environment_result->strToReport($environment_result->getBypassStr(), 'warn');
2016                 //Append the restrict if there is some
2017                 $feedbacktext .= $environment_result->strToReport($environment_result->getRestrictStr(), 'error');
2019                 $report .= $feedbacktext;
2021                 // Add the row to the table
2022                 if ($environment_result->getPart() == 'custom_check'){
2023                     $otherdata[$messagetype][] = array ($info, $report, $plugin, $status);
2024                 } else {
2025                     $serverdata[$messagetype][] = array ($type, $info, $report, $plugin, $status);
2026                 }
2027             }
2028         }
2030         //put errors first in
2031         $servertable->data = array_merge($serverdata['error'], $serverdata['warn'], $serverdata['ok']);
2032         $othertable->data = array_merge($otherdata['error'], $otherdata['warn'], $otherdata['ok']);
2034         // Print table
2035         $output = '';
2036         $output .= $this->heading(get_string('serverchecks', 'admin'));
2037         $output .= html_writer::table($servertable);
2038         if (count($othertable->data)){
2039             $output .= $this->heading(get_string('customcheck', 'admin'));
2040             $output .= html_writer::table($othertable);
2041         }
2043         // Finally, if any error has happened, print the summary box
2044         if (!$result) {
2045             $output .= $this->box(get_string('environmenterrortodo', 'admin'), 'environmentbox errorbox');
2046         }
2048         return $output;
2049     }
2051     /**
2052      * Render a simple page for providing the upgrade key.
2053      *
2054      * @param moodle_url|string $url
2055      * @return string
2056      */
2057     public function upgradekey_form_page($url) {
2059         $output = '';
2060         $output .= $this->header();
2061         $output .= $this->container_start('upgradekeyreq');
2062         $output .= $this->heading(get_string('upgradekeyreq', 'core_admin'));
2063         $output .= html_writer::start_tag('form', array('method' => 'POST', 'action' => $url));
2064         $output .= html_writer::empty_tag('input', array('name' => 'upgradekey', 'type' => 'password'));
2065         $output .= html_writer::empty_tag('input', array('value' => get_string('submit'), 'type' => 'submit'));
2066         $output .= html_writer::end_tag('form');
2067         $output .= $this->container_end();
2068         $output .= $this->footer();
2070         return $output;
2071     }
2073     /**
2074      * Check to see if writing to the deprecated legacy log store is enabled.
2075      *
2076      * @return string An error message if writing to the legacy log store is enabled.
2077      */
2078     protected function legacy_log_store_writing_error() {
2079         $enabled = get_config('logstore_legacy', 'loglegacy');
2080         $plugins = explode(',', get_config('tool_log', 'enabled_stores'));
2081         $enabled = $enabled && in_array('logstore_legacy', $plugins);
2083         if ($enabled) {
2084             return $this->warning(get_string('legacylogginginuse'));
2085         }
2086     }