| 1 | efrain | 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 basis for one execution (backup/restore) plan
 | 
        
           |  |  | 27 |  *
 | 
        
           |  |  | 28 |  * TODO: Finish phpdocs
 | 
        
           |  |  | 29 |  */
 | 
        
           |  |  | 30 | abstract class base_plan implements checksumable, executable {
 | 
        
           |  |  | 31 |   | 
        
           |  |  | 32 |     protected $name;      // One simple name for identification purposes
 | 
        
           |  |  | 33 |     protected $settings;  // One array of (accumulated from tasks) base_setting elements
 | 
        
           |  |  | 34 |     protected $tasks;     // One array of base_task elements
 | 
        
           |  |  | 35 |     protected $results;   // One array of results received from tasks
 | 
        
           |  |  | 36 |   | 
        
           |  |  | 37 |     protected $built;     // Flag to know if one plan has been built
 | 
        
           |  |  | 38 |   | 
        
           |  |  | 39 |     /**
 | 
        
           |  |  | 40 |      * Constructor - instantiates one object of this class
 | 
        
           |  |  | 41 |      */
 | 
        
           |  |  | 42 |     public function __construct($name) {
 | 
        
           |  |  | 43 |         $this->name = $name;
 | 
        
           |  |  | 44 |         $this->settings = array();
 | 
        
           |  |  | 45 |         $this->tasks    = array();
 | 
        
           |  |  | 46 |         $this->results  = array();
 | 
        
           |  |  | 47 |         $this->built = false;
 | 
        
           |  |  | 48 |     }
 | 
        
           |  |  | 49 |   | 
        
           |  |  | 50 |     public function get_name() {
 | 
        
           |  |  | 51 |         return $this->name;
 | 
        
           |  |  | 52 |     }
 | 
        
           |  |  | 53 |   | 
        
           |  |  | 54 |     public function add_task($task) {
 | 
        
           |  |  | 55 |         if (! $task instanceof base_task) {
 | 
        
           |  |  | 56 |             throw new base_plan_exception('wrong_base_task_specified');
 | 
        
           |  |  | 57 |         }
 | 
        
           |  |  | 58 |         $this->tasks[] = $task;
 | 
        
           |  |  | 59 |         // link the task with the plan
 | 
        
           |  |  | 60 |         $task->set_plan($this);
 | 
        
           |  |  | 61 |         // Append task settings to plan array, if not present, for comodity
 | 
        
           |  |  | 62 |         foreach ($task->get_settings() as $key => $setting) {
 | 
        
           |  |  | 63 |             // Check if there is already a setting for this name.
 | 
        
           |  |  | 64 |             $name = $setting->get_name();
 | 
        
           |  |  | 65 |             if (!isset($this->settings[$name])) {
 | 
        
           |  |  | 66 |                 // There is no setting, so add it.
 | 
        
           |  |  | 67 |                 $this->settings[$name] = $setting;
 | 
        
           |  |  | 68 |             } else if ($this->settings[$name] != $setting) {
 | 
        
           |  |  | 69 |                 // If the setting already exists AND it is not the same setting,
 | 
        
           |  |  | 70 |                 // then throw an error. (I.e. you're allowed to add the same
 | 
        
           |  |  | 71 |                 // setting twice, but cannot add two different ones with same
 | 
        
           |  |  | 72 |                 // name.)
 | 
        
           |  |  | 73 |                 throw new base_plan_exception('multiple_settings_by_name_found', $name);
 | 
        
           |  |  | 74 |             }
 | 
        
           |  |  | 75 |         }
 | 
        
           |  |  | 76 |     }
 | 
        
           |  |  | 77 |   | 
        
           |  |  | 78 |     public function get_tasks() {
 | 
        
           |  |  | 79 |         return $this->tasks;
 | 
        
           |  |  | 80 |     }
 | 
        
           |  |  | 81 |   | 
        
           |  |  | 82 |     /**
 | 
        
           |  |  | 83 |      * Add the passed info to the plan results
 | 
        
           |  |  | 84 |      *
 | 
        
           |  |  | 85 |      * At the moment we expect an associative array structure to be merged into
 | 
        
           |  |  | 86 |      * the current results. In the future, some sort of base_result class may
 | 
        
           |  |  | 87 |      * be introduced.
 | 
        
           |  |  | 88 |      *
 | 
        
           |  |  | 89 |      * @param array $result associative array describing a result of a task/step
 | 
        
           |  |  | 90 |      */
 | 
        
           |  |  | 91 |     public function add_result($result) {
 | 
        
           |  |  | 92 |         if (!is_array($result)) {
 | 
        
           |  |  | 93 |             throw new coding_exception('Associative array is expected as a parameter of add_result()');
 | 
        
           |  |  | 94 |         }
 | 
        
           |  |  | 95 |         $this->results = array_merge($this->results, $result);
 | 
        
           |  |  | 96 |     }
 | 
        
           |  |  | 97 |   | 
        
           |  |  | 98 |     /**
 | 
        
           |  |  | 99 |      * Return the results collected via {@link self::add_result()} method
 | 
        
           |  |  | 100 |      *
 | 
        
           |  |  | 101 |      * @return array
 | 
        
           |  |  | 102 |      */
 | 
        
           |  |  | 103 |     public function get_results() {
 | 
        
           |  |  | 104 |         return $this->results;
 | 
        
           |  |  | 105 |     }
 | 
        
           |  |  | 106 |   | 
        
           |  |  | 107 |     public function get_settings() {
 | 
        
           |  |  | 108 |         return $this->settings;
 | 
        
           |  |  | 109 |     }
 | 
        
           |  |  | 110 |   | 
        
           |  |  | 111 |     /**
 | 
        
           |  |  | 112 |      * return one setting by name, useful to request root/course settings
 | 
        
           |  |  | 113 |      * that are, by definition, unique by name.
 | 
        
           |  |  | 114 |      *
 | 
        
           |  |  | 115 |      * @param string $name name of the setting
 | 
        
           |  |  | 116 |      * @return base_setting
 | 
        
           |  |  | 117 |      * @throws base_plan_exception if setting name is not found.
 | 
        
           |  |  | 118 |      */
 | 
        
           |  |  | 119 |     public function get_setting($name) {
 | 
        
           |  |  | 120 |         $result = null;
 | 
        
           |  |  | 121 |         if (isset($this->settings[$name])) {
 | 
        
           |  |  | 122 |             $result = $this->settings[$name];
 | 
        
           |  |  | 123 |         } else {
 | 
        
           |  |  | 124 |             throw new base_plan_exception('setting_by_name_not_found', $name);
 | 
        
           |  |  | 125 |         }
 | 
        
           |  |  | 126 |         return $result;
 | 
        
           |  |  | 127 |     }
 | 
        
           |  |  | 128 |   | 
        
           |  |  | 129 |     /**
 | 
        
           |  |  | 130 |      * For debug only. Get a simple test display of all the settings.
 | 
        
           |  |  | 131 |      *
 | 
        
           |  |  | 132 |      * @return string
 | 
        
           |  |  | 133 |      */
 | 
        
           |  |  | 134 |     public function debug_display_all_settings_values(): string {
 | 
        
           |  |  | 135 |         $result = '';
 | 
        
           |  |  | 136 |         foreach ($this->settings as $name => $setting) {
 | 
        
           |  |  | 137 |             $result .= $name . ': ' . $setting->get_value() . "\n";
 | 
        
           |  |  | 138 |         }
 | 
        
           |  |  | 139 |         return $result;
 | 
        
           |  |  | 140 |     }
 | 
        
           |  |  | 141 |   | 
        
           |  |  | 142 |     /**
 | 
        
           |  |  | 143 |      * Wrapper over @get_setting() that returns if the requested setting exists or no
 | 
        
           |  |  | 144 |      */
 | 
        
           |  |  | 145 |     public function setting_exists($name) {
 | 
        
           |  |  | 146 |         try {
 | 
        
           |  |  | 147 |             $this->get_setting($name);
 | 
        
           |  |  | 148 |             return true;
 | 
        
           |  |  | 149 |         } catch (base_plan_exception $e) {
 | 
        
           |  |  | 150 |             // Nothing to do
 | 
        
           |  |  | 151 |         }
 | 
        
           |  |  | 152 |         return false;
 | 
        
           |  |  | 153 |     }
 | 
        
           |  |  | 154 |   | 
        
           |  |  | 155 |   | 
        
           |  |  | 156 |     /**
 | 
        
           |  |  | 157 |      * Function responsible for building the tasks of any plan
 | 
        
           |  |  | 158 |      * with their corresponding settings
 | 
        
           |  |  | 159 |      * (must set the $built property to true)
 | 
        
           |  |  | 160 |      */
 | 
        
           |  |  | 161 |     abstract public function build();
 | 
        
           |  |  | 162 |   | 
        
           |  |  | 163 |     public function is_checksum_correct($checksum) {
 | 
        
           |  |  | 164 |         return $this->calculate_checksum() === $checksum;
 | 
        
           |  |  | 165 |     }
 | 
        
           |  |  | 166 |   | 
        
           |  |  | 167 |     public function calculate_checksum() {
 | 
        
           |  |  | 168 |         // Let's do it using name and tasks (settings are part of tasks)
 | 
        
           |  |  | 169 |         return md5($this->name . '-' . backup_general_helper::array_checksum_recursive($this->tasks));
 | 
        
           |  |  | 170 |     }
 | 
        
           |  |  | 171 |   | 
        
           |  |  | 172 |     /**
 | 
        
           |  |  | 173 |      * Function responsible for executing the tasks of any plan
 | 
        
           |  |  | 174 |      */
 | 
        
           |  |  | 175 |     public function execute() {
 | 
        
           |  |  | 176 |         if (!$this->built) {
 | 
        
           |  |  | 177 |             throw new base_plan_exception('base_plan_not_built');
 | 
        
           |  |  | 178 |         }
 | 
        
           |  |  | 179 |   | 
        
           |  |  | 180 |         // Calculate the total weight of all tasks and start progress tracking.
 | 
        
           |  |  | 181 |         $progress = $this->get_progress();
 | 
        
           |  |  | 182 |         $totalweight = 0;
 | 
        
           |  |  | 183 |         foreach ($this->tasks as $task) {
 | 
        
           |  |  | 184 |             $totalweight += $task->get_weight();
 | 
        
           |  |  | 185 |         }
 | 
        
           |  |  | 186 |         $progress->start_progress($this->get_name(), $totalweight);
 | 
        
           |  |  | 187 |   | 
        
           |  |  | 188 |         // Build and execute all tasks.
 | 
        
           |  |  | 189 |         foreach ($this->tasks as $task) {
 | 
        
           |  |  | 190 |             $task->build();
 | 
        
           |  |  | 191 |             $task->execute();
 | 
        
           |  |  | 192 |         }
 | 
        
           |  |  | 193 |   | 
        
           |  |  | 194 |         // Finish progress tracking.
 | 
        
           |  |  | 195 |         $progress->end_progress();
 | 
        
           |  |  | 196 |     }
 | 
        
           |  |  | 197 |   | 
        
           |  |  | 198 |     /**
 | 
        
           |  |  | 199 |      * Gets the progress reporter, which can be used to report progress within
 | 
        
           |  |  | 200 |      * the backup or restore process.
 | 
        
           |  |  | 201 |      *
 | 
        
           |  |  | 202 |      * @return \core\progress\base Progress reporting object
 | 
        
           |  |  | 203 |      */
 | 
        
           |  |  | 204 |     abstract public function get_progress();
 | 
        
           |  |  | 205 |   | 
        
           |  |  | 206 |     /**
 | 
        
           |  |  | 207 |      * Destroy all circular references. It helps PHP 5.2 a lot!
 | 
        
           |  |  | 208 |      */
 | 
        
           |  |  | 209 |     public function destroy() {
 | 
        
           |  |  | 210 |         // Before reseting anything, call destroy recursively
 | 
        
           |  |  | 211 |         foreach ($this->tasks as $task) {
 | 
        
           |  |  | 212 |             $task->destroy();
 | 
        
           |  |  | 213 |         }
 | 
        
           |  |  | 214 |         foreach ($this->settings as $setting) {
 | 
        
           |  |  | 215 |             $setting->destroy();
 | 
        
           |  |  | 216 |         }
 | 
        
           |  |  | 217 |         // Everything has been destroyed recursively, now we can reset safely
 | 
        
           |  |  | 218 |         $this->tasks = array();
 | 
        
           |  |  | 219 |         $this->settings = array();
 | 
        
           |  |  | 220 |     }
 | 
        
           |  |  | 221 | }
 | 
        
           |  |  | 222 |   | 
        
           |  |  | 223 |   | 
        
           |  |  | 224 | /*
 | 
        
           |  |  | 225 |  * Exception class used by all the @base_plan stuff
 | 
        
           |  |  | 226 |  */
 | 
        
           |  |  | 227 | class base_plan_exception extends moodle_exception {
 | 
        
           |  |  | 228 |   | 
        
           |  |  | 229 |     public function __construct($errorcode, $a=NULL, $debuginfo=null) {
 | 
        
           |  |  | 230 |         parent::__construct($errorcode, '', '', $a, $debuginfo);
 | 
        
           |  |  | 231 |     }
 | 
        
           |  |  | 232 | }
 |