Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1441 ariadna 1
<?php
2
// This file is part of Moodle - http://moodle.org/
3
//
4
// Moodle is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8
//
9
// Moodle is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16
 
17
namespace core\output;
18
 
19
use core\exception\coding_exception;
20
 
21
/**
22
 * Progress bar class.
23
 *
24
 * Manages the display of a progress bar.
25
 *
26
 * To use this class.
27
 * - construct
28
 * - call create (or use the 3rd param to the constructor)
29
 * - call update or update_full() or update() repeatedly
30
 *
31
 * @copyright 2008 jamiesensei
32
 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
33
 * @package core
34
 * @category output
35
 */
36
class progress_bar implements renderable, templatable {
37
 
38
    /** @var bool Can use output buffering. */
39
    protected static $supportsoutputbuffering = false;
40
 
41
    /** @var string unique id */
42
    protected $idnumber;
43
 
44
    /** @var int total width */
45
    protected $width;
46
 
47
    /** @var int last percentage printed */
48
    protected $percent = 0;
49
 
50
    /** @var int time when last printed */
51
    protected $lastupdate = 0;
52
 
53
    /** @var int when did we start printing this */
54
    protected $timestart = 0;
55
 
56
    /** @var bool Whether or not to auto render updates to the screen */
57
    protected $autoupdate = true;
58
 
59
    /** @var bool Whether or not an error has occured */
60
    protected $haserrored = false;
61
 
62
    /**
63
     * Constructor
64
     *
65
     * Prints JS code if $autostart true.
66
     *
67
     * @param string $htmlid The unique ID for the progress bar or HTML container id.
68
     * @param int $width The suggested width.
69
     * @param bool $autostart Whether to start the progress bar right away.
70
     */
71
    public function __construct($htmlid = '', $width = 500, $autostart = false) {
72
        if (!static::$supportsoutputbuffering && !CLI_SCRIPT && !NO_OUTPUT_BUFFERING) {
73
            debugging('progress_bar used in a non-CLI script without setting NO_OUTPUT_BUFFERING.', DEBUG_DEVELOPER);
74
        }
75
 
76
        if (!empty($htmlid)) {
77
            $this->idnumber  = $htmlid;
78
        } else {
79
            $this->idnumber  = 'pbar_'.uniqid();
80
        }
81
 
82
        $this->width = $width;
83
 
84
        if ($autostart) {
85
            $this->create();
86
        }
87
    }
88
 
89
    /**
90
     * Getter for ID
91
     * @return string id
92
     */
93
    public function get_id(): string {
94
        return $this->idnumber;
95
    }
96
 
97
    /**
98
     * Get the percent
99
     * @return float
100
     */
101
    public function get_percent(): float {
102
        return $this->percent;
103
    }
104
 
105
    /**
106
     * Create a new progress bar, this function will output html.
107
     *
108
     * @return void Echo's output
109
     */
110
    public function create() {
111
 
112
        $this->timestart = microtime(true);
113
        $this->render();
114
 
115
    }
116
 
117
    /**
118
     * Render the progress bar.
119
     *
120
     * @return void
121
     */
122
    public function render(): void {
123
        flush();
124
        echo $this->get_content();
125
        flush();
126
    }
127
 
128
    /**
129
     * Get the content to be rendered
130
     *
131
     * @return string
132
     */
133
    public function get_content(): string {
134
        global $OUTPUT;
135
        return $OUTPUT->render($this);
136
    }
137
 
138
    /**
139
     * Set whether or not to auto render updates to the screen
140
     *
141
     * @param bool $value
142
     * @return void
143
     */
144
    public function auto_update(bool $value): void {
145
        $this->autoupdate = $value;
146
    }
147
 
148
    /**
149
     * Update the progress bar.
150
     *
151
     * @param int $percent From 1-100.
152
     * @param string $msg The message.
153
     * @return void Echo's output
154
     * @throws coding_exception
155
     */
156
    protected function update_raw($percent, $msg) {
157
        global $OUTPUT;
158
 
159
        if (empty($this->timestart)) {
160
            throw new coding_exception('You must call create() (or use the $autostart ' .
161
                'argument to the constructor) before you try updating the progress bar.');
162
        }
163
 
164
        $estimate = $this->estimate($percent);
165
 
166
        // Always do the first and last updates. Estimate would be null in the beginning and 0 at the end.
167
        $isfirstorlastupdate = empty($estimate);
168
        // We need to update every 20 seconds since last update to prevent browser timeout.
169
        $timetoupdate = $this->lastupdate + 20 < time();
170
        // Whether the progress has moved.
171
        $issameprogress = round($this->percent, 2) === round($percent, 2);
172
 
173
        // No need to update if it's not yet time to update and there's no progress.
174
        if (!$isfirstorlastupdate && !$timetoupdate && $issameprogress) {
175
            return;
176
        }
177
 
178
        $estimatemsg = $this->get_estimate_message($percent);
179
 
180
        $this->percent = $percent;
181
        $this->lastupdate = microtime(true);
182
 
183
        if ($this->autoupdate) {
184
            echo $OUTPUT->render_progress_bar_update($this->idnumber, $this->percent, $msg, $estimatemsg);
185
            flush();
186
        }
187
    }
188
 
189
    /**
190
     * Estimate how much time it is going to take.
191
     *
192
     * @param int $pt From 1-100.
193
     * @return mixed Null (unknown), or int.
194
     */
195
    protected function estimate($pt) {
196
        if ($this->lastupdate == 0) {
197
            return null;
198
        }
199
        if ($pt < 0.00001) {
200
            return null; // We do not know yet how long it will take.
201
        }
202
        if ($pt > 99.99999) {
203
            return 0; // Nearly done, right?
204
        }
205
        $consumed = microtime(true) - $this->timestart;
206
        if ($consumed < 0.001) {
207
            return null;
208
        }
209
 
210
        return (100 - $pt) * ($consumed / $pt);
211
    }
212
 
213
    /**
214
     * Update progress bar according percent.
215
     *
216
     * @param int $percent From 1-100.
217
     * @param string $msg The message needed to be shown.
218
     */
219
    public function update_full($percent, $msg) {
220
        $percent = max(min($percent, 100), 0);
221
        $this->update_raw($percent, $msg);
222
    }
223
 
224
    /**
225
     * Update progress bar according the number of tasks.
226
     *
227
     * @param int $cur Current task number.
228
     * @param int $total Total task number.
229
     * @param string $msg The message needed to be shown.
230
     */
231
    public function update($cur, $total, $msg) {
232
        $percent = ($cur / $total) * 100;
233
        $this->update_full($percent, $msg);
234
    }
235
 
236
    /**
237
     * Restart the progress bar.
238
     */
239
    public function restart() {
240
        $this->percent    = 0;
241
        $this->lastupdate = 0;
242
        $this->timestart = 0;
243
    }
244
 
245
    /**
246
     * Export for template.
247
     *
248
     * @param  renderer_base $output The renderer.
249
     * @return array
250
     */
251
    public function export_for_template(renderer_base $output) {
252
        return [
253
            'id' => '',
254
            'idnumber' => $this->idnumber,
255
            'width' => $this->width,
256
            'class' => '',
257
            'value' => 0,
258
            'error' => 0,
259
        ];
260
    }
261
 
262
    /**
263
     * This gets the estimate message to be displayed with the progress bar.
264
     *
265
     * @param float $percent
266
     * @return string
267
     */
268
    public function get_estimate_message(float $percent): string {
269
        $estimate = $this->estimate($percent);
270
        $estimatemsg = '';
271
        if ($estimate != 0 && is_numeric($estimate)) {
272
            $estimatemsg = format_time(ceil($estimate));
273
        }
274
 
275
        return $estimatemsg;
276
    }
277
 
278
    /**
279
     * Set the error flag on the object
280
     *
281
     * @param bool $value
282
     * @return void
283
     */
284
    protected function set_haserrored(bool $value): void {
285
        $this->haserrored = $value;
286
    }
287
 
288
    /**
289
     * Check if the process has errored
290
     *
291
     * @return bool
292
     */
293
    public function get_haserrored(): bool {
294
        return $this->haserrored;
295
    }
296
 
297
    /**
298
     * Set that the process running has errored
299
     *
300
     * @param string $errormsg
301
     * @return void
302
     */
303
    public function error(string $errormsg): void {
304
        global $OUTPUT;
305
 
306
        $this->haserrored = true;
307
        $this->message = $errormsg;
308
 
309
        if ($this->autoupdate) {
310
            echo $OUTPUT->render_progress_bar_update($this->idnumber, $this->percent, $errormsg, '', true);
311
            flush();
312
        }
313
    }
314
 
315
}
316
 
317
// Alias this class to the old name.
318
// This file will be autoloaded by the legacyclasses autoload system.
319
// In future all uses of this class will be corrected and the legacy references will be removed.
320
class_alias(progress_bar::class, \progress_bar::class);