See Release Notes
Long Term Support Release
Differences Between: [Versions 401 and 402] [Versions 401 and 403]
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-structure 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 * TODO: Finish phpdocs 25 */ 26 27 /** 28 * Instantiable class representing one nestable element (non final) piece of information on backup 29 */ 30 class backup_nested_element extends base_nested_element implements processable { 31 32 protected $var_array; // To be used in case we pass one in-memory structure 33 protected $table; // Table (without prefix) to fetch records from 34 protected $tablesortby; // The field to sort by when using the table methods 35 protected $sql; // Raw SQL to fetch records from 36 protected $params; // Unprocessed params as specified in the set_source() call 37 protected $procparams;// Processed (path resolved) params array 38 protected $aliases; // Define DB->final element aliases 39 protected $fileannotations; // array of file areas to be searched by file annotations 40 protected $counter; // Number of instances of this element that have been processed 41 protected $results; // Logs the results we encounter during the process. 42 protected $logs; // Some log messages that could be retrieved later. 43 44 /** 45 * Constructor - instantiates one backup_nested_element, specifying its basic info. 46 * 47 * @param string $name name of the element 48 * @param array $attributes attributes this element will handle (optional, defaults to null) 49 * @param array $final_elements this element will handle (optional, defaults to null) 50 */ 51 public function __construct($name, $attributes = null, $final_elements = null) { 52 parent::__construct($name, $attributes, $final_elements); 53 $this->var_array = null; 54 $this->table = null; 55 $this->tablesortby = null; 56 $this->sql = null; 57 $this->params = null; 58 $this->procparams= null; 59 $this->aliases = array(); 60 $this->fileannotations = array(); 61 $this->counter = 0; 62 $this->results = array(); 63 $this->logs = array(); 64 } 65 66 /** 67 * Process the nested element 68 * 69 * @param object $processor the processor 70 * @return void 71 */ 72 public function process($processor) { 73 if (!$processor instanceof base_processor) { // No correct processor, throw exception 74 throw new base_element_struct_exception('incorrect_processor'); 75 } 76 77 $iterator = $this->get_iterator($processor); // Get the iterator over backup-able data 78 79 foreach ($iterator as $key => $values) { // Process each "ocurrrence" of the nested element (recordset or array) 80 81 // Fill the values of the attributes and final elements with the $values from the iterator 82 $this->fill_values($values); 83 84 // Perform pre-process tasks for the nested_element 85 $processor->pre_process_nested_element($this); 86 87 // Delegate the process of each attribute 88 foreach ($this->get_attributes() as $attribute) { 89 $attribute->process($processor); 90 } 91 92 // Main process tasks for the nested element, once its attributes have been processed 93 $processor->process_nested_element($this); 94 95 // Delegate the process of each final_element 96 foreach ($this->get_final_elements() as $final_element) { 97 $final_element->process($processor); 98 } 99 100 // Delegate the process to the optigroup 101 if ($this->get_optigroup()) { 102 $this->get_optigroup()->process($processor); 103 } 104 105 // Delegate the process to each child nested_element 106 foreach ($this->get_children() as $child) { 107 $child->process($processor); 108 } 109 110 // Perform post-process tasks for the nested element 111 $processor->post_process_nested_element($this); 112 113 // Everything processed, clean values before next iteration 114 $this->clean_values(); 115 116 // Increment counter for this element 117 $this->counter++; 118 119 // For root element, check we only have 1 element 120 if ($this->get_parent() === null && $this->counter > 1) { 121 throw new base_element_struct_exception('root_only_one_ocurrence', $this->get_name()); 122 } 123 } 124 // Close the iterator (DB recordset / array iterator) 125 $iterator->close(); 126 } 127 128 /** 129 * Saves a log message to an array 130 * 131 * @see backup_helper::log() 132 * @param string $message to add to the logs 133 * @param int $level level of importance {@link backup::LOG_DEBUG} and other constants 134 * @param mixed $a to be included in $message 135 * @param int $depth of the message 136 * @param display $bool supporting translation via get_string() if true 137 * @return void 138 */ 139 protected function add_log($message, $level, $a = null, $depth = null, $display = false) { 140 // Adding the result to the oldest parent. 141 if ($this->get_parent()) { 142 $parent = $this->get_grandparent(); 143 $parent->add_log($message, $level, $a, $depth, $display); 144 } else { 145 $log = new stdClass(); 146 $log->message = $message; 147 $log->level = $level; 148 $log->a = $a; 149 $log->depth = $depth; 150 $log->display = $display; 151 $this->logs[] = $log; 152 } 153 } 154 155 /** 156 * Saves the results to an array 157 * 158 * @param array $result associative array 159 * @return void 160 */ 161 protected function add_result($result) { 162 if (is_array($result)) { 163 // Adding the result to the oldest parent. 164 if ($this->get_parent()) { 165 $parent = $this->get_grandparent(); 166 $parent->add_result($result); 167 } else { 168 $this->results = array_merge($this->results, $result); 169 } 170 } 171 } 172 173 /** 174 * Returns the logs 175 * 176 * @return array of log objects 177 */ 178 public function get_logs() { 179 return $this->logs; 180 } 181 182 /** 183 * Returns the results 184 * 185 * @return associative array of results 186 */ 187 public function get_results() { 188 return $this->results; 189 } 190 191 public function set_source_array($arr) { 192 // TODO: Only elements having final elements can set source 193 $this->var_array = $arr; 194 } 195 196 public function set_source_table($table, $params, $sortby = null) { 197 if (!is_array($params)) { // Check we are passing array 198 throw new base_element_struct_exception('setsourcerequiresarrayofparams'); 199 } 200 // TODO: Only elements having final elements can set source 201 $this->table = $table; 202 $this->procparams = $this->convert_table_params($params); 203 if ($sortby) { 204 $this->tablesortby = $sortby; 205 } 206 } 207 208 public function set_source_sql($sql, $params) { 209 if (!is_array($params)) { // Check we are passing array 210 throw new base_element_struct_exception('setsourcerequiresarrayofparams'); 211 } 212 // TODO: Only elements having final elements can set source 213 $this->sql = $sql; 214 $this->procparams = $this->convert_sql_params($params); 215 } 216 217 public function set_source_alias($dbname, $finalelementname) { 218 // Get final element 219 $finalelement = $this->get_final_element($finalelementname); 220 if (!$finalelement) { // Final element incorrect, throw exception 221 throw new base_element_struct_exception('incorrectaliasfinalnamenotfound', $finalelementname); 222 } else { 223 $this->aliases[$dbname] = $finalelement; 224 } 225 } 226 227 public function annotate_files($component, $filearea, $elementname, $filesctxid = null) { 228 if (!array_key_exists($component, $this->fileannotations)) { 229 $this->fileannotations[$component] = array(); 230 } 231 232 if ($elementname !== null) { // Check elementname is valid 233 $elementname = $this->find_element($elementname); //TODO: no warning here? (skodak) 234 } 235 236 if (array_key_exists($filearea, $this->fileannotations[$component])) { 237 throw new base_element_struct_exception('annotate_files_duplicate_annotation', "$component/$filearea/$elementname"); 238 } 239 240 $info = new stdclass(); 241 $info->element = $elementname; 242 $info->contextid = $filesctxid; 243 $this->fileannotations[$component][$filearea] = $info; 244 } 245 246 public function annotate_ids($itemname, $elementname) { 247 $element = $this->find_element($elementname); 248 $element->set_annotation_item($itemname); 249 } 250 251 /** 252 * Returns one array containing the element in the 253 * @backup_structure and the areas to be searched 254 */ 255 public function get_file_annotations() { 256 return $this->fileannotations; 257 } 258 259 public function get_source_array() { 260 return $this->var_array; 261 } 262 263 public function get_source_table() { 264 return $this->table; 265 } 266 267 public function get_source_table_sortby() { 268 return $this->tablesortby; 269 } 270 271 public function get_source_sql() { 272 return $this->sql; 273 } 274 275 public function get_counter() { 276 return $this->counter; 277 } 278 279 /** 280 * Simple filler that, matching by name, will fill both attributes and final elements 281 * depending of this nested element, debugging info about non-matching elements and/or 282 * elements present in both places. Accept both arrays and objects. 283 */ 284 public function fill_values($values) { 285 $values = (array)$values; 286 287 foreach ($values as $key => $value) { 288 $found = 0; 289 if ($attribute = $this->get_attribute($key)) { // Set value for attributes 290 $attribute->set_value($value); 291 $found++; 292 } 293 if ($final = $this->get_final_element($key)) { // Set value for final elements 294 $final->set_value($value); 295 $found++; 296 } 297 if (isset($this->aliases[$key])) { // Last chance, set value by processing final element aliases 298 $this->aliases[$key]->set_value($value); 299 $found++; 300 } 301 // Found more than once, notice 302 // TODO: Route this through backup loggers 303 if ($found > 1) { 304 debugging('Key found more than once ' . $key, DEBUG_DEVELOPER); 305 } 306 } 307 308 } 309 310 // Protected API starts here 311 312 protected function convert_table_params($params) { 313 return $this->convert_sql_params($params); 314 } 315 316 protected function convert_sql_params($params) { 317 $procparams = array(); // Reset processed params 318 foreach ($params as $key => $param) { 319 $procparams[$key] = $this->find_element($param); 320 } 321 return $procparams; 322 } 323 324 protected function find_element($param) { 325 if ($param == backup::VAR_PARENTID) { // Look for first parent having id attribute/final_element 326 $param = $this->find_first_parent_by_name('id'); 327 328 // If the param is array, with key 'sqlparam', return the value without modifications 329 } else if (is_array($param) && array_key_exists('sqlparam', $param)) { 330 return $param['sqlparam']; 331 332 } else if (((int)$param) >= 0) { // Search by path if param isn't a backup::XXX candidate 333 $param = $this->find_element_by_path($param); 334 } 335 return $param; // Return the param unmodified 336 } 337 338 /** 339 * Returns one instace of the @base_attribute class to work with 340 * when attributes are added simply by name 341 */ 342 protected function get_new_attribute($name) { 343 return new backup_attribute($name); 344 } 345 346 /** 347 * Returns one instace of the @final_element class to work with 348 * when final_elements are added simply by name 349 */ 350 protected function get_new_final_element($name) { 351 return new backup_final_element($name); 352 } 353 354 /** 355 * Returns one PHP iterator over each "ocurrence" of this nested 356 * element (array or DB recordset). Delegated to backup_structure_dbops class 357 */ 358 protected function get_iterator($processor) { 359 return backup_structure_dbops::get_iterator($this, $this->procparams, $processor); 360 } 361 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body