Merge branch 'MDL-46455-master-20151012' of git://github.com/damyon/moodle

This commit is contained in:
David Monllao 2015-10-13 11:42:40 +08:00
commit ee58df52da
308 changed files with 3572 additions and 118 deletions

View File

@ -112,4 +112,9 @@ class langpack_imported extends \core\event\base {
throw new \coding_exception('The \'langcode\' value must be set to a valid language code');
}
}
public static function get_other_mapping() {
// No mapping required for this event because this event is not backed up.
return false;
}
}

View File

@ -113,4 +113,9 @@ class langpack_removed extends \core\event\base {
throw new \coding_exception('The \'langcode\' value must be set to a valid language code');
}
}
public static function get_other_mapping() {
// No mapping required for this event because this event is not backed up.
return false;
}
}

View File

@ -112,4 +112,9 @@ class langpack_updated extends \core\event\base {
throw new \coding_exception('The \'langcode\' value must be set to a valid language code');
}
}
public static function get_other_mapping() {
// No mapping required for this event because this event is not backed up.
return false;
}
}

View File

@ -0,0 +1,37 @@
<?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/>.
/**
* Backup support for tool_log logstore subplugins.
*
* @package tool_log
* @category backup
* @copyright 2015 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Parent class of all the logstore subplugin implementations.
*
* Note: While this intermediate class is not strictly required and all the
* subplugin implementations can extend directly {@link backup_subplugin},
* it is always recommended to have it, both for better testing and also
* for sharing code between all subplugins.
*/
abstract class backup_tool_log_logstore_subplugin extends backup_subplugin {
}

View File

@ -0,0 +1,150 @@
<?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/>.
/**
* Restore support for tool_log logstore subplugins.
*
* @package tool_log
* @category backup
* @copyright 2015 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Parent class of all the logstore subplugin implementations.
*
* Note: While this intermediate class is not strictly required and all the
* subplugin implementations can extend directly {@link restore_subplugin},
* it is always recommended to have it, both for better testing and also
* for sharing code between all subplugins.
*/
abstract class restore_tool_log_logstore_subplugin extends restore_subplugin {
/**
* Process log entries.
*
* This method proceeds to read, complete, remap and, finally,
* discard or save every log entry.
*
* @param array $data log entry.
* @return object|null $dataobject A data object with values for one or more fields in the record,
* or null if we are not going to process the log.
*/
protected function process_log($data) {
$data = (object) $data;
// Complete the information that does not come from backup.
$contextid = $data->contextid;
if (!$data->contextid = $this->get_mappingid('context', $contextid)) {
$message = "Context id \"$contextid\" could not be mapped. Skipping log record.";
$this->log($message, backup::LOG_DEBUG);
return;
}
$context = context::instance_by_id($data->contextid, MUST_EXIST);
$data->contextlevel = $context->contextlevel;
$data->contextinstanceid = $context->instanceid;
$data->courseid = $this->task->get_courseid();
// Remap users.
$userid = $data->userid;
if (!$data->userid = $this->get_mappingid('user', $userid)) {
$message = "User id \"$userid\" could not be mapped. Skipping log record.";
$this->log($message, backup::LOG_DEBUG);
return;
}
if (!empty($data->relateduserid)) { // This is optional.
$relateduserid = $data->relateduserid;
if (!$data->relateduserid = $this->get_mappingid('user', $relateduserid)) {
$message = "Related user id \"$relateduserid\" could not be mapped. Skipping log record.";
$this->log($message, backup::LOG_DEBUG);
return;
}
}
if (!empty($data->realuserid)) { // This is optional.
$realuserid = $data->realuserid;
if (!$data->realuserid = $this->get_mappingid('user', $realuserid)) {
$message = "Real user id \"$realuserid\" could not be mapped. Skipping log record.";
$this->log($message, backup::LOG_DEBUG);
return;
}
}
// Roll dates.
$data->timecreated = $this->apply_date_offset($data->timecreated);
// Revert other to its original php way.
$data->other = unserialize(base64_decode($data->other));
// Arrived here, we have both 'objectid' and 'other' to be converted. This is the tricky part.
// Both are pointing to other records id, but the sources are not identified in the
// same way restore mappings work. So we need to delegate them to some resolver that
// will give us the correct restore mapping to be used.
if (!empty($data->objectid)) {
// Check if there is an available class for this event we can use to map this value.
$eventclass = $data->eventname;
if (class_exists($eventclass)) {
$mapping = $eventclass::get_objectid_mapping();
if ($mapping) {
// Check if it can not be mapped.
if ((is_int($mapping) && $mapping === \core\event\base::NOT_MAPPED) ||
($mapping['restore'] === \core\event\base::NOT_MAPPED)) {
$data->objectid = \core\event\base::NOT_MAPPED;
} else {
$data->objectid = $this->get_mappingid($mapping['restore'], $data->objectid);
}
}
} else {
$message = "Event class not found: \"$eventclass\". Skipping log record.";
$this->log($message, backup::LOG_DEBUG);
return; // No such class, can not restore.
}
}
if (!empty($data->other)) {
// Check if there is an available class for this event we can use to map this value.
$eventclass = $data->eventname;
if (class_exists($eventclass)) {
$othermapping = $eventclass::get_other_mapping();
if ($othermapping) {
// Go through the data we have.
foreach ($data->other as $key => $value) {
// Check if there is a corresponding key we can use to map to.
if (isset($othermapping[$key]) && !empty($value)) {
// Ok, let's map this.
$mapping = $othermapping[$key];
// Check if it can not be mapped.
if ((is_int($mapping) && $mapping === \core\event\base::NOT_MAPPED) ||
($mapping['restore'] === \core\event\base::NOT_MAPPED)) {
$data->other[$key] = \core\event\base::NOT_MAPPED;
} else {
$data->other[$key] = $this->get_mappingid($mapping['restore'], $value);
}
}
}
}
// Now we want to serialize it so we can store it in the DB.
$data->other = serialize($data->other);
} else {
$message = "Event class not found: \"$eventclass\". Skipping log record.";
$this->log($message, backup::LOG_DEBUG);
return; // No such class, can not restore.
}
}
return $data;
}
}

View File

@ -0,0 +1,98 @@
<?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/>.
/**
* Backup implementation for the (tool_log) logstore_database nested element.
*
* @package logstore_database
* @category backup
* @copyright 2015 Damyon Wiese <damyon@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Custom subclass of backup_nested_element that iterates over an external DB connection.
*
* @package logstore_database
* @category backup
* @copyright 2015 Damyon Wiese <damyon@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class backup_logstore_database_nested_element extends backup_nested_element {
/**
* @var \moodle_database $sourcedb
*/
protected $sourcedb;
/**
* Constructor - instantiates one backup_nested_element, specifying its basic info.
*
* @param string $name name of the element
* @param array $attributes attributes this element will handle (optional, defaults to null)
* @param array $finalelements this element will handle (optional, defaults to null)
*/
public function __construct($name, $attributes = null, $finalelements = null) {
global $DB;
parent::__construct($name, $attributes, $finalelements);
$this->sourcedb = $DB;
}
/**
* For sql or table datasources, this will iterate over the "external" DB connection
* stored in this class instead of the default $DB. All other cases use the parent default.
* @param object $processor the processor
*/
protected function get_iterator($processor) {
if ($this->get_source_table() !== null) { // It's one table, return recordset iterator.
return $this->get_source_db()->get_recordset(
$this->get_source_table(),
backup_structure_dbops::convert_params_to_values($this->procparams, $processor),
$this->get_source_table_sortby()
);
} else if ($this->get_source_sql() !== null) { // It's one sql, return recordset iterator.
return $this->get_source_db()->get_recordset_sql(
$this->get_source_sql(),
backup_structure_dbops::convert_params_to_values($this->procparams, $processor)
);
}
return parent::get_iterator($processor);
}
/**
* Set the database we want to use.
*
* @param \moodle_database $db
*/
public function set_source_db($db) {
$this->sourcedb = $db;
}
/**
* Get the database we want to use.
*
* @return \moodle_database $db
*/
public function get_source_db() {
return $this->sourcedb;
}
}

View File

@ -0,0 +1,65 @@
<?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/>.
/**
* Backup implementation for the (tool_log) logstore_database subplugin.
*
* @package logstore_database
* @category backup
* @copyright 2015 Mark Nelson <markn@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
require_once('backup_logstore_database_nested_element.php');
class backup_logstore_database_subplugin extends backup_tool_log_logstore_subplugin {
/**
* Returns the subplugin structure to attach to the 'logstore' XML element.
*
* @return backup_subplugin_element the subplugin structure to be attached.
*/
protected function define_logstore_subplugin_structure() {
$subplugin = $this->get_subplugin_element();
$subpluginwrapper = new backup_nested_element($this->get_recommended_name());
// Create the custom (base64 encoded, xml safe) 'other' final element.
$otherelement = new base64_encode_final_element('other');
$subpluginlog = new backup_logstore_database_nested_element('logstore_database_log', array('id'), array(
'eventname', 'component', 'action', 'target', 'objecttable',
'objectid', 'crud', 'edulevel', 'contextid', 'userid', 'relateduserid',
'anonymous', $otherelement, 'timecreated', 'ip', 'realuserid'));
$subplugin->add_child($subpluginwrapper);
$subpluginwrapper->add_child($subpluginlog);
// Get the details for the external database.
$manager = new \tool_log\log\manager();
$store = new \logstore_database\log\store($manager);
$extdb = $store->get_extdb();
if (!$extdb) {
return false;
}
$subpluginlog->set_source_db($extdb);
$subpluginlog->set_source_table($store->get_config_value('dbtable'), array('contextid' => backup::VAR_CONTEXTID));
return $subplugin;
}
}

View File

@ -0,0 +1,102 @@
<?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/>.
/**
* Restore implementation for the (tool_log) logstore_database subplugin.
*
* @package logstore_database
* @category backup
* @copyright 2015 Mark Nelson <markn@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
class restore_logstore_database_subplugin extends restore_tool_log_logstore_subplugin {
/**
* @var moodle_database the external database.
*/
private static $extdb = null;
/**
* @var string the external database table name.
*/
private static $extdbtablename = null;
/**
* The constructor for this logstore.
*
* @param string $subplugintype the subplugin type.
* @param string $subpluginname the subplugin name.
* @param restore_structure_step $step.
*/
public function __construct($subplugintype, $subpluginname, $step) {
// Check that the logstore is enabled before setting variables.
$enabledlogstores = explode(',', get_config('tool_log', 'enabled_stores'));
if (in_array('logstore_database', $enabledlogstores)) {
$manager = new \tool_log\log\manager();
$store = new \logstore_database\log\store($manager);
self::$extdb = $store->get_extdb();
self::$extdbtablename = $store->get_config_value('dbtable');
}
parent::__construct($subplugintype, $subpluginname, $step);
}
/**
* Returns the subplugin structure to attach to the 'logstore' XML element.
*
* @return restore_path_element[] array of elements to be processed on restore.
*/
protected function define_logstore_subplugin_structure() {
// If the logstore is not enabled we don't add structures for it.
$enabledlogstores = explode(',', get_config('tool_log', 'enabled_stores'));
if (!in_array('logstore_database', $enabledlogstores)) {
return array(); // The logstore is not enabled, nothing to restore.
}
$paths = array();
$elename = $this->get_namefor('log');
$elepath = $this->get_pathfor('/logstore_database_log');
$paths[] = new restore_path_element($elename, $elepath);
return $paths;
}
/**
* Process logstore_database_log entries.
*
* This method proceeds to read, complete, remap and, finally,
* discard or save every log entry.
*
* @param array() $data log entry.
* @return null if we are not restoring the log.
*/
public function process_logstore_database_log($data) {
// Do not bother processing if we can not add it to a database.
if (!self::$extdb || !self::$extdbtablename) {
return;
}
$data = $this->process_log($data);
if ($data) {
self::$extdb->insert_record(self::$extdbtablename, $data);
}
}
}

View File

@ -258,6 +258,30 @@ class store implements \tool_log\log\writer, \core\log\sql_reader {
return $this->extdb->count_records_select($dbtable, $selectwhere, $params);
}
/**
* Get a config value for the store.
*
* @param string $name Config name
* @param mixed $default default value
* @return mixed config value if set, else the default value.
*/
public function get_config_value($name, $default = null) {
return $this->get_config($name, $default);
}
/**
* Get the external database object.
*
* @return \moodle_database $extdb
*/
public function get_extdb() {
if (!$this->init()) {
return false;
}
return $this->extdb;
}
/**
* Are the new events appearing in the reader?
*

View File

@ -0,0 +1,55 @@
<?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/>.
/**
* Backup implementation for the (tool_log) logstore_standard subplugin.
*
* @package logstore_standard
* @category backup
* @copyright 2015 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
class backup_logstore_standard_subplugin extends backup_tool_log_logstore_subplugin {
/**
* Returns the subplugin structure to attach to the 'logstore' XML element.
*
* @return backup_subplugin_element the subplugin structure to be attached.
*/
protected function define_logstore_subplugin_structure() {
$subplugin = $this->get_subplugin_element();
$subpluginwrapper = new backup_nested_element($this->get_recommended_name());
// Create the custom (base64 encoded, xml safe) 'other' final element.
$otherelement = new base64_encode_final_element('other');
$subpluginlog = new backup_nested_element('logstore_standard_log', array('id'), array(
'eventname', 'component', 'action', 'target', 'objecttable',
'objectid', 'crud', 'edulevel', 'contextid', 'userid', 'relateduserid',
'anonymous', $otherelement, 'timecreated', 'ip', 'realuserid'));
$subplugin->add_child($subpluginwrapper);
$subpluginwrapper->add_child($subpluginlog);
$subpluginlog->set_source_table('logstore_standard_log', array('contextid' => backup::VAR_CONTEXTID));
return $subplugin;
}
}

View File

@ -0,0 +1,69 @@
<?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/>.
/**
* Restore implementation for the (tool_log) logstore_standard subplugin.
*
* @package logstore_standard
* @category backup
* @copyright 2015 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
class restore_logstore_standard_subplugin extends restore_tool_log_logstore_subplugin {
/**
* Returns the subplugin structure to attach to the 'logstore' XML element.
*
* @return restore_path_element[] array of elements to be processed on restore.
*/
protected function define_logstore_subplugin_structure() {
// If the logstore is not enabled we don't add structures for it.
$enabledlogstores = explode(',', get_config('tool_log', 'enabled_stores'));
if (!in_array('logstore_standard', $enabledlogstores)) {
return array(); // The logstore is not enabled, nothing to restore.
}
$paths = array();
$elename = $this->get_namefor('log');
$elepath = $this->get_pathfor('/logstore_standard_log');
$paths[] = new restore_path_element($elename, $elepath);
return $paths;
}
/**
* Process logstore_standard_log entries.
*
* This method proceeds to read, complete, remap and, finally,
* discard or save every log entry.
*
* @param array() $data log entry.
*/
public function process_logstore_standard_log($data) {
global $DB;
$data = $this->process_log($data);
if ($data) {
$DB->insert_record('logstore_standard_log', $data);
}
}
}

View File

@ -74,4 +74,9 @@ class rule_created extends \core\event\base {
return new \moodle_url('/admin/tool/monitor/edit.php', array('ruleid' => $this->objectid,
'courseid' => $this->courseid));
}
public static function get_objectid_mapping() {
// No mapping required for this event because event monitor rules are not backed up.
return array('db' => 'tool_monitor_rules', 'restore' => \core\event\base::NOT_MAPPED);
}
}

View File

@ -73,4 +73,9 @@ class rule_deleted extends \core\event\base {
public function get_url() {
return new \moodle_url('/admin/tool/monitor/managerules.php', array('courseid' => $this->courseid));
}
public static function get_objectid_mapping() {
// No mapping required for this event because event monitor rules are not backed up.
return array('db' => 'tool_monitor_rules', 'restore' => \core\event\base::NOT_MAPPED);
}
}

View File

@ -74,4 +74,9 @@ class rule_updated extends \core\event\base {
return new \moodle_url('/admin/tool/monitor/edit.php', array('ruleid' => $this->objectid,
'courseid' => $this->courseid));
}
public static function get_objectid_mapping() {
// No mapping required for this event because event monitor rules are not backed up.
return array('db' => 'tool_monitor_rules', 'restore' => \core\event\base::NOT_MAPPED);
}
}

View File

@ -64,4 +64,9 @@ class subscription_created extends \core\event\base {
public function get_description() {
return "The user with id '$this->userid' created the event monitor subscription with id '$this->objectid'.";
}
public static function get_objectid_mapping() {
// No mapping required for this event because event monitor subscriptions are not backed up.
return array('db' => 'tool_monitor_subscriptions', 'restore' => \core\event\base::NOT_MAPPED);
}
}

View File

@ -83,4 +83,9 @@ class subscription_criteria_met extends \core\event\base {
throw new \coding_exception('The \'subscriptionid\' value must be set in other.');
}
}
public static function get_other_mapping() {
// No mapping required for this event because event monitor subscriptions are not backed up.
return false;
}
}

View File

@ -64,4 +64,9 @@ class subscription_deleted extends \core\event\base {
public function get_description() {
return "The user with id '$this->userid' deleted the event monitor subscription with id '$this->objectid'.";
}
public static function get_objectid_mapping() {
// No mapping required for this event because event monitor subscriptions are not backed up.
return array('db' => 'tool_monitor_subscriptions', 'restore' => \core\event\base::NOT_MAPPED);
}
}

View File

@ -166,7 +166,10 @@ abstract class backup_activity_task extends backup_task {
// Generate the logs file (conditionally)
if ($this->get_setting_value('logs')) {
// Legacy logs.
$this->add_step(new backup_activity_logs_structure_step('activity_logs', 'logs.xml'));
// New log stores.
$this->add_step(new backup_activity_logstores_structure_step('activity_logstores', 'logstores.xml'));
}
// Generate the calendar events file (conditionally)

View File

@ -121,7 +121,10 @@ class backup_course_task extends backup_task {
// Generate the logs file (conditionally)
if ($this->get_setting_value('logs')) {
// Legacy logs.
$this->add_step(new backup_course_logs_structure_step('course_logs', 'logs.xml'));
// New log stores.
$this->add_step(new backup_course_logstores_structure_step('course_logstores', 'logstores.xml'));
}
// Generate the inforef file (must be after ALL steps gathering annotations of ANY type)

View File

@ -78,6 +78,25 @@ class mnethosturl_final_element extends backup_final_element {
}
}
/**
* Implementation of {@link backup_final_element} that provides base64 encoding.
*
* This final element transparently encodes with base64_encode() contents that
* normally are not safe for being stored in utf-8 xml files (binaries, serialized
* data...).
*/
class base64_encode_final_element extends backup_final_element {
/**
* Set the value for the final element, encoding it as utf-8/xml safe base64.
*
* @param string $value Original value coming from backup step source, usually db.
*/
public function set_value($value) {
parent::set_value(base64_encode($value));
}
}
/**
* Implementation of backup_nested_element that provides special handling of files
*

View File

@ -91,64 +91,10 @@ class create_taskbasepath_directory extends backup_execution_step {
/**
* Abstract structure step, parent of all the activity structure steps. Used to wrap the
* activity structure definition within the main <activity ...> tag. Also provides
* subplugin support for activities (that must be properly declared)
* activity structure definition within the main <activity ...> tag.
*/
abstract class backup_activity_structure_step extends backup_structure_step {
/**
* Add subplugin structure to any element in the activity backup tree
*
* @param string $subplugintype type of subplugin as defined in activity db/subplugins.php
* @param backup_nested_element $element element in the activity backup tree that
* we are going to add subplugin information to
* @param bool $multiple to define if multiple subplugins can produce information
* for each instance of $element (true) or no (false)
* @return void
*/
protected function add_subplugin_structure($subplugintype, $element, $multiple) {
global $CFG;
// Check the requested subplugintype is a valid one
$subpluginsfile = $CFG->dirroot . '/mod/' . $this->task->get_modulename() . '/db/subplugins.php';
if (!file_exists($subpluginsfile)) {
throw new backup_step_exception('activity_missing_subplugins_php_file', $this->task->get_modulename());
}
include($subpluginsfile);
if (!array_key_exists($subplugintype, $subplugins)) {
throw new backup_step_exception('incorrect_subplugin_type', $subplugintype);
}
// Arrived here, subplugin is correct, let's create the optigroup
$optigroupname = $subplugintype . '_' . $element->get_name() . '_subplugin';
$optigroup = new backup_optigroup($optigroupname, null, $multiple);
$element->add_child($optigroup); // Add optigroup to stay connected since beginning
// Get all the optigroup_elements, looking across all the subplugin dirs
$subpluginsdirs = core_component::get_plugin_list($subplugintype);
foreach ($subpluginsdirs as $name => $subpluginsdir) {
$classname = 'backup_' . $subplugintype . '_' . $name . '_subplugin';
$backupfile = $subpluginsdir . '/backup/moodle2/' . $classname . '.class.php';
if (file_exists($backupfile)) {
require_once($backupfile);
$backupsubplugin = new $classname($subplugintype, $name, $optigroup, $this);
// Add subplugin returned structure to optigroup
$backupsubplugin->define_subplugin_structure($element->get_name());
}
}
}
/**
* As far as activity backup steps are implementing backup_subplugin stuff, they need to
* have the parent task available for wrapping purposes (get course/context....)
*
* @return backup_activity_task
*/
public function get_task() {
return $this->task;
}
/**
* Wraps any activity backup structure within the common 'activity' element
* that will include common to all activities information like id, context...
@ -1539,6 +1485,36 @@ class backup_activity_logs_structure_step extends backup_structure_step {
}
}
/**
* Structure step in charge of constructing the logstores.xml file for the course logs.
*
* This backup step will backup the logs for all the enabled logstore subplugins supporting
* it, for logs belonging to the course level.
*/
class backup_course_logstores_structure_step extends backup_structure_step {
protected function define_structure() {
// Define the structure of logstores container.
$logstores = new backup_nested_element('logstores');
$logstore = new backup_nested_element('logstore');
$logstores->add_child($logstore);
// Add the tool_log logstore subplugins information to the logstore element.
$this->add_subplugin_structure('logstore', $logstore, true, 'tool', 'log');
return $logstores;
}
}
/**
* Structure step in charge of constructing the logstores.xml file for the activity logs.
*
* Note: Activity structure is completely equivalent to the course one, so just extend it.
*/
class backup_activity_logstores_structure_step extends backup_course_logstores_structure_step {
}
/**
* structure in charge of constructing the inforef.xml file for all the items we want
* to have referenced there (users, roles, files...)

View File

@ -173,7 +173,10 @@ abstract class restore_activity_task extends restore_task {
// Logs (conditionally)
if ($this->get_setting_value('logs')) {
// Legacy logs.
$this->add_step(new restore_activity_logs_structure_step('activity_logs', 'logs.xml'));
// New log stores.
$this->add_step(new restore_activity_logstores_structure_step('activity_logstores', 'logstores.xml'));
}
// At the end, mark it as built

View File

@ -82,9 +82,12 @@ class restore_final_task extends restore_task {
$this->add_step(new restore_decode_interlinks('decode_interlinks'));
// Restore course logs (conditionally). They are restored here because we need all
// the activities to be already restored
// the activities to be already restored.
if ($this->get_setting_value('logs')) {
// Legacy logs.
$this->add_step(new restore_course_logs_structure_step('course_logs', 'course/logs.xml'));
// New log stores.
$this->add_step(new restore_course_logstores_structure_step('course_logstores', 'course/logstores.xml'));
}
// Review all the executed tasks having one after_restore method

View File

@ -2997,6 +2997,75 @@ class restore_activity_logs_structure_step extends restore_course_logs_structure
}
}
/**
* Structure step in charge of restoring the logstores.xml file for the course logs.
*
* This restore step will rebuild the logs for all the enabled logstore subplugins supporting
* it, for logs belonging to the course level.
*/
class restore_course_logstores_structure_step extends restore_structure_step {
/**
* Conditionally decide if this step should be executed.
*
* This function checks the following parameter:
*
* 1. the logstores.xml file exists
*
* @return bool true is safe to execute, false otherwise
*/
protected function execute_condition() {
// Check it is included in the backup.
$fullpath = $this->task->get_taskbasepath();
$fullpath = rtrim($fullpath, '/') . '/' . $this->filename;
if (!file_exists($fullpath)) {
// Not found, can't restore logstores.xml information.
return false;
}
return true;
}
/**
* Return the elements to be processed on restore of logstores.
*
* @return restore_path_element[] array of elements to be processed on restore.
*/
protected function define_structure() {
$paths = array();
$logstore = new restore_path_element('logstore', '/logstores/logstore');
$paths[] = $logstore;
// Add logstore subplugin support to the 'logstore' element.
$this->add_subplugin_structure('logstore', $logstore, 'tool', 'log');
return array($logstore);
}
/**
* Process the 'logstore' element,
*
* Note: This is empty by definition in backup, because stores do not share any
* data between them, so there is nothing to process here.
*
* @param array $data element data
*/
protected function process_logstore($data) {
return;
}
}
/**
* Structure step in charge of restoring the logstores.xml file for the activity logs.
*
* Note: Activity structure is completely equivalent to the course one, so just extend it.
*/
class restore_activity_logstores_structure_step extends restore_course_logstores_structure_step {
}
/**
* Defines the restore step for advanced grading methods attached to the activity module
@ -3782,48 +3851,11 @@ class restore_userscompletion_structure_step extends restore_structure_step {
}
/**
* Abstract structure step, parent of all the activity structure steps. Used to suuport
* the main <activity ...> tag and process it. Also provides subplugin support for
* activities.
* Abstract structure step, parent of all the activity structure steps. Used to support
* the main <activity ...> tag and process it.
*/
abstract class restore_activity_structure_step extends restore_structure_step {
protected function add_subplugin_structure($subplugintype, $element) {
global $CFG;
// Check the requested subplugintype is a valid one
$subpluginsfile = $CFG->dirroot . '/mod/' . $this->task->get_modulename() . '/db/subplugins.php';
if (!file_exists($subpluginsfile)) {
throw new restore_step_exception('activity_missing_subplugins_php_file', $this->task->get_modulename());
}
include($subpluginsfile);
if (!array_key_exists($subplugintype, $subplugins)) {
throw new restore_step_exception('incorrect_subplugin_type', $subplugintype);
}
// Get all the restore path elements, looking across all the subplugin dirs
$subpluginsdirs = core_component::get_plugin_list($subplugintype);
foreach ($subpluginsdirs as $name => $subpluginsdir) {
$classname = 'restore_' . $subplugintype . '_' . $name . '_subplugin';
$restorefile = $subpluginsdir . '/backup/moodle2/' . $classname . '.class.php';
if (file_exists($restorefile)) {
require_once($restorefile);
$restoresubplugin = new $classname($subplugintype, $name, $this);
// Add subplugin paths to the step
$this->prepare_pathelements($restoresubplugin->define_subplugin_structure($element));
}
}
}
/**
* As far as activity restore steps are implementing restore_subplugin stuff, they need to
* have the parent task available for wrapping purposes (get course/context....)
* @return restore_task
*/
public function get_task() {
return $this->task;
}
/**
* Adds support for the 'activity' path that is common to all the activities
* and will be processed globally here

View File

@ -159,6 +159,13 @@ abstract class restore_subplugin {
return $this->step->apply_date_offset($value);
}
/**
* Call the log function from the step.
*/
public function log($message, $level, $a = null, $depth = null, $display = false) {
return $this->step->log($message, $level, $a, $depth, $display);
}
/**
* Returns the value of one (task/plan) setting
*/

View File

@ -34,10 +34,12 @@ abstract class backup_structure_dbops extends backup_dbops {
public static function get_iterator($element, $params, $processor) {
global $DB;
// Check we are going to get_iterator for one backup_nested_element
if (! $element instanceof backup_nested_element) {
throw new base_element_struct_exception('backup_nested_element_expected');
}
// If var_array, table and sql are null, and element has no final elements it is one nested element without source
// Just return one 1 element iterator without information
if ($element->get_source_array() === null && $element->get_source_table() === null &&
@ -58,7 +60,7 @@ abstract class backup_structure_dbops extends backup_dbops {
}
}
protected static function convert_params_to_values($params, $processor) {
public static function convert_params_to_values($params, $processor) {
$newparams = array();
foreach ($params as $key => $param) {
$newvalue = null;

View File

@ -162,6 +162,83 @@ abstract class backup_structure_step extends backup_step {
}
}
/**
* Add subplugin structure for a given plugin to any element in the structure backup tree.
*
* This method allows the injection of subplugins (of a specified plugin) data to any
* element in any backup structure.
*
* NOTE: Initially subplugins were only available for activities (mod), so only the
* {@link backup_activity_structure_step} class had support for them, always
* looking for /mod/modulenanme subplugins. This new method is a generalization of the
* existing one for activities, supporting all subplugins injecting information everywhere.
*
* @param string $subplugintype type of subplugin as defined in plugin's db/subplugins.php.
* @param backup_nested_element $element element in the backup tree (anywhere) that
* we are going to add subplugin information to.
* @param bool $multiple to define if multiple subplugins can produce information
* for each instance of $element (true) or no (false).
* @param string $plugintype type of the plugin.
* @param string $pluginname name of the plugin.
* @return void
*/
protected function add_subplugin_structure($subplugintype, $element, $multiple, $plugintype = null, $pluginname = null) {
// Verify if this is a BC call for an activity backup. See NOTE above for this special case.
if ($plugintype === null and $pluginname === null) {
$plugintype = 'mod';
$pluginname = $this->task->get_modulename();
// TODO: Once all the calls have been changed to add both not null plugintype and pluginname, add a debugging here.
}
// Check the requested plugintype is a valid one.
if (!array_key_exists($plugintype, core_component::get_plugin_types())) {
throw new backup_step_exception('incorrect_plugin_type', $plugintype);
}
// Check the requested pluginname, for the specified plugintype, is a valid one.
if (!array_key_exists($pluginname, core_component::get_plugin_list($plugintype))) {
throw new backup_step_exception('incorrect_plugin_name', array($plugintype, $pluginname));
}
// Check the requested subplugintype is a valid one.
$subpluginsfile = core_component::get_component_directory($plugintype . '_' . $pluginname) . '/db/subplugins.php';
if (!file_exists($subpluginsfile)) {
throw new backup_step_exception('plugin_missing_subplugins_php_file', array($plugintype, $pluginname));
}
include($subpluginsfile);
if (!array_key_exists($subplugintype, $subplugins)) {
throw new backup_step_exception('incorrect_subplugin_type', $subplugintype);
}
// Arrived here, subplugin is correct, let's create the optigroup.
$optigroupname = $subplugintype . '_' . $element->get_name() . '_subplugin';
$optigroup = new backup_optigroup($optigroupname, null, $multiple);
$element->add_child($optigroup); // Add optigroup to stay connected since beginning.
// Every subplugin optionally can have a common/parent subplugin
// class for shared stuff.
$parentclass = 'backup_' . $plugintype . '_' . $pluginname . '_' . $subplugintype . '_subplugin';
$parentfile = core_component::get_component_directory($plugintype . '_' . $pluginname) .
'/backup/moodle2/' . $parentclass . '.class.php';
if (file_exists($parentfile)) {
require_once($parentfile);
}
// Get all the optigroup_elements, looking over all the subplugin dirs.
$subpluginsdirs = core_component::get_plugin_list($subplugintype);
foreach ($subpluginsdirs as $name => $subpluginsdir) {
$classname = 'backup_' . $subplugintype . '_' . $name . '_subplugin';
$backupfile = $subpluginsdir . '/backup/moodle2/' . $classname . '.class.php';
if (file_exists($backupfile)) {
require_once($backupfile);
$backupsubplugin = new $classname($subplugintype, $name, $optigroup, $this);
// Add subplugin returned structure to optigroup.
$backupsubplugin->define_subplugin_structure($element->get_name());
}
}
}
/**
* To conditionally decide if one step will be executed or no
*
@ -175,8 +252,9 @@ abstract class backup_structure_step extends backup_step {
}
/**
* Function that will return the structure to be processed by this backup_step.
* Must return one backup_nested_element
* Define the structure to be processed by this backup step.
*
* @return backup_nested_element
*/
abstract protected function define_structure();
}

View File

@ -294,6 +294,76 @@ abstract class restore_structure_step extends restore_step {
}
}
/**
* Add subplugin structure for a given plugin to any element in the structure restore tree
*
* This method allows the injection of subplugins (of a specific plugin) parsing and proccessing
* to any element in the restore structure.
*
* NOTE: Initially subplugins were only available for activities (mod), so only the
* {@link restore_activity_structure_step} class had support for them, always
* looking for /mod/modulenanme subplugins. This new method is a generalization of the
* existing one for activities, supporting all subplugins injecting information everywhere.
*
* @param string $subplugintype type of subplugin as defined in plugin's db/subplugins.php.
* @param restore_path_element $element element in the structure restore tree that
* we are going to add subplugin information to.
* @param string $plugintype type of the plugin.
* @param string $pluginname name of the plugin.
* @return void
*/
protected function add_subplugin_structure($subplugintype, $element, $plugintype = null, $pluginname = null) {
// Verify if this is a BC call for an activity restore. See NOTE above for this special case.
if ($plugintype === null and $pluginname === null) {
$plugintype = 'mod';
$pluginname = $this->task->get_modulename();
// TODO: Once all the calls have been changed to add both not null plugintype and pluginname, add a debugging here.
}
// Check the requested plugintype is a valid one.
if (!array_key_exists($plugintype, core_component::get_plugin_types())) {
throw new restore_step_exception('incorrect_plugin_type', $plugintype);
}
// Check the requested pluginname, for the specified plugintype, is a valid one.
if (!array_key_exists($pluginname, core_component::get_plugin_list($plugintype))) {
throw new restore_step_exception('incorrect_plugin_name', array($plugintype, $pluginname));
}
// Check the requested subplugintype is a valid one.
$subpluginsfile = core_component::get_component_directory($plugintype . '_' . $pluginname) . '/db/subplugins.php';
if (!file_exists($subpluginsfile)) {
throw new restore_step_exception('plugin_missing_subplugins_php_file', array($plugintype, $pluginname));
}
include($subpluginsfile);
if (!array_key_exists($subplugintype, $subplugins)) {
throw new restore_step_exception('incorrect_subplugin_type', $subplugintype);
}
// Every subplugin optionally can have a common/parent subplugin
// class for shared stuff.
$parentclass = 'restore_' . $plugintype . '_' . $pluginname . '_' . $subplugintype . '_subplugin';
$parentfile = core_component::get_component_directory($plugintype . '_' . $pluginname) .
'/backup/moodle2/' . $parentclass . '.class.php';
if (file_exists($parentfile)) {
require_once($parentfile);
}
// Get all the restore path elements, looking across all the subplugin dirs.
$subpluginsdirs = core_component::get_plugin_list($subplugintype);
foreach ($subpluginsdirs as $name => $subpluginsdir) {
$classname = 'restore_' . $subplugintype . '_' . $name . '_subplugin';
$restorefile = $subpluginsdir . '/backup/moodle2/' . $classname . '.class.php';
if (file_exists($restorefile)) {
require_once($restorefile);
$restoresubplugin = new $classname($subplugintype, $name, $this);
// Add subplugin paths to the step.
$this->prepare_pathelements($restoresubplugin->define_subplugin_structure($element));
}
}
}
/**
* Launch all the after_execute methods present in all the processing objects
*

View File

@ -26,6 +26,7 @@ defined('MOODLE_INTERNAL') || die();
// Include all the needed stuff
global $CFG;
require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');
require_once($CFG->dirroot . '/backup/util/includes/restore_includes.php');
/**
@ -61,6 +62,9 @@ class mock_backup_step extends backup_step {
*/
class mock_backup_task_basepath extends backup_task {
/** @var string name of the mod plugin (activity) being used in the tests */
private $modulename;
public function build() {
// Nothing to do
}
@ -73,6 +77,39 @@ class mock_backup_task_basepath extends backup_task {
global $CFG;
return $CFG->tempdir . '/test';
}
public function set_modulename($modulename) {
$this->modulename = $modulename;
}
public function get_modulename() {
return $this->modulename;
}
}
/**
* Instantiable class extending restore_task in order to mockup get_taskbasepath()
*/
class mock_restore_task_basepath extends restore_task {
/** @var string name of the mod plugin (activity) being used in the tests */
private $modulename;
public function build() {
// Nothing to do.
}
public function define_settings() {
// Nothing to do.
}
public function set_modulename($modulename) {
$this->modulename = $modulename;
}
public function get_modulename() {
return $this->modulename;
}
}
/**
@ -80,7 +117,7 @@ class mock_backup_task_basepath extends backup_task {
*/
class mock_backup_structure_step extends backup_structure_step {
protected function define_structure() {
public function define_structure() {
// Create really simple structure (1 nested with 1 attr and 2 fields)
$test = new backup_nested_element('test',
@ -91,6 +128,35 @@ class mock_backup_structure_step extends backup_structure_step {
return $test;
}
public function add_plugin_structure($plugintype, $element, $multiple) {
parent::add_plugin_structure($plugintype, $element, $multiple);
}
public function add_subplugin_structure($subplugintype, $element, $multiple, $plugintype = null, $pluginname = null) {
parent::add_subplugin_structure($subplugintype, $element, $multiple, $plugintype, $pluginname);
}
}
class mock_restore_structure_step extends restore_structure_step {
public function define_structure() {
// Create a really simple structure (1 element).
$test = new restore_path_element('test', '/tests/test');
return array($test);
}
public function add_plugin_structure($plugintype, $element) {
parent::add_plugin_structure($plugintype, $element);
}
public function add_subplugin_structure($subplugintype, $element, $plugintype = null, $pluginname = null) {
parent::add_subplugin_structure($subplugintype, $element, $plugintype, $pluginname);
}
public function get_pathelements() {
return $this->pathelements;
}
}
/**

View File

@ -134,6 +134,261 @@ class backup_step_testcase extends advanced_testcase {
@remove_dir(dirname($file));
}
/**
* Verify the add_plugin_structure() backup method behavior and created structures.
*/
public function test_backup_structure_step_add_plugin_structure() {
// Create mocked task, step and element.
$bt = new mock_backup_task_basepath('taskname');
$bs = new mock_backup_structure_step('steptest', null, $bt);
$el = new backup_nested_element('question', array('id'), array('one', 'two', 'qtype'));
// Wrong plugintype.
try {
$bs->add_plugin_structure('fakeplugin', $el, true);
$this->assertTrue(false, 'base_step_exception expected');
} catch (exception $e) {
$this->assertTrue($e instanceof backup_step_exception);
$this->assertEquals('incorrect_plugin_type', $e->errorcode);
}
// Correct plugintype qtype call (@ 'question' level).
$bs->add_plugin_structure('qtype', $el, false);
$ch = $el->get_children();
$this->assertEquals(1, count($ch));
$og = reset($ch);
$this->assertTrue($og instanceof backup_optigroup);
$ch = $og->get_children();
$this->assertTrue(array_key_exists('optigroup_qtype_calculatedsimple_question', $ch));
$this->assertTrue($ch['optigroup_qtype_calculatedsimple_question'] instanceof backup_plugin_element);
}
/**
* Verify the add_subplugin_structure() backup method behavior and created structures.
*/
public function test_backup_structure_step_add_subplugin_structure() {
// Create mocked task, step and element.
$bt = new mock_backup_task_basepath('taskname');
$bs = new mock_backup_structure_step('steptest', null, $bt);
$el = new backup_nested_element('workshop', array('id'), array('one', 'two', 'qtype'));
// Wrong plugin type.
try {
$bs->add_subplugin_structure('fakesubplugin', $el, true, 'fakeplugintype', 'fakepluginname');
$this->assertTrue(false, 'base_step_exception expected');
} catch (exception $e) {
$this->assertTrue($e instanceof backup_step_exception);
$this->assertEquals('incorrect_plugin_type', $e->errorcode);
}
// Wrong plugin type.
try {
$bs->add_subplugin_structure('fakesubplugin', $el, true, 'mod', 'fakepluginname');
$this->assertTrue(false, 'base_step_exception expected');
} catch (exception $e) {
$this->assertTrue($e instanceof backup_step_exception);
$this->assertEquals('incorrect_plugin_name', $e->errorcode);
}
// Wrong plugin not having subplugins.
try {
$bs->add_subplugin_structure('fakesubplugin', $el, true, 'mod', 'page');
$this->assertTrue(false, 'base_step_exception expected');
} catch (exception $e) {
$this->assertTrue($e instanceof backup_step_exception);
$this->assertEquals('plugin_missing_subplugins_php_file', $e->errorcode);
}
// Wrong BC (defaulting to mod and modulename) use not having subplugins.
try {
$bt->set_modulename('page');
$bs->add_subplugin_structure('fakesubplugin', $el, true);
$this->assertTrue(false, 'base_step_exception expected');
} catch (exception $e) {
$this->assertTrue($e instanceof backup_step_exception);
$this->assertEquals('plugin_missing_subplugins_php_file', $e->errorcode);
}
// Wrong subplugin type.
try {
$bs->add_subplugin_structure('fakesubplugin', $el, true, 'mod', 'workshop');
$this->assertTrue(false, 'base_step_exception expected');
} catch (exception $e) {
$this->assertTrue($e instanceof backup_step_exception);
$this->assertEquals('incorrect_subplugin_type', $e->errorcode);
}
// Wrong BC subplugin type.
try {
$bt->set_modulename('workshop');
$bs->add_subplugin_structure('fakesubplugin', $el, true);
$this->assertTrue(false, 'base_step_exception expected');
} catch (exception $e) {
$this->assertTrue($e instanceof backup_step_exception);
$this->assertEquals('incorrect_subplugin_type', $e->errorcode);
}
// Correct call to workshopform subplugin (@ 'workshop' level).
$bs->add_subplugin_structure('workshopform', $el, true, 'mod', 'workshop');
$ch = $el->get_children();
$this->assertEquals(1, count($ch));
$og = reset($ch);
$this->assertTrue($og instanceof backup_optigroup);
$ch = $og->get_children();
$this->assertTrue(array_key_exists('optigroup_workshopform_accumulative_workshop', $ch));
$this->assertTrue($ch['optigroup_workshopform_accumulative_workshop'] instanceof backup_subplugin_element);
// Correct BC call to workshopform subplugin (@ 'assessment' level).
$el = new backup_nested_element('assessment', array('id'), array('one', 'two', 'qtype'));
$bt->set_modulename('workshop');
$bs->add_subplugin_structure('workshopform', $el, true);
$ch = $el->get_children();
$this->assertEquals(1, count($ch));
$og = reset($ch);
$this->assertTrue($og instanceof backup_optigroup);
$ch = $og->get_children();
$this->assertTrue(array_key_exists('optigroup_workshopform_accumulative_assessment', $ch));
$this->assertTrue($ch['optigroup_workshopform_accumulative_assessment'] instanceof backup_subplugin_element);
// TODO: Add some test covering a non-mod subplugin once we have some implemented in core.
}
/**
* Verify the add_plugin_structure() restore method behavior and created structures.
*/
public function test_restore_structure_step_add_plugin_structure() {
// Create mocked task, step and element.
$bt = new mock_restore_task_basepath('taskname');
$bs = new mock_restore_structure_step('steptest', null, $bt);
$el = new restore_path_element('question', '/some/path/to/question');
// Wrong plugintype.
try {
$bs->add_plugin_structure('fakeplugin', $el);
$this->assertTrue(false, 'base_step_exception expected');
} catch (exception $e) {
$this->assertTrue($e instanceof restore_step_exception);
$this->assertEquals('incorrect_plugin_type', $e->errorcode);
}
// Correct plugintype qtype call (@ 'question' level).
$bs->add_plugin_structure('qtype', $el);
$patheles = $bs->get_pathelements();
// Verify some well-known qtype plugin restore_path_elements have been added.
$keys = array(
'/some/path/to/question/plugin_qtype_calculated_question/answers/answer',
'/some/path/to/question/plugin_qtype_calculated_question/dataset_definitions/dataset_definition',
'/some/path/to/question/plugin_qtype_calculated_question/calculated_options/calculated_option',
'/some/path/to/question/plugin_qtype_essay_question/essay',
'/some/path/to/question/plugin_qtype_random_question',
'/some/path/to/question/plugin_qtype_truefalse_question/answers/answer');
foreach ($keys as $key) {
// Verify the element exists.
$this->assertArrayHasKey($key, $patheles);
// Verify the element is a restore_path_element.
$this->assertTrue($patheles[$key] instanceof restore_path_element);
// Check it has a processing object.
$po = $patheles[$key]->get_processing_object();
$this->assertTrue($po instanceof restore_plugin);
}
}
/**
* Verify the add_subplugin_structure() restore method behavior and created structures.
*/
public function test_restore_structure_step_add_subplugin_structure() {
// Create mocked task, step and element.
$bt = new mock_restore_task_basepath('taskname');
$bs = new mock_restore_structure_step('steptest', null, $bt);
$el = new restore_path_element('workshop', '/path/to/workshop');
// Wrong plugin type.
try {
$bs->add_subplugin_structure('fakesubplugin', $el, 'fakeplugintype', 'fakepluginname');
$this->assertTrue(false, 'base_step_exception expected');
} catch (exception $e) {
$this->assertTrue($e instanceof restore_step_exception);
$this->assertEquals('incorrect_plugin_type', $e->errorcode);
}
// Wrong plugin type.
try {
$bs->add_subplugin_structure('fakesubplugin', $el, 'mod', 'fakepluginname');
$this->assertTrue(false, 'base_step_exception expected');
} catch (exception $e) {
$this->assertTrue($e instanceof restore_step_exception);
$this->assertEquals('incorrect_plugin_name', $e->errorcode);
}
// Wrong plugin not having subplugins.
try {
$bs->add_subplugin_structure('fakesubplugin', $el, 'mod', 'page');
$this->assertTrue(false, 'base_step_exception expected');
} catch (exception $e) {
$this->assertTrue($e instanceof restore_step_exception);
$this->assertEquals('plugin_missing_subplugins_php_file', $e->errorcode);
}
// Wrong BC (defaulting to mod and modulename) use not having subplugins.
try {
$bt->set_modulename('page');
$bs->add_subplugin_structure('fakesubplugin', $el);
$this->assertTrue(false, 'base_step_exception expected');
} catch (exception $e) {
$this->assertTrue($e instanceof restore_step_exception);
$this->assertEquals('plugin_missing_subplugins_php_file', $e->errorcode);
}
// Wrong subplugin type.
try {
$bs->add_subplugin_structure('fakesubplugin', $el, 'mod', 'workshop');
$this->assertTrue(false, 'base_step_exception expected');
} catch (exception $e) {
$this->assertTrue($e instanceof restore_step_exception);
$this->assertEquals('incorrect_subplugin_type', $e->errorcode);
}
// Wrong BC subplugin type.
try {
$bt->set_modulename('workshop');
$bs->add_subplugin_structure('fakesubplugin', $el);
$this->assertTrue(false, 'base_step_exception expected');
} catch (exception $e) {
$this->assertTrue($e instanceof restore_step_exception);
$this->assertEquals('incorrect_subplugin_type', $e->errorcode);
}
// Correct call to workshopform subplugin (@ 'workshop' level).
$bt = new mock_restore_task_basepath('taskname');
$bs = new mock_restore_structure_step('steptest', null, $bt);
$el = new restore_path_element('workshop', '/path/to/workshop');
$bs->add_subplugin_structure('workshopform', $el, 'mod', 'workshop');
$patheles = $bs->get_pathelements();
// Verify some well-known workshopform subplugin restore_path_elements have been added.
$keys = array(
'/path/to/workshop/subplugin_workshopform_accumulative_workshop/workshopform_accumulative_dimension',
'/path/to/workshop/subplugin_workshopform_comments_workshop/workshopform_comments_dimension',
'/path/to/workshop/subplugin_workshopform_numerrors_workshop/workshopform_numerrors_map',
'/path/to/workshop/subplugin_workshopform_rubric_workshop/workshopform_rubric_config');
foreach ($keys as $key) {
// Verify the element exists.
$this->assertArrayHasKey($key, $patheles);
// Verify the element is a restore_path_element.
$this->assertTrue($patheles[$key] instanceof restore_path_element);
// Check it has a processing object.
$po = $patheles[$key]->get_processing_object();
$this->assertTrue($po instanceof restore_subplugin);
}
// Correct BC call to workshopform subplugin (@ 'assessment' level).
$bt = new mock_restore_task_basepath('taskname');
$bs = new mock_restore_structure_step('steptest', null, $bt);
$el = new restore_path_element('assessment', '/a/assessment');
$bt->set_modulename('workshop');
$bs->add_subplugin_structure('workshopform', $el);
$patheles = $bs->get_pathelements();
// Verify some well-known workshopform subplugin restore_path_elements have been added.
$keys = array(
'/a/assessment/subplugin_workshopform_accumulative_assessment/workshopform_accumulative_grade',
'/a/assessment/subplugin_workshopform_comments_assessment/workshopform_comments_grade',
'/a/assessment/subplugin_workshopform_numerrors_assessment/workshopform_numerrors_grade',
'/a/assessment/subplugin_workshopform_rubric_assessment/workshopform_rubric_grade');
foreach ($keys as $key) {
// Verify the element exists.
$this->assertArrayHasKey($key, $patheles);
// Verify the element is a restore_path_element.
$this->assertTrue($patheles[$key] instanceof restore_path_element);
// Check it has a processing object.
$po = $patheles[$key]->get_processing_object();
$this->assertTrue($po instanceof restore_subplugin);
}
// TODO: Add some test covering a non-mod subplugin once we have some implemented in core.
}
/**
* wrong base_step class tests
*/

View File

@ -77,4 +77,8 @@ abstract class assessable_uploaded extends base {
}
}
public static function get_other_mapping() {
// Nothing to map.
return false;
}
}

View File

@ -94,4 +94,15 @@ class badge_awarded extends base {
throw new \coding_exception('The \'objectid\' must be set.');
}
}
public static function get_objectid_mapping() {
return array('db' => 'badge', 'restore' => 'badge');
}
public static function get_other_mapping() {
$othermapped = array();
$othermapped['badgeissuedid'] = array('db' => 'badge_issued', 'restore' => base::NOT_MAPPED);
return $othermapped;
}
}

View File

@ -75,6 +75,11 @@ abstract class base implements \IteratorAggregate {
*/
const LEVEL_PARTICIPATING = 2;
/**
* The value used when an id can not be mapped during a restore.
*/
const NOT_MAPPED = -31337;
/** @var array event data */
protected $data;
@ -478,6 +483,79 @@ abstract class base implements \IteratorAggregate {
return $event;
}
/**
* This is used when restoring course logs where it is required that we
* map the objectid to it's new value in the new course.
*
* Does nothing in the base class except display a debugging message warning
* the user that the event does not contain the required functionality to
* map this information. For events that do not store an objectid this won't
* be called, so no debugging message will be displayed.
*
* Example of usage:
*
* return array('db' => 'assign_submissions', 'restore' => 'submission');
*
* If the objectid can not be mapped during restore set the value to \core\event\base::NOT_MAPPED, example -
*
* return array('db' => 'some_table', 'restore' => \core\event\base::NOT_MAPPED);
*
* Note - it isn't necessary to specify the 'db' and 'restore' values in this case, so you can also use -
*
* return \core\event\base::NOT_MAPPED;
*
* The 'db' key refers to the database table and the 'restore' key refers to
* the name of the restore element the objectid is associated with. In many
* cases these will be the same.
*
* @return string the name of the restore mapping the objectid links to
*/
public static function get_objectid_mapping() {
debugging('In order to restore course logs accurately the event "' . get_called_class() . '" must define the
function get_objectid_mapping().', DEBUG_DEVELOPER);
return false;
}
/**
* This is used when restoring course logs where it is required that we
* map the information in 'other' to it's new value in the new course.
*
* Does nothing in the base class except display a debugging message warning
* the user that the event does not contain the required functionality to
* map this information. For events that do not store any other information this
* won't be called, so no debugging message will be displayed.
*
* Example of usage:
*
* $othermapped = array();
* $othermapped['discussionid'] = array('db' => 'forum_discussions', 'restore' => 'forum_discussion');
* $othermapped['forumid'] = array('db' => 'forum', 'restore' => 'forum');
* return $othermapped;
*
* If an id can not be mapped during restore we set it to \core\event\base::NOT_MAPPED, example -
*
* $othermapped = array();
* $othermapped['someid'] = array('db' => 'some_table', 'restore' => \core\event\base::NOT_MAPPED);
* return $othermapped;
*
* Note - it isn't necessary to specify the 'db' and 'restore' values in this case, so you can also use -
*
* $othermapped = array();
* $othermapped['someid'] = \core\event\base::NOT_MAPPED;
* return $othermapped;
*
* The 'db' key refers to the database table and the 'restore' key refers to
* the name of the restore element the other value is associated with. In many
* cases these will be the same.
*
* @return array an array of other values and their corresponding mapping
*/
public static function get_other_mapping() {
debugging('In order to restore course logs accurately the event "' . get_called_class() . '" must define the
function get_other_mapping().', DEBUG_DEVELOPER);
}
/**
* Get static information about an event.
* This is used in reports and is not for general use.

View File

@ -125,4 +125,18 @@ class blog_association_created extends base {
throw new \coding_exception('The \'subject\' value must be set in other.');
}
}
public static function get_objectid_mapping() {
// Blogs are not included in backups, so no mapping required for restore.
return array('db' => 'blog_association', 'restore' => base::NOT_MAPPED);
}
public static function get_other_mapping() {
// Blogs are not included in backups, so no mapping required for restore.
$othermapped = array();
$othermapped['blogid'] = array('db' => 'post', 'restore' => base::NOT_MAPPED);
// The associateid field is varying (context->instanceid) so cannot be mapped.
return $othermapped;
}
}

View File

@ -52,4 +52,10 @@ class blog_comment_created extends comment_created {
public function get_description() {
return "The user with id '$this->userid' added the comment to the blog with id '{$this->other['itemid']}'.";
}
public static function get_other_mapping() {
$othermapped = array();
$othermapped['itemid'] = array('db' => 'post', 'restore' => base::NOT_MAPPED);
return $othermapped;
}
}

View File

@ -52,4 +52,10 @@ class blog_comment_deleted extends comment_deleted {
public function get_description() {
return "The user with id '$this->userid' deleted the comment for the blog with id '{$this->other['itemid']}'.";
}
public static function get_other_mapping() {
$othermapped = array();
$othermapped['itemid'] = array('db' => 'post', 'restore' => base::NOT_MAPPED);
return $othermapped;
}
}

View File

@ -106,4 +106,16 @@ class blog_entries_viewed extends base {
$url = new \moodle_url('index.php', $params);
return array (SITEID, 'blog', 'view', $url->out(), 'view blog entry');
}
public static function get_other_mapping() {
$othermapped = array();
$othermapped['entryid'] = array('db' => 'post', 'restore' => base::NOT_MAPPED);
$othermapped['tagid'] = array('db' => 'tag', 'restore' => base::NOT_MAPPED);
$othermapped['userid'] = array('db' => 'user', 'restore' => 'user');
$othermapped['modid'] = array('db' => 'course_modules', 'restore' => 'course_module');
$othermapped['groupid'] = array('db' => 'groups', 'restore' => 'group');
$othermapped['courseid'] = array('db' => 'course', 'restore' => 'course');
return $othermapped;
}
}

View File

@ -140,4 +140,9 @@ class blog_entry_created extends base {
throw new \coding_exception('The \'relateduserid\' must be set.');
}
}
public static function get_objectid_mapping() {
// Blogs are not backed up, so no mapping required for restore.
return array('db' => 'post', 'restore' => base::NOT_MAPPED);
}
}

View File

@ -131,4 +131,9 @@ class blog_entry_deleted extends base {
throw new \coding_exception('The \'relateduserid\' must be set.');
}
}
public static function get_objectid_mapping() {
// Blogs are not backed up, so no need for mapping for restore.
return array('db' => 'post', 'restore' => base::NOT_MAPPED);
}
}

View File

@ -138,5 +138,10 @@ class blog_entry_updated extends base {
throw new \coding_exception('The \'relateduserid\' must be set.');
}
}
public static function get_objectid_mapping() {
// Blogs are not backed up, so no need for mapping for restore.
return array('db' => 'post', 'restore' => NOT_MAPPED);
}
}

View File

@ -111,4 +111,15 @@ class calendar_event_created extends base {
throw new \coding_exception('The \'timestart\' value must be set in other.');
}
}
public static function get_objectid_mapping() {
return array('db' => 'event', 'restore' => 'event');
}
public static function get_other_mapping() {
$othermapped = array();
$othermapped['repeatid'] = array('db' => 'event', 'restore' => 'event');
return $othermapped;
}
}

View File

@ -92,4 +92,15 @@ class calendar_event_deleted extends base {
throw new \coding_exception('The \'timestart\' value must be set in other.');
}
}
public static function get_objectid_mapping() {
return array('db' => 'event', 'restore' => 'event');
}
public static function get_other_mapping() {
$othermapped = array();
$othermapped['repeatid'] = array('db' => 'event', 'restore' => 'event');
return $othermapped;
}
}

View File

@ -110,4 +110,15 @@ class calendar_event_updated extends base {
throw new \coding_exception('The \'timestart\' value must be set in other.');
}
}
public static function get_objectid_mapping() {
return array('db' => 'event', 'restore' => 'event');
}
public static function get_other_mapping() {
$othermapped = array();
$othermapped['repeatid'] = array('db' => 'event', 'restore' => 'event');
return $othermapped;
}
}

View File

@ -90,4 +90,9 @@ class cohort_created extends base {
protected function get_legacy_eventdata() {
return $this->get_record_snapshot('cohort', $this->objectid);
}
public static function get_objectid_mapping() {
// Cohorts are not included in backups, so no mapping is needed for restore.
return array('db' => 'cohort', 'restore' => base::NOT_MAPPED);
}
}

View File

@ -90,4 +90,9 @@ class cohort_deleted extends base {
protected function get_legacy_eventdata() {
return $this->get_record_snapshot('cohort', $this->objectid);
}
public static function get_objectid_mapping() {
// Cohorts are not included in backups, so no mapping is needed for restore.
return array('db' => 'cohort', 'restore' => base::NOT_MAPPED);
}
}

View File

@ -108,4 +108,9 @@ class cohort_member_added extends base {
throw new \coding_exception('The \'relateduserid\' must be set.');
}
}
public static function get_objectid_mapping() {
// Cohorts are not included in backups, so no mapping is needed for restore.
return array('db' => 'cohort', 'restore' => base::NOT_MAPPED);
}
}

View File

@ -109,4 +109,9 @@ class cohort_member_removed extends base {
throw new \coding_exception('The \'relateduserid\' must be set.');
}
}
public static function get_objectid_mapping() {
// Cohorts are not included in backups, so no mapping is needed for restore.
return array('db' => 'cohort', 'restore' => base::NOT_MAPPED);
}
}

View File

@ -90,4 +90,9 @@ class cohort_updated extends base {
protected function get_legacy_eventdata() {
return $this->get_record_snapshot('cohort', $this->objectid);
}
public static function get_objectid_mapping() {
// Cohorts are not included in backups, so no mapping is needed for restore.
return array('db' => 'cohort', 'restore' => base::NOT_MAPPED);
}
}

View File

@ -100,4 +100,15 @@ abstract class comment_created extends base {
throw new \coding_exception('The \'itemid\' value must be set in other.');
}
}
public static function get_objectid_mapping() {
return array('db' => 'comments', 'restore' => 'comment');
}
public static function get_other_mapping() {
// We cannot map fields that do not have a 1:1 mapping.
$othermapped = array();
$othermapped['itemid'] = base::NOT_MAPPED;
return $othermapped;
}
}

View File

@ -100,4 +100,15 @@ abstract class comment_deleted extends base {
throw new \coding_exception('The \'itemid\' value must be set in other.');
}
}
public static function get_objectid_mapping() {
return array('db' => 'comments', 'restore' => 'comment');
}
public static function get_other_mapping() {
// We cannot map fields that do not have a 1:1 mapping.
$othermapped = array();
$othermapped['itemid'] = base::NOT_MAPPED;
return $othermapped;
}
}

View File

@ -126,5 +126,9 @@ abstract class content_viewed extends base {
throw new \coding_exception('The \'content\' value must be set in other.');
}
}
public static function get_other_mapping() {
return false;
}
}

View File

@ -80,4 +80,9 @@ class course_category_created extends base {
protected function get_legacy_logdata() {
return array(SITEID, 'category', 'add', 'editcategory.php?id=' . $this->objectid, $this->objectid);
}
public static function get_objectid_mapping() {
// Categories are not backed up, so no need to map them on restore.
return array('db' => 'course_categories', 'restore' => base::NOT_MAPPED);
}
}

View File

@ -136,4 +136,13 @@ class course_category_deleted extends base {
throw new \coding_exception('The \'name\' value must be set in other.');
}
}
public static function get_objectid_mapping() {
// Categories are not backed up, so no need to map them on restore.
return array('db' => 'course_categories', 'restore' => base::NOT_MAPPED);
}
public static function get_other_mapping() {
return false;
}
}

View File

@ -96,4 +96,9 @@ class course_category_updated extends base {
return array(SITEID, 'category', 'update', 'editcategory.php?id=' . $this->objectid, $this->objectid);
}
public static function get_objectid_mapping() {
// Categories are not backed up, so no need to map them on restore.
return array('db' => 'course_categories', 'restore' => base::NOT_MAPPED);
}
}

View File

@ -134,4 +134,15 @@ class course_completed extends base {
throw new \coding_exception('The \'relateduserid\' value must be set in other.');
}
}
public static function get_objectid_mapping() {
// Sorry - there is no mapping available for completion records.
return array('db' => 'course_completions', 'restore' => base::NOT_MAPPED);
}
public static function get_other_mapping() {
$othermapped = array();
$othermapped['relateduserid'] = array('db' => 'user', 'restore' => 'user');
return $othermapped;
}
}

View File

@ -104,4 +104,12 @@ class course_content_deleted extends base {
throw new \coding_exception('The \'options\' value must be set in other.');
}
}
public static function get_objectid_mapping() {
return array('db' => 'course', 'restore' => 'course');
}
public static function get_other_mapping() {
return false;
}
}

View File

@ -119,4 +119,13 @@ class course_created extends base {
throw new \coding_exception('The \'fullname\' value must be set in other.');
}
}
public static function get_objectid_mapping() {
return array('db' => 'course', 'restore' => 'course');
}
public static function get_other_mapping() {
// Nothing to map.
return false;
}
}

View File

@ -114,4 +114,13 @@ class course_deleted extends base {
throw new \coding_exception('The \'fullname\' value must be set in other.');
}
}
public static function get_objectid_mapping() {
return array('db' => 'course', 'restore' => 'course');
}
public static function get_other_mapping() {
// Nothing to map.
return false;
}
}

View File

@ -29,6 +29,12 @@ defined('MOODLE_INTERNAL') || die();
/**
* Course module completion event class.
*
* @property-read array $other {
* Extra information about event.
*
* - int relateduserid: (optional) the related user id.
* }
*
* @package core
* @since Moodle 2.6
* @copyright 2013 Rajesh Taneja <rajesh@moodle.com>
@ -107,4 +113,16 @@ class course_module_completion_updated extends base {
throw new \coding_exception('The \'relateduserid\' must be set.');
}
}
public static function get_objectid_mapping() {
// Sorry mapping info is not available for course modules completion records.
return array('db' => 'course_modules_completion', 'restore' => base::NOT_MAPPED);
}
public static function get_other_mapping() {
$othermapped = array();
$othermapped['relateduserid'] = array('db' => 'user', 'restore' => 'user');
return $othermapped;
}
}

View File

@ -165,5 +165,16 @@ class course_module_created extends base {
throw new \coding_exception('The \'name\' value must be set in other.');
}
}
public static function get_objectid_mapping() {
return array('db' => 'course_modules', 'restore' => 'course_module');
}
public static function get_other_mapping() {
$othermapped = array();
$othermapped['instanceid'] = base::NOT_MAPPED;
return $othermapped;
}
}

View File

@ -119,5 +119,16 @@ class course_module_deleted extends base {
throw new \coding_exception('The \'instanceid\' value must be set in other.');
}
}
public static function get_objectid_mapping() {
return array('db' => 'course_modules', 'restore' => 'course_module');
}
public static function get_other_mapping() {
$othermapped = array();
$othermapped['instanceid'] = base::NOT_MAPPED;
return $othermapped;
}
}

View File

@ -163,5 +163,16 @@ class course_module_updated extends base {
));
return $event;
}
public static function get_objectid_mapping() {
return array('db' => 'course_modules', 'restore' => 'course_module');
}
public static function get_other_mapping() {
$othermapping = array();
$othermapping['instanceid'] = base::NOT_MAPPED;
return $othermapping;
}
}

View File

@ -90,4 +90,9 @@ class course_reset_ended extends base {
throw new \coding_exception('The \'reset_options\' value must be set in other.');
}
}
public static function get_other_mapping() {
// Nothing to map.
return false;
}
}

View File

@ -90,4 +90,8 @@ class course_reset_started extends base {
throw new \coding_exception('The \'reset_options\' value must be set in other.');
}
}
public static function get_other_mapping() {
return false;
}
}

View File

@ -137,4 +137,13 @@ class course_restored extends base {
throw new \coding_exception('The \'samesite\' value must be set in other.');
}
}
public static function get_objectid_mapping() {
return array('db' => 'course', 'restore' => 'course');
}
public static function get_other_mapping() {
// No need to map anything.
return false;
}
}

View File

@ -104,4 +104,13 @@ class course_section_updated extends base {
throw new \coding_exception('The \'sectionnum\' value must be set in other.');
}
}
public static function get_objectid_mapping() {
return array('db' => 'course_sections', 'restore' => 'course_section');
}
public static function get_other_mapping() {
// Nothing to map.
return false;
}
}

View File

@ -117,4 +117,13 @@ class course_updated extends base {
protected function get_legacy_logdata() {
return $this->legacylogdata;
}
public static function get_objectid_mapping() {
return array('db' => 'course', 'restore' => 'course');
}
public static function get_other_mapping() {
// Nothing to map.
return false;
}
}

View File

@ -114,4 +114,9 @@ class course_user_report_viewed extends base {
throw new \coding_exception('The \'mode\' value must be set in other.');
}
}
public static function get_other_mapping() {
// Nothing to map.
return false;
}
}

View File

@ -141,4 +141,9 @@ class course_viewed extends base {
throw new \coding_exception('Context level must be CONTEXT_COURSE.');
}
}
public static function get_other_mapping() {
// No mapping required.
return false;
}
}

View File

@ -30,6 +30,14 @@ defined('MOODLE_INTERNAL') || die();
/**
* Email failed event class.
*
* @property-read array $other {
* Extra information about event.
*
* - string subject: the message subject.
* - string message: the message text.
* - string errorinfo: the error info.
* }
*
* @package core
* @since Moodle 2.7
* @copyright 2013 Mark Nelson <markn@moodle.com>
@ -94,4 +102,8 @@ class email_failed extends base {
throw new \coding_exception('The \'errorinfo\' value must be set in other.');
}
}
public static function get_other_mapping() {
return false;
}
}

View File

@ -106,4 +106,13 @@ class enrol_instance_created extends base {
throw new \coding_exception('The \'enrol\' value must be set in other.');
}
}
public static function get_objectid_mapping() {
return array('db' => 'enrol', 'restore' => 'enrol');
}
public static function get_other_mapping() {
// Nothing to map.
return false;
}
}

View File

@ -107,4 +107,13 @@ class enrol_instance_deleted extends base {
throw new \coding_exception('The \'enrol\' value must be set in other.');
}
}
public static function get_objectid_mapping() {
return array('db' => 'enrol', 'restore' => 'enrol');
}
public static function get_other_mapping() {
// Nothing to map.
return false;
}
}

View File

@ -107,4 +107,13 @@ class enrol_instance_updated extends base {
throw new \coding_exception('The \'enrol\' value must be set in other.');
}
}
public static function get_objectid_mapping() {
return array('db' => 'enrol', 'restore' => 'enrol');
}
public static function get_other_mapping() {
// Nothing to map.
return false;
}
}

View File

@ -131,4 +131,15 @@ class grade_deleted extends base {
throw new \coding_exception('The \'overridden\' value must be set in other.');
}
}
public static function get_objectid_mapping() {
return array('db' => 'grade_grades', 'restore' => 'grade_grades');
}
public static function get_other_mapping() {
$othermapped = array();
$othermapped['itemid'] = array('db' => 'grade_items', 'restore' => 'grade_item');
return $othermapped;
}
}

View File

@ -90,4 +90,8 @@ class group_created extends base {
$this->data['edulevel'] = self::LEVEL_OTHER;
$this->data['objecttable'] = 'groups';
}
public static function get_objectid_mapping() {
return array('db' => 'groups', 'restore' => 'group');
}
}

View File

@ -90,4 +90,8 @@ class group_deleted extends base {
$this->data['edulevel'] = self::LEVEL_OTHER;
$this->data['objecttable'] = 'groups';
}
public static function get_objectid_mapping() {
return array('db' => 'groups', 'restore' => 'group');
}
}

View File

@ -125,4 +125,15 @@ class group_member_added extends base {
throw new \coding_exception('The \'itemid\' value must be set in other, even if empty.');
}
}
public static function get_objectid_mapping() {
return array('db' => 'groups', 'restore' => 'group');
}
public static function get_other_mapping() {
$othermapped = array();
$othermapped['itemid'] = base::NOT_MAPPED;
return $othermapped;
}
}

View File

@ -108,4 +108,9 @@ class group_member_removed extends base {
throw new \coding_exception('The \'relateduserid\' must be set.');
}
}
public static function get_objectid_mapping() {
return array('db' => 'groups', 'restore' => 'group');
}
}

View File

@ -90,4 +90,8 @@ class group_updated extends base {
$this->data['edulevel'] = self::LEVEL_OTHER;
$this->data['objecttable'] = 'groups';
}
public static function get_objectid_mapping() {
return array('db' => 'groups', 'restore' => 'group');
}
}

View File

@ -90,4 +90,8 @@ class grouping_created extends base {
$this->data['edulevel'] = self::LEVEL_OTHER;
$this->data['objecttable'] = 'groupings';
}
public static function get_objectid_mapping() {
return array('db' => 'groupings', 'restore' => 'grouping');
}
}

View File

@ -97,4 +97,8 @@ class grouping_deleted extends base {
$this->data['edulevel'] = self::LEVEL_OTHER;
$this->data['objecttable'] = 'groupings';
}
public static function get_objectid_mapping() {
return array('db' => 'groupings', 'restore' => 'grouping');
}
}

View File

@ -90,4 +90,8 @@ class grouping_updated extends base {
$this->data['edulevel'] = self::LEVEL_OTHER;
$this->data['objecttable'] = 'groupings';
}
public static function get_objectid_mapping() {
return array('db' => 'groupings', 'restore' => 'grouping');
}
}

View File

@ -94,4 +94,9 @@ class message_contact_added extends base {
throw new \coding_exception('The \'relateduserid\' must be set.');
}
}
public static function get_objectid_mapping() {
// Messaging contacts are not backed up, so no need to map them on restore.
return array('db' => 'message_contacts', 'restore' => base::NOT_MAPPED);
}
}

View File

@ -94,4 +94,9 @@ class message_contact_blocked extends base {
throw new \coding_exception('The \'relateduserid\' must be set.');
}
}
public static function get_objectid_mapping() {
// Messaging contacts are not backed up, so no need to map them on restore.
return array('db' => 'message_contacts', 'restore' => base::NOT_MAPPED);
}
}

View File

@ -94,4 +94,9 @@ class message_contact_removed extends base {
throw new \coding_exception('The \'relateduserid\' must be set.');
}
}
public static function get_objectid_mapping() {
// Messaging contacts are not backed up, so no need to map them on restore.
return array('db' => 'message_contacts', 'restore' => base::NOT_MAPPED);
}
}

View File

@ -94,4 +94,9 @@ class message_contact_unblocked extends base {
throw new \coding_exception('The \'relateduserid\' must be set.');
}
}
public static function get_objectid_mapping() {
// Messaging contacts are not backed up, so no need to map them on restore.
return array('db' => 'message_contacts', 'restore' => base::NOT_MAPPED);
}
}

View File

@ -142,4 +142,14 @@ class message_deleted extends base {
throw new \coding_exception('The \'useridto\' value must be set in other.');
}
}
public static function get_other_mapping() {
// Messages are not backed up, so no need to map them on restore.
$othermapped = array();
// The messageid table varies so it cannot be mapped.
$othermapped['messageid'] = array('db' => base::NOT_MAPPED, 'restore' => base::NOT_MAPPED);
$othermapped['useridfrom'] = array('db' => 'user', 'restore' => base::NOT_MAPPED);
$othermapped['useridto'] = array('db' => 'user', 'restore' => base::NOT_MAPPED);
return $othermapped;
}
}

View File

@ -144,4 +144,17 @@ class message_sent extends base {
throw new \coding_exception('The \'messageid\' value must be set in other.');
}
}
public static function get_objectid_mapping() {
// Messages are not backed up, so no need to map them.
return false;
}
public static function get_other_mapping() {
// Messages are not backed up, so no need to map them on restore.
$othermapped = array();
// The messages table could vary for older events - so cannot be mapped.
$othermapped['messageid'] = array('db' => base::NOT_MAPPED, 'restore' => base::NOT_MAPPED);
return $othermapped;
}
}

View File

@ -95,4 +95,17 @@ class message_viewed extends base {
throw new \coding_exception('The \'messageid\' value must be set in other.');
}
}
public static function get_objectid_mapping() {
// Messages are not backed up, so no need to map them.
return array('db' => 'message_read', 'restore' => base::NOT_MAPPED);
}
public static function get_other_mapping() {
// Messages are not backed up, so no need to map them on restore.
$othermapped = array();
// The messages table could vary for older events - so cannot be mapped.
$othermapped['messageid'] = array('db' => base::NOT_MAPPED, 'restore' => base::NOT_MAPPED);
return $othermapped;
}
}

View File

@ -113,4 +113,14 @@ class mnet_access_control_created extends base {
throw new \coding_exception('The \'accessctrl\' value must be set in other.');
}
}
public static function get_objectid_mapping() {
// Mnet info is not backed up, so no need to map on restore.
return array('db' => 'mnet_sso_access_control', 'restore' => base::NOT_MAPPED);
}
public static function get_other_mapping() {
// Nothing to map.
return false;
}
}

View File

@ -113,4 +113,14 @@ class mnet_access_control_updated extends base {
throw new \coding_exception('The \'accessctrl\' value must be set in other.');
}
}
public static function get_objectid_mapping() {
// Mnet info is not backed up, so no need to map on restore.
return array('db' => 'mnet_sso_access_control', 'restore' => base::NOT_MAPPED);
}
public static function get_other_mapping() {
// Nothing to map.
return false;
}
}

View File

@ -106,4 +106,14 @@ class note_created extends base {
throw new \coding_exception('The \'relateduserid\' must be set.');
}
}
public static function get_objectid_mapping() {
// Notes are not backed up, so no need to map on restore.
return array('db' => 'post', 'restore' => base::NOT_MAPPED);
}
public static function get_other_mapping() {
// Nothing to map.
return false;
}
}

View File

@ -96,4 +96,14 @@ class note_deleted extends base {
throw new \coding_exception('The \'relateduserid\' must be set.');
}
}
public static function get_objectid_mapping() {
// Notes are not backed up, so no need to map on restore.
return array('db' => 'post', 'restore' => base::NOT_MAPPED);
}
public static function get_other_mapping() {
// Nothing to map.
return false;
}
}

View File

@ -106,4 +106,14 @@ class note_updated extends base {
throw new \coding_exception('The \'relateduserid\' must be set.');
}
}
public static function get_objectid_mapping() {
// Notes are not backed up, so no need to map on restore.
return array('db' => 'post', 'restore' => base::NOT_MAPPED);
}
public static function get_other_mapping() {
// Nothing to map.
return false;
}
}

View File

@ -96,4 +96,8 @@ class question_category_created extends base {
// This is not related to individual quiz at all.
return null;
}
public static function get_objectid_mapping() {
return array('db' => 'question_categories', 'restore' => 'question_category');
}
}

View File

@ -131,4 +131,16 @@ class role_assigned extends base {
throw new \coding_exception('The \'component\' value must be set in other.');
}
}
public static function get_objectid_mapping() {
return array('db' => 'role', 'restore' => 'role');
}
public static function get_other_mapping() {
$othermapped = array();
$othermapped['id'] = array('db' => 'role_assignments', 'restore' => base::NOT_MAPPED);
$othermapped['itemid'] = base::NOT_MAPPED;
return $othermapped;
}
}

View File

@ -98,4 +98,8 @@ class role_capabilities_updated extends base {
protected function get_legacy_logdata() {
return $this->legacylogdata;
}
public static function get_objectid_mapping() {
return array('db' => 'role', 'restore' => 'role');
}
}

View File

@ -102,4 +102,13 @@ class role_deleted extends base {
throw new \coding_exception('The \'shortname\' value must be set in other.');
}
}
public static function get_objectid_mapping() {
return array('db' => 'role', 'restore' => 'role');
}
public static function get_other_mapping() {
// Nothing to map.
return false;
}
}

View File

@ -128,4 +128,16 @@ class role_unassigned extends base {
throw new \coding_exception('The \'component\' value must be set in other.');
}
}
public static function get_objectid_mapping() {
return array('db' => 'role', 'restore' => 'role');
}
public static function get_other_mapping() {
$othermapped = array();
$othermapped['id'] = array('db' => 'role_assignments', 'restore' => base::NOT_MAPPED);
$othermapped['itemid'] = base::NOT_MAPPED;
return $othermapped;
}
}

View File

@ -117,4 +117,17 @@ class tag_added extends base {
throw new \coding_exception('The \'tagrawname\' value must be set in other.');
}
}
public static function get_objectid_mapping() {
// Tags cannot be mapped.
return array('db' => 'tag_instance', 'restore' => base::NOT_MAPPED);
}
public static function get_other_mapping() {
$othermapped = array();
$othermapped['tagid'] = array('db' => 'tag', 'restore' => base::NOT_MAPPED);
$othermapped['itemid'] = base::NOT_MAPPED;
return $othermapped;
}
}

Some files were not shown because too many files have changed in this diff Show More