|
22 | 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
23 | 23 | */
|
24 | 24 |
|
| 25 | +use core\exception\coding_exception; |
| 26 | +use core\output\mustache_engine; |
| 27 | +use core\output\mustache_string_helper; |
| 28 | + |
25 | 29 | /**
|
26 | 30 | * Non instantiable helper class providing DB support to the @backup_plan class
|
27 | 31 | *
|
@@ -194,81 +198,115 @@ public static function get_mnet_localhost_wwwroot() {
|
194 | 198 | }
|
195 | 199 |
|
196 | 200 | /**
|
197 |
| - * Returns the default backup filename, based in passed params. |
198 |
| - * |
199 |
| - * Default format is (see MDL-22145) |
200 |
| - * backup word - format - type - name - date - info . mbz |
201 |
| - * where name is variable (course shortname, section name/id, activity modulename + cmid) |
202 |
| - * and info can be (nu = no user info, an = anonymized). The last param $useidasname, |
203 |
| - * defaulting to false, allows to replace the course shortname by the course id (used |
204 |
| - * by automated backups, to avoid non-ascii chars in OS filesystem) |
205 |
| - * |
206 |
| - * @param string $format One of backup::FORMAT_ |
207 |
| - * @param string $type One of backup::TYPE_ |
208 |
| - * @param int $courseid/$sectionid/$cmid |
209 |
| - * @param bool $users Should be true is users were included in the backup |
210 |
| - * @param bool $anonymised Should be true is user information was anonymized. |
211 |
| - * @param bool $useidonly only use the ID in the file name |
212 |
| - * @return string The filename to use |
213 |
| - */ |
214 |
| - public static function get_default_backup_filename($format, $type, $id, $users, $anonymised, |
215 |
| - $useidonly = false, $files = true) { |
| 201 | + * Returns the default backup filename, based in passed params. |
| 202 | + * |
| 203 | + * Default format is (see MDL-22145) |
| 204 | + * backup word - format - type - name - date - info . mbz |
| 205 | + * where name is variable (course shortname, section name/id, activity modulename + cmid) |
| 206 | + * and info can be (nu = no user info, an = anonymized). The last param $useidonly, |
| 207 | + * defaulting to false, allows to replace the course shortname by the course id (used |
| 208 | + * by automated backups, to avoid non-ascii chars in OS filesystem) |
| 209 | + * |
| 210 | + * @param string $format One of backup::FORMAT_ |
| 211 | + * @param string $type One of backup::TYPE_ |
| 212 | + * @param int $id course id, section id, or course module id |
| 213 | + * @param bool $users Should be true is users were included in the backup |
| 214 | + * @param bool $anonymised Should be true is user information was anonymized |
| 215 | + * @param bool $useidonly only use the ID in the file name |
| 216 | + * @param bool $files if files are included |
| 217 | + * @param int|null $time time to use in any dates, if not given uses current time |
| 218 | + * @return string The filename to use |
| 219 | + */ |
| 220 | + public static function get_default_backup_filename(string $format, string $type, int $id, bool $users, bool $anonymised, |
| 221 | + bool $useidonly = false, bool $files = true, ?int $time = null): string { |
216 | 222 | global $DB;
|
217 | 223 |
|
218 |
| - // Calculate backup word |
219 |
| - $backupword = str_replace(' ', '_', core_text::strtolower(get_string('backupfilename'))); |
220 |
| - $backupword = trim(clean_filename($backupword), '_'); |
221 |
| - |
222 |
| - // Not $useidonly, lets fetch the name |
223 |
| - $shortname = ''; |
224 |
| - if (!$useidonly) { |
225 |
| - // Calculate proper name element (based on type) |
226 |
| - switch ($type) { |
227 |
| - case backup::TYPE_1COURSE: |
228 |
| - $shortname = $DB->get_field('course', 'shortname', array('id' => $id)); |
229 |
| - $context = context_course::instance($id); |
230 |
| - $shortname = format_string($shortname, true, array('context' => $context)); |
231 |
| - break; |
232 |
| - case backup::TYPE_1SECTION: |
233 |
| - if (!$shortname = $DB->get_field('course_sections', 'name', array('id' => $id))) { |
234 |
| - $shortname = $DB->get_field('course_sections', 'section', array('id' => $id)); |
235 |
| - } |
236 |
| - break; |
237 |
| - case backup::TYPE_1ACTIVITY: |
238 |
| - $cm = get_coursemodule_from_id(null, $id); |
239 |
| - $shortname = $cm->modname . $id; |
240 |
| - break; |
241 |
| - } |
242 |
| - $shortname = str_replace(' ', '_', $shortname); |
243 |
| - $shortname = core_text::strtolower(trim(clean_filename($shortname), '_')); |
244 |
| - } |
245 |
| - |
246 |
| - // The name will always contain the ID, but we append the course short name if requested. |
247 |
| - $name = $id; |
248 |
| - if (!$useidonly && $shortname != '') { |
249 |
| - $name .= '-' . $shortname; |
| 224 | + if ($time === null) { |
| 225 | + $time = time(); |
250 | 226 | }
|
251 | 227 |
|
252 |
| - // Calculate date |
253 | 228 | $backupdateformat = str_replace(' ', '_', get_string('backupnameformat', 'langconfig'));
|
254 |
| - $date = userdate(time(), $backupdateformat, 99, false); |
255 |
| - $date = core_text::strtolower(trim(clean_filename($date), '_')); |
256 |
| - |
257 |
| - // Calculate info |
258 |
| - $info = ''; |
259 |
| - if (!$users) { |
260 |
| - $info = '-nu'; |
261 |
| - } else if ($anonymised) { |
262 |
| - $info = '-an'; |
| 229 | + $formatdate = function(int $date) use ($backupdateformat): string { |
| 230 | + $date = userdate($date, $backupdateformat, 99, false); |
| 231 | + return core_text::strtolower(trim(clean_filename($date), '_')); |
| 232 | + }; |
| 233 | + |
| 234 | + $context = [ |
| 235 | + 'format' => $format, |
| 236 | + 'type' => $type, |
| 237 | + 'id' => $id, |
| 238 | + 'users' => $users, |
| 239 | + 'anonymised' => $anonymised, |
| 240 | + 'files' => $files, |
| 241 | + 'useidonly' => $useidonly, |
| 242 | + 'time' => $time, |
| 243 | + 'date' => $formatdate($time), |
| 244 | + ]; |
| 245 | + |
| 246 | + // Add extra context based on the type of backup. |
| 247 | + // It is important to use array and not stdClass here, otherwise array_walk_recursive will not work. |
| 248 | + switch ($type) { |
| 249 | + case backup::TYPE_1COURSE: |
| 250 | + $context['course'] = (array) $DB->get_record('course', ['id' => $id], |
| 251 | + 'shortname,fullname,startdate,enddate', MUST_EXIST); |
| 252 | + $context['course']['startdate'] = $formatdate($context['course']['startdate']); |
| 253 | + $context['course']['enddate'] = $formatdate($context['course']['enddate']); |
| 254 | + break; |
| 255 | + case backup::TYPE_1SECTION: |
| 256 | + $context['section'] = (array) $DB->get_record('course_sections', ['id' => $id], 'name,section', MUST_EXIST); |
| 257 | + break; |
| 258 | + case backup::TYPE_1ACTIVITY: |
| 259 | + $cm = get_coursemodule_from_id(null, $id, 0, false, MUST_EXIST); |
| 260 | + $context['activity'] = [ |
| 261 | + 'modname' => $cm->modname, |
| 262 | + 'name' => $cm->name, |
| 263 | + ]; |
| 264 | + break; |
| 265 | + default: |
| 266 | + throw new coding_exception('Unknown backup type - cannot get template context'); |
263 | 267 | }
|
264 | 268 |
|
265 |
| - // Indicate if backup doesn't contain files. |
266 |
| - if (!$files) { |
267 |
| - $info .= '-nf'; |
| 269 | + $instancecontext = null; |
| 270 | + switch ($type) { |
| 271 | + case backup::TYPE_1COURSE: |
| 272 | + $instancecontext = context_course::instance($id); |
| 273 | + break; |
| 274 | + case backup::TYPE_1SECTION: |
| 275 | + // A section is still course context, but needs an extra step to find the course id. |
| 276 | + $courseid = $DB->get_field('course_sections', 'course', ['id' => $id], MUST_EXIST); |
| 277 | + $instancecontext = context_course::instance($courseid); |
| 278 | + break; |
| 279 | + case backup::TYPE_1ACTIVITY: |
| 280 | + $instancecontext = context_module::instance($id); |
| 281 | + break; |
| 282 | + default: |
| 283 | + throw new coding_exception('Unknown backup type - cannot get instance context'); |
268 | 284 | }
|
269 | 285 |
|
270 |
| - return $backupword . '-' . $format . '-' . $type . '-' . |
271 |
| - $name . '-' . $date . $info . '.mbz'; |
| 286 | + // Recursively format all the strings and trim any extra whitespace. |
| 287 | + array_walk_recursive($context, function(&$item) use ($instancecontext) { |
| 288 | + if (is_string($item)) { |
| 289 | + // Update by reference. |
| 290 | + $item = trim(format_string($item, true, ['context' => $instancecontext])); |
| 291 | + } |
| 292 | + }); |
| 293 | + |
| 294 | + $templates = [ |
| 295 | + backup::TYPE_1COURSE => get_config('backup', 'backup_default_filename_template_course'), |
| 296 | + backup::TYPE_1SECTION => get_config('backup', 'backup_default_filename_template_section'), |
| 297 | + backup::TYPE_1ACTIVITY => get_config('backup', 'backup_default_filename_template_activity'), |
| 298 | + ]; |
| 299 | + $template = $templates[$type]; |
| 300 | + $mustache = new mustache_engine([ |
| 301 | + 'helpers' => [ |
| 302 | + 'str' => [new mustache_string_helper(), 'str'], |
| 303 | + ], |
| 304 | + ]); |
| 305 | + $new = $mustache->render($template, $context); |
| 306 | + |
| 307 | + // Clean as filename, remove spaces, and trim to max 251 chars (filename limit, 255 including .mbz extension). |
| 308 | + $cleaned = substr(str_replace(' ', '_', clean_filename($new)), 0, 251); |
| 309 | + return $cleaned . '.mbz'; |
272 | 310 | }
|
273 | 311 |
|
274 | 312 | /**
|
|
0 commit comments