first commit

This commit is contained in:
CHIEFSOFT\ameye
2024-09-30 18:11:26 -04:00
commit e592ca6823
27270 changed files with 5002257 additions and 0 deletions
+347
View File
@@ -0,0 +1,347 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace core\progress;
defined('MOODLE_INTERNAL') || die();
/**
* Base class for handling progress information.
*
* Subclasses should generally override the {@link current_progress} function which
* summarises all progress information.
*
* @package core_progress
* @copyright 2013 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
abstract class base {
/**
* @var int Constant indicating that the number of progress calls is unknown.
*/
const INDETERMINATE = -1;
/**
* This value is set rather high to ensure there are no regressions from
* previous behaviour. For testing, it may be useful to set the
* frontendservertimeout config option to a lower value, such as 180
* seconds (default for some commercial products).
*
* @var int The number of seconds that can pass without {@link progress()} calls.
*/
const TIME_LIMIT_WITHOUT_PROGRESS = 3600;
/**
* @var int Time of last progress call.
*/
protected $lastprogresstime;
/**
* @var int Number of progress calls (restricted to ~ 1/second).
*/
protected $count;
/**
* @var array Array of progress descriptions for each stack level.
*/
protected $descriptions = array();
/**
* @var array Array of maximum progress values for each stack level.
*/
protected $maxes = array();
/**
* @var array Array of current progress values.
*/
protected $currents = array();
/**
* @var int[] Array of counts within parent progress entry (ignored for first)
*/
protected $parentcounts = array();
/**
* Marks the start of an operation that will display progress.
*
* This can be called multiple times for nested progress sections. It must
* be paired with calls to end_progress.
*
* The progress maximum may be {@link self::INDETERMINATE} if the current operation has
* an unknown number of steps. (This is default.)
*
* Calling this function will always result in a new display, so this
* should not be called exceedingly frequently.
*
* When it is complete by calling {@link end_progress()}, each {@link start_progress} section
* automatically adds progress to its parent, as defined by $parentcount.
*
* @param string $description Description to display
* @param int $max Maximum value of progress for this section
* @param int $parentcount How many progress points this section counts for
* @throws \coding_exception If max is invalid
*/
public function start_progress($description, $max = self::INDETERMINATE,
$parentcount = 1) {
if ($max != self::INDETERMINATE && $max < 0) {
throw new \coding_exception(
'start_progress() max value cannot be negative');
}
if ($parentcount < 1) {
throw new \coding_exception(
'start_progress() parent progress count must be at least 1');
}
if (!empty($this->descriptions)) {
$prevmax = end($this->maxes);
if ($prevmax !== self::INDETERMINATE) {
$prevcurrent = end($this->currents);
if ($prevcurrent + $parentcount > $prevmax) {
throw new \coding_exception(
'start_progress() parent progress would exceed max');
}
}
} else {
if ($parentcount != 1) {
throw new \coding_exception(
'start_progress() progress count must be 1 when no parent');
}
}
$this->descriptions[] = $description;
$this->maxes[] = $max;
$this->currents[] = 0;
$this->parentcounts[] = $parentcount;
$this->update_progress();
}
/**
* Marks the end of an operation that will display progress.
*
* This must be paired with each {@link start_progress} call.
*
* If there is a parent progress section, its progress will be increased
* automatically to reflect the end of the child section.
*
* @throws \coding_exception If progress hasn't been started
*/
public function end_progress() {
if (!count($this->descriptions)) {
throw new \coding_exception('end_progress() without start_progress()');
}
array_pop($this->descriptions);
array_pop($this->maxes);
array_pop($this->currents);
$parentcount = array_pop($this->parentcounts);
if (!empty($this->descriptions)) {
$lastmax = end($this->maxes);
if ($lastmax != self::INDETERMINATE) {
$lastvalue = end($this->currents);
$this->currents[key($this->currents)] = $lastvalue + $parentcount;
}
}
$this->update_progress();
}
/**
* Indicates that progress has occurred.
*
* The progress value should indicate the total progress so far, from 0
* to the value supplied for $max (inclusive) in {@link start_progress}.
*
* You do not need to call this function for every value. It is OK to skip
* values. It is also OK to call this function as often as desired; it
* doesn't update the display if called more than once per second.
*
* It must be INDETERMINATE if {@link start_progress} was called with $max set to
* INDETERMINATE. Otherwise it must not be indeterminate.
*
* @param int $progress Progress so far
* @throws \coding_exception If progress value is invalid
*/
public function progress($progress = self::INDETERMINATE) {
// Check we are inside a progress section.
$max = end($this->maxes);
if ($max === false) {
throw new \coding_exception(
'progress() without start_progress');
}
// Check and apply new progress.
if ($progress === self::INDETERMINATE) {
// Indeterminate progress.
if ($max !== self::INDETERMINATE) {
throw new \coding_exception(
'progress() INDETERMINATE, expecting value');
}
} else {
// Determinate progress.
$current = end($this->currents);
if ($max === self::INDETERMINATE) {
throw new \coding_exception(
'progress() with value, expecting INDETERMINATE');
} else if ($progress < 0 || $progress > $max) {
throw new \coding_exception(
'progress() value out of range');
} else if ($progress < $current) {
throw new \coding_exception(
'progress() value may not go backwards');
}
$this->currents[key($this->currents)] = $progress;
}
// Don't update progress bar too frequently (more than once per second).
$now = $this->get_time();
if ($now === $this->lastprogresstime) {
return;
}
// Update progress.
$this->count++;
$this->lastprogresstime = $now;
// Update time limit before next progress display.
\core_php_time_limit::raise(self::TIME_LIMIT_WITHOUT_PROGRESS);
$this->update_progress();
}
/**
* An alternative to calling progress. This keeps track of the number of items done internally. Call this method
* with no parameters to increment the internal counter by one or you can use the $incby parameter to specify a positive
* change in progress. The internal progress counter should not exceed $max as passed to {@link start_progress} for this
* section.
*
* If you called {@link start_progress} with parameter INDETERMINATE then you cannot call this method.
*
* @var int $incby The positive change to apply to the internal progress counter. Defaults to 1.
*/
public function increment_progress($incby = 1) {
$current = end($this->currents);
$this->progress($current + $incby);
}
/**
* Gets time (this is provided so that unit tests can override it).
*
* @return int Current system time
*/
protected function get_time() {
return time();
}
/**
* Called whenever new progress should be displayed.
*/
abstract protected function update_progress();
/**
* @return bool True if currently inside a progress section
*/
public function is_in_progress_section() {
return !empty($this->descriptions);
}
/**
* Checks max value of current progress section.
*
* @return int Current max value - may be {@link \core\progress\base::INDETERMINATE}.
* @throws \coding_exception If not in a progress section
*/
public function get_current_max() {
$max = end($this->maxes);
if ($max === false) {
throw new \coding_exception('Not inside progress section');
}
return $max;
}
/**
* @throws \coding_exception
* @return string Current progress section description
*/
public function get_current_description() {
$description = end($this->descriptions);
if ($description === false) {
throw new \coding_exception('Not inside progress section');
}
return $description;
}
/**
* Obtains current progress in a way suitable for drawing a progress bar.
*
* Progress is returned as a minimum and maximum value. If there is no
* indeterminate progress, these values will be identical. If there is
* intermediate progress, these values can be different. (For example, if
* the top level progress sections is indeterminate, then the values will
* always be 0.0 and 1.0.)
*
* @return array Minimum and maximum possible progress proportions
*/
public function get_progress_proportion_range() {
// If there is no progress underway, we must have finished.
if (empty($this->currents)) {
return array(1.0, 1.0);
}
$count = count($this->currents);
$min = 0.0;
$max = 1.0;
for ($i = 0; $i < $count; $i++) {
// Get max value at that section - if it's indeterminate we can tell
// no more.
$sectionmax = $this->maxes[$i];
if ($sectionmax === self::INDETERMINATE) {
return array($min, $max);
}
// Special case if current value is max (this should only happen
// just before ending a section).
$sectioncurrent = $this->currents[$i];
if ($sectioncurrent === $sectionmax) {
return array($max, $max);
}
// Using the current value at that section, we know we are somewhere
// between 'current' and the next 'current' value which depends on
// the parentcount of the nested section (if any).
$newmin = ($sectioncurrent / $sectionmax) * ($max - $min) + $min;
$nextcurrent = $sectioncurrent + 1;
if ($i + 1 < $count) {
$weight = $this->parentcounts[$i + 1];
$nextcurrent = $sectioncurrent + $weight;
}
$newmax = ($nextcurrent / $sectionmax) * ($max - $min) + $min;
$min = $newmin;
$max = $newmax;
}
// If there was nothing indeterminate, we use the min value as current.
return array($min, $min);
}
/**
* Obtains current indeterminate progress in a way suitable for adding to
* the progress display.
*
* This returns the number of indeterminate calls (at any level) during the
* lifetime of this progress reporter, whether or not there is a current
* indeterminate step. (The number will not be ridiculously high because
* progress calls are limited to one per second.)
*
* @return int Number of indeterminate progress calls
*/
public function get_progress_count() {
return $this->count;
}
}
+123
View File
@@ -0,0 +1,123 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Progress handler that updates a database table with the progress.
*
* @package core
* @copyright 2018 Matt Porritt <mattp@catalyst-au.net>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core\progress;
defined('MOODLE_INTERNAL') || die();
/**
* Progress handler that updates a database table with the progress.
*
* @package core
* @copyright 2018 Matt Porritt <mattp@catalyst-au.net>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class db_updater extends base {
/**
* The primary key of the database record to update.
*
* @var integer
*/
protected $recordid = 0;
/**
* The database table to insert the progress updates into.
*
* @var string
*/
protected $table = '';
/**
* The table field to update with the progress.
*
* @var string
*/
protected $field = '';
/**
* The maximum frequency in seconds to update the database (default 5 seconds).
* Lower values will increase database calls.
*
* @var integer
*/
protected $interval = 5;
/**
* The timestamp of when the next progress update to the database will be.
*
* @var integer
*/
protected $nextupdate = 0;
/**
* Constructs the progress reporter.
*
* @param int $recordid The primary key of the database record to update.
* @param string $table The databse table to insert the progress updates into.
* @param string $field The table field to update with the progress.
* @param int $interval The maximum frequency in seconds to update the database (default 5 seconds).
*/
public function __construct($recordid, $table, $field, $interval=5) {
$this->recordid = $recordid;
$this->table = $table;
$this->field = $field;
$this->interval = $interval;
}
/**
* Updates the progress in the database.
* Database update frequency is set by $interval.
*
* @see \core\progress\base::update_progress()
*/
public function update_progress() {
global $DB;
$now = $this->get_time();
$lastprogress = $this->lastprogresstime != 0 ? $this->lastprogresstime : $now;
$progressrecord = new \stdClass();
$progressrecord->id = $this->recordid;
$progressrecord->{$this->field} = '';
// Update database with progress.
if ($now > $this->nextupdate) { // Limit database updates based on time.
list ($min, $max) = $this->get_progress_proportion_range();
$progressrecord->{$this->field} = $min;
$DB->update_record($this->table, $progressrecord);
$this->nextupdate = $lastprogress + $this->interval;
}
// Set progress to 1 (100%) when there are no more progress updates.
// Their is no guarantee that the final update from the get progress method
// will be 1 even for a successful process. So we explicitly set the final DB
// value to 1 when we are no longer in progress.
if (!$this->is_in_progress_section()) {
$progressrecord->{$this->field} = 1;
$DB->update_record($this->table, $progressrecord);
}
}
}
+156
View File
@@ -0,0 +1,156 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace core\progress;
defined('MOODLE_INTERNAL') || die();
/**
* Progress handler that uses a standard Moodle progress bar to display
* progress. The Moodle progress bar cannot show indeterminate progress,
* so we do extra output in addition to the bar.
*
* @package core_progress
* @copyright 2013 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class display extends base {
/**
* @var int Number of wibble states (state0...stateN-1 classes in CSS)
*/
const WIBBLE_STATES = 13;
/**
* @var \progress_bar Current progress bar.
*/
private $bar;
protected $lastwibble, $currentstate = 0, $direction = 1;
/**
* @var bool True to display names
*/
protected $displaynames = false;
/**
* Constructs the progress reporter. This will output HTML code for the
* progress bar, and an indeterminate wibbler below it.
*
* @param bool $startnow If true, outputs HTML immediately.
*/
public function __construct($startnow = true) {
if ($startnow) {
$this->start_html();
}
}
/**
* By default, the progress section names do not display because
* these will probably be untranslated and incomprehensible. To make them
* display, call this method.
*
* @param bool $displaynames True to display names
*/
public function set_display_names($displaynames = true) {
$this->displaynames = $displaynames;
}
/**
* Starts to output progress.
*
* Called in constructor and in update_progress if required.
*
* @throws \coding_exception If already started
*/
public function start_html() {
if ($this->bar) {
throw new \coding_exception('Already started');
}
$this->bar = new \progress_bar();
$this->bar->create();
echo \html_writer::start_div('wibbler');
}
/**
* Finishes output. (Progress can begin again later if there are more
* calls to update_progress.)
*
* Automatically called from update_progress when progress finishes.
*/
public function end_html() {
// Finish progress bar.
$this->bar->update_full(100, '');
$this->bar = null;
// End wibbler div.
echo \html_writer::end_div();
}
/**
* When progress is updated, updates the bar.
*
* @see \core\progress\base::update_progress()
*/
public function update_progress() {
// If finished...
if (!$this->is_in_progress_section()) {
if ($this->bar) {
$this->end_html();
}
} else {
if (!$this->bar) {
$this->start_html();
}
// In case of indeterminate or small progress, update the wibbler
// (up to once per second).
if (time() != $this->lastwibble) {
$this->lastwibble = time();
echo \html_writer::div('', 'wibble state' . $this->currentstate);
// Go on to next colour.
$this->currentstate += $this->direction;
if ($this->currentstate < 0 || $this->currentstate >= self::WIBBLE_STATES) {
$this->direction = -$this->direction;
$this->currentstate += 2 * $this->direction;
}
$buffersize = ini_get('output_buffering');
if (!is_numeric($buffersize)) {
// The output_buffering setting can be a number, but can also be "On" or "Off".
// If "Off", there's no buffer, if "On", there's no limit to the size. In either case,
// there's no point in trying to fill the buffer.
$buffersize = 0;
}
if ($buffersize) {
// Force the buffer full.
echo str_pad('', $buffersize);
}
}
// Get progress.
list ($min, $max) = $this->get_progress_proportion_range();
// Update progress bar.
$message = '';
if ($this->displaynames) {
$message = $this->get_current_description();
}
$this->bar->update_full($min * 100, $message);
// Flush output.
flush();
}
}
}
+131
View File
@@ -0,0 +1,131 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace core\progress;
defined('MOODLE_INTERNAL') || die();
/**
* Progress handler that uses a standard Moodle progress bar to display
* progress. Same as \core\progress\display, but the bar does not
* appear until a certain time has elapsed, and disappears automatically
* after it finishes.
*
* The bar can be re-used, i.e. if you end all sections it will disappear,
* but if you start all sections, a new bar will be output.
*
* @package core_progress
* @copyright 2013 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class display_if_slow extends display {
/**
* @var int Waits this many seconds before displaying progress bar
*/
const DEFAULT_DISPLAY_DELAY = 5;
/**
* @var int Number in the next id to use
*/
private static $nextid = 1;
/**
* @var string HTML id for containing div
*/
protected $id;
/**
* @var string Text to display in heading if bar appears
*/
protected $heading;
/**
* @var int Time at which the progress bar should display (if it isn't yet)
*/
protected $starttime;
/**
* Constructs the progress reporter. This will not output HTML just yet,
* until the required delay time expires.
*
* @param string $heading Text to display above bar (if it appears); '' for none (default)
* @param int $delay Delay time (default 5 seconds)
*/
public function __construct($heading = '', $delay = self::DEFAULT_DISPLAY_DELAY) {
// Set start time based on delay.
$this->starttime = time() + $delay;
$this->heading = $heading;
parent::__construct(false);
}
/**
* Starts displaying the progress bar, with optional heading and a special
* div so it can be hidden later.
*
* @see \core\progress\display::start_html()
*/
public function start_html() {
global $OUTPUT;
$this->id = 'core_progress_display_if_slow' . self::$nextid;
self::$nextid++;
// Containing div includes a CSS class so that it can be themed if required,
// and an id so it can be automatically hidden at end.
echo \html_writer::start_div('core_progress_display_if_slow',
array('id' => $this->id));
// Display optional heading.
if ($this->heading !== '') {
echo $OUTPUT->heading($this->heading, 3);
}
// Use base class to display progress bar.
parent::start_html();
}
/**
* When progress is updated, after a certain time, starts actually displaying
* the progress bar.
*
* @see \core\progress\base::update_progress()
*/
public function update_progress() {
// If we haven't started yet, consider starting.
if ($this->starttime) {
if (time() > $this->starttime) {
$this->starttime = 0;
} else {
// Do nothing until start time.
return;
}
}
// We have started, so handle as default.
parent::update_progress();
}
/**
* Finishes parent display then closes div and hides it.
*
* @see \core\progress\display::end_html()
*/
public function end_html() {
parent::end_html();
echo \html_writer::end_div();
echo \html_writer::script('document.getElementById("' . $this->id .
'").style.display = "none"');
}
}
+45
View File
@@ -0,0 +1,45 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Progress handler that ignores progress entirely.
*
* @package core
* @copyright 2013 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core\progress;
defined('MOODLE_INTERNAL') || die();
/**
* Progress handler that ignores progress entirely.
*
* @package core
* @copyright 2013 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class none extends base {
/**
* When progress is updated, do nothing.
*
* @see \core\progress\base::update_progress()
*/
public function update_progress() {
// Do nothing.
}
}