Skip to content
Snippets Groups Projects
Unverified Commit ca928ac8 authored by Tobias Reischmann's avatar Tobias Reischmann
Browse files

Add backup and restore classes for workflows

parent 14390e24
No related branches found
No related tags found
No related merge requests found
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace tool_lifecycle\local\backup;
use tool_lifecycle\entity\step_subplugin;
use tool_lifecycle\entity\trigger_subplugin;
use tool_lifecycle\entity\workflow;
use tool_lifecycle\manager\workflow_manager;
use tool_lifecycle\manager\step_manager;
use tool_lifecycle\manager\trigger_manager;
use tool_lifecycle\manager\settings_manager;
defined('MOODLE_INTERNAL') || die();
class backup_lifecycle_workflow {
/** @var $workflow workflow */
private $workflow;
/** @var $steps step_subplugin[] */
private $steps;
/** @var $trigger trigger_subplugin[] */
private $trigger;
/** @var $writer XMLWriter */
private $writer;
public function __construct($workflowid) {
$this->workflow = workflow_manager::get_workflow($workflowid);
$this->steps = step_manager::get_step_instances($workflowid);
$this->trigger = trigger_manager::get_triggers_for_workflow($workflowid);
}
/**
* Executes the backup process. It write the workflow with all steps and triggers to a xml file.
* Afterwards it sends the file to the client.
* @throws \moodle_exception
*/
public function execute() {
global $CFG;
make_temp_directory('lifecycle');
$tempfilename = $CFG->tempdir .'/lifecycle/'. md5(sesskey().microtime());
if (!$handle = fopen($tempfilename, 'w+b')) {
print_error('cannotcreatetempdir');
}
header('Content-type: text/xml');
$this->writer = new XMLWriter();
$this->writer->openMemory();
$this->writer->setIndent(true);
$this->writer->startDocument();
$this->writer->startElement("workflow");
$this->writeWorkflow();
$this->writeSteps();
$this->writeTriggers();
$this->writer->endElement();
$this->writer->endDocument();
fwrite($handle, $this->writer->flush());
fclose($handle);
@header("Content-type: text/xml; charset=UTF-8");
send_temp_file($tempfilename, 'myfile.xml', false);
die();
}
/**
* Write the workflow with all its attributes to the xmlwriter.
*/
private function writeWorkflow() {
foreach (get_object_vars($this->workflow) as $prop => $value) {
$this->writer->writeAttribute($prop, $value);
}
}
/**
* Write all trigger of the workflow with all their attributes to the xmlwriter.
*/
private function writeTriggers() {
foreach ($this->trigger as $trigger) {
$this->writer->startElement("trigger");
foreach (get_object_vars($trigger) as $prop => $value) {
$this->writer->writeAttribute($prop, $value);
}
$settings = settings_manager::get_settings($trigger->id, SETTINGS_TYPE_TRIGGER);
foreach ($settings as $name => $value) {
$this->writer->startElement("setting");
$this->writer->writeAttribute('name', $name);
$this->writer->writeAttribute('value', $value);
$this->writer->endElement();
}
$this->writer->endElement();
}
}
/**
* Write all steps of the workflow with all their attributes to the xmlwriter.
*/
private function writeSteps() {
foreach ($this->steps as $step) {
$this->writer->startElement("step");
foreach (get_object_vars($step) as $prop => $value) {
$this->writer->writeAttribute($prop, $value);
}
$settings = settings_manager::get_settings($step->id, SETTINGS_TYPE_STEP);
foreach ($settings as $name => $value) {
$this->writer->startElement("setting");
$this->writer->writeAttribute('name', $name);
$this->writer->writeAttribute('value', $value);
$this->writer->endElement();
}
$this->writer->endElement();
}
}
}
\ No newline at end of file
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace tool_lifecycle\local\backup;
use tool_lifecycle\entity\step_subplugin;
use tool_lifecycle\entity\trigger_subplugin;
use tool_lifecycle\entity\workflow;
use tool_lifecycle\manager\workflow_manager;
use tool_lifecycle\manager\step_manager;
use tool_lifecycle\manager\trigger_manager;
use tool_lifecycle\manager\settings_manager;
defined('MOODLE_INTERNAL') || die();
class restore_lifecycle_workflow {
/** @var $workflow workflow */
private $workflow;
/** @var $steps step_subplugin[] */
private $steps;
/** @var $trigger trigger_subplugin[] */
private $trigger;
/** @var $settings array */
private $settings;
/** @var $errors string[] errors that occurred during restore.*/
private $errors = [];
/** @var $writer XMLWriter */
private $reader;
public function __construct($xmldata) {
$this->reader = new XMLReader();
$this->reader->XML($xmldata);
}
/**
* Executes the restore process. It loads the workflow with all steps and triggers from the xml data.
* If all data is valid, it restores the workflow with all subplugins and settings.
* Otherwise an array with error strings is returned.
* @return string[] Errors, which occurred during the restore process.
* @throws coding_exception
* @throws moodle_exception
*/
public function execute() {
$this->reader->read();
$this->load_workflow();
// If the workflow could be loaded continue with the subplugins.
if ($this->workflow) {
$this->load_subplugins();
// Validate the subplugin data.
if ($this->all_subplugins_installed()) {
// If all loaded data is valid, the new workflow and the steps can be stored in the database.
$this->persist();
}
}
return $this->errors;
}
/**
* Load the data of the workflow, stored within the xml data.
*/
private function load_workflow() {
if (!$this->reader->name == 'workflow' || !$this->reader->hasAttributes) {
$this->errors[] = get_string('restore_workflow_not_found', 'tool_lifecycle');
}
$tempworkflow = new stdClass();
foreach (get_class_vars(workflow::class) as $prop => $value) {
$tempworkflow->$prop = $this->reader->getAttribute($prop);
}
unset($tempworkflow->id);
$this->workflow = workflow::from_record($tempworkflow);
$this->workflow->active = false;
$this->workflow->timeactive = null;
$this->workflow->timedeactive = null;
}
/**
* Load the data of the subplugins, stored within the xml data.
*/
private function load_subplugins() {
$currentsubplugin = null;
$currenttype = null;
while ($this->reader->read()) {
$tag = $this->reader->name;
if ($tag == '#text' || $this->reader->nodeType == XMLReader::END_ELEMENT) {
continue;
}
if ((!$tag == 'step' && !$tag == 'trigger' && !$tag == 'setting')
|| !$this->reader->hasAttributes) {
$this->errors[] = get_string('restore_subplugins_not_found', 'tool_lifecycle');
}
switch ($tag) {
case 'trigger':
$currentsubplugin = new stdClass();
$currenttype = SETTINGS_TYPE_TRIGGER;
foreach (get_class_vars(trigger_subplugin::class) as $prop => $value) {
$currentsubplugin->$prop = $this->reader->getAttribute($prop);
}
$this->trigger[] = trigger_subplugin::from_record($currentsubplugin);
break;
case 'step':
$currentsubplugin = new stdClass();
$currenttype = SETTINGS_TYPE_STEP;
foreach (get_class_vars(step_subplugin::class) as $prop => $value) {
$currentsubplugin->$prop = $this->reader->getAttribute($prop);
}
$this->steps[] = step_subplugin::from_record($currentsubplugin);
break;
case 'setting':
$setting = new stdClass();
$setting->name = $this->reader->getAttribute('name');
$setting->pluginid = $currentsubplugin->id;
$setting->type = $currenttype;
$setting->value = $this->reader->getAttribute('value');
$this->settings[] = $setting;
}
}
}
/**
* Checks if all subplugins loaded from the backup file are installed in the system.
* If subplugins are missing, an error string is appended to the $error array,
* which can be used for displaying to the user later.
* @return bool true, if all subplugins are installed; false otherwise.
* @throws coding_exception
*/
private function all_subplugins_installed() {
$installedsteps = core_component::get_plugin_list('lifecyclestep');
foreach ($this->steps as $step) {
if (!array_key_exists($step->subpluginname, $installedsteps)) {
$this->errors[] = get_string('restore_step_does_not_exist', 'tool_lifecycle', $step->subpluginname);
}
}
$installedtrigger = core_component::get_plugin_list('lifecycletrigger');
foreach ($this->trigger as $trigger) {
if (!array_key_exists($trigger->subpluginname, $installedtrigger)) {
$this->errors[] = get_string('restore_trigger_does_not_exist', 'tool_lifecycle', $trigger->subpluginname); return false;
}
}
if (count($this->errors) > 0) {
return false;
}
return true;
}
/**
* Stores all loaded data in the database.
* @throws moodle_exception
*/
private function persist() {
workflow_manager::insert_or_update($this->workflow);
foreach ($this->steps as $step) {
$step->workflowid = $this->workflow->id;
$stepid = $step->id;
$step->id = null;
step_manager::insert_or_update($step);
foreach ($this->settings as $setting) {
if ($setting->type == SETTINGS_TYPE_STEP &&
$setting->pluginid == $stepid) {
settings_manager::save_setting($step->id, SETTINGS_TYPE_STEP, $step->subpluginname,
$setting->name, $setting->value);
}
}
}
foreach ($this->trigger as $trigger) {
$trigger->workflowid = $this->workflow->id;
$triggerid = $trigger->id;
$trigger->id = null;
trigger_manager::insert_or_update($trigger);
foreach ($this->settings as $setting) {
if ($setting->type == SETTINGS_TYPE_TRIGGER &&
$setting->pluginid == $triggerid) {
settings_manager::save_setting($trigger->id, SETTINGS_TYPE_TRIGGER, $trigger->subpluginname,
$setting->name, $setting->value);
}
}
}
}
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment