Updated the HEAD build version to 20100718
[moodle.git] / backup / util / plan / restore_structure_step.class.php
CommitLineData
69023455
EL
1<?php
2
3// This file is part of Moodle - http://moodle.org/
4//
5// Moodle is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// Moodle is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
17
18/**
19 * @package moodlecore
20 * @subpackage backup-plan
21 * @copyright 2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 */
24
25/**
26 * Abstract class defining the needed stuff to restore one xml file
27 *
28 * TODO: Finish phpdocs
29 */
30abstract class restore_structure_step extends restore_step {
31
32 protected $filename; // Name of the file to be parsed
33 protected $pathelements; // Array of pathelements to process
34
35 /**
36 * Constructor - instantiates one object of this class
37 */
38 public function __construct($name, $filename, $task = null) {
39 if (!is_null($task) && !($task instanceof restore_task)) {
40 throw new restore_step_exception('wrong_restore_task_specified');
41 }
42 $this->filename = $filename;
43 $this->pathelements = array();
44 parent::__construct($name, $task);
45 }
46
47 public function execute() {
48
482aac65
EL
49 if (!$this->execute_condition()) { // Check any condition to execute this
50 return;
51 }
52
69023455
EL
53 $fullpath = $this->task->get_taskbasepath();
54
55 // We MUST have one fullpath here, else, error
56 if (empty($fullpath)) {
57 throw new restore_step_exception('restore_structure_step_undefined_fullpath');
58 }
59
60 // Append the filename to the fullpath
61 $fullpath = rtrim($fullpath, '/') . '/' . $this->filename;
62
63 // And it MUST exist
64 if (!file_exists($fullpath)) { // Shouldn't happen ever, but...
65 throw new restore_step_exception('missing_moodle_backup_xml_file', $fullpath);
66 }
67
68 // Get restore_path elements array adapting and preparing it for processing
69 $this->pathelements = $this->prepare_pathelements($this->define_structure());
70
71 // Create parser and processor
72 $xmlparser = new progressive_parser();
73 $xmlparser->set_file($fullpath);
74 $xmlprocessor = new restore_structure_parser_processor($this->task->get_courseid(), $this);
75 $xmlparser->set_processor($xmlprocessor);
76
77 // Add pathelements to processor
78 foreach ($this->pathelements as $element) {
79 $xmlprocessor->add_path($element->get_path(), $element->is_grouped());
80 }
81
82 // And process it, dispatch to target methods in step will start automatically
83 $xmlparser->process();
84 }
85
86// Protected API starts here
87
88 /**
89 * Receive one chunk of information form the xml parser processor and
90 * dispatch it, following the naming rules
91 */
92 public function process($data) {
93 if (!array_key_exists($data['path'], $this->pathelements)) { // Incorrect path, must not happen
94 throw new restore_step_exception('restore_structure_step_missing_path', $data['path']);
95 }
96 $element = $this->pathelements[$data['path']];
97 $object = $element->get_processing_object();
98 $method = $element->get_processing_method();
99 if (empty($object)) { // No processing object defined
100 throw new restore_step_exception('restore_structure_step_missing_pobject', $object);
101 }
102 $rdata = $object->$method($data['tags']); // Dispatch to proper object/method
103 if ($rdata !== null) { // If the method has returned any info, set element data to it
104 $element->set_data($rdata);
105 } else { // Else, put the original parsed data
106 $element->set_data($data);
107 }
108 }
109
110 /**
111 * Prepare the pathelements for processing, looking for duplicates, applying
112 * processing objects and other adjustments
113 */
114 protected function prepare_pathelements($elementsarr) {
115
116 // First iteration, push them to new array, indexed by name
117 // detecting duplicates in names or paths
118 $names = array();
119 $paths = array();
120 foreach($elementsarr as $element) {
121 if (array_key_exists($element->get_name(), $names)) {
122 throw new restore_step_exception('restore_path_element_name_alreadyexists', $element->get_name());
123 }
124 if (array_key_exists($element->get_path(), $paths)) {
125 throw new restore_step_exception('restore_path_element_path_alreadyexists', $element->get_path());
126 }
127 $names[$element->get_name()] = true;
128 $elements[$element->get_path()] = $element;
129 }
130 // Now, for each element not having one processing object, if
131 // not child of grouped element, assign $this (the step itself) as processing element
132 // Note method must exist or we'll get one @restore_path_element_exception
133 foreach($elements as $key => $pelement) {
134 if ($pelement->get_processing_object() === null && !$this->grouped_parent_exists($pelement, $elements)) {
135 $elements[$key]->set_processing_object($this);
136 }
137 }
138 // Done, return them
139 return $elements;
140 }
141
142 /**
143 * Given one pathelement, return true if grouped parent was found
144 */
145 protected function grouped_parent_exists($pelement, $elements) {
146 foreach ($elements as $element) {
147 if ($pelement->get_path() == $element->get_path()) {
148 continue; // Don't compare against itself
149 }
150 // If element is grouped and parent of pelement, return true
151 if ($element->is_grouped() and strpos($pelement->get_path() . '/', $element->get_path()) === 0) {
152 return true;
153 }
154 }
155 return false; // no grouped parent found
156 }
157
482aac65
EL
158 /**
159 * To conditionally decide if one step will be executed or no
160 *
161 * For steps needing to be executed conditionally, based in dynamic
162 * conditions (at execution time vs at declaration time) you must
163 * override this function. It will return true if the step must be
164 * executed and false if not
165 */
166 protected function execute_condition() {
167 return true;
168 }
169
69023455
EL
170 /**
171 * Function that will return the structure to be processed by this restore_step.
172 * Must return one array of @restore_path_element elements
173 */
174 abstract protected function define_structure();
175}