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