MDL-46455 restore: Implement restore of standard logstore

Using standard subplugin support, this commits implements
the restore of logstore subplugins in general and the
standard logstore is particular. Notes:

- TODO: Decide about these 2 pending issues:

1) Some logs are already created (events fired) by the restore process itself. Every time
   an API is used and it fires events... corresponding (and actual!)
   logs are created. We need to prevent restore to duplicate them (or,
   alternatively, stop firing events when restore is happening).

2) There are 2 pieces of information in the logs that, right now, can
   not be restored, because the process does not know enough to be able
   to remap that information to its new counterparts. We are talking
   about objectid and other columns. So we need to specify, in some way
   understandable by restore, to which existing mappings they correspond
   to.
This commit is contained in:
Eloy Lafuente (stronk7) 2015-03-30 01:19:01 +02:00 committed by Mark Nelson
parent 73c2a35420
commit ea6c56437a
5 changed files with 228 additions and 1 deletions

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/>.
/**
* 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 {
}

View File

@ -0,0 +1,115 @@
<?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 = (object)$data;
// Complete the information that does not come from backup.
if (! $data->contextid = $this->get_mappingid('context', $data->contextid)) {
// Something went really wrong, cannot find the context this log belongs to.
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.
if (! $data->userid = $this->get_mappingid('user', $data->userid)) {
// Something went really wrong, cannot find the user this log belongs to.
return;
}
if (!empty($data->relateduserid)) { // This is optional.
if (! $data->relateduserid = $this->get_mappingid('user', $data->relateduserid)) {
// Something went really wrong, cannot find the relateduserid this log is about.
return;
}
}
if (!empty($data->realuserid)) { // This is optional.
if (! $data->realuserid = $this->get_mappingid('user', $data->realuserid)) {
// Something went really wrong, cannot find the realuserid this log is logged in as.
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)) {
// TODO: Call to the resolver.
return;
}
if (!empty($data->other)) {
// TODO: Call to the resolver.
return;
}
// Arrived here, everything is now ready to be added to database, let's proceed.
$DB->insert_record('logstore_standard_log', $data);
}
}

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