Merge branch 'master' into backup-convert
[moodle.git] / backup / converter / convertlib.php
1 <?php
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/>.
18 /**
19  * Provides base converter classes
20  *
21  * @package    core
22  * @subpackage backup-convert
23  * @copyright  2011 Mark Nielsen <mark@moodlerooms.com>
24  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25  */
27 defined('MOODLE_INTERNAL') || die();
29 require_once($CFG->dirroot . '/backup/util/includes/convert_includes.php');
31 /**
32  * Base converter class
33  *
34  * All Moodle backup converters are supposed to extend this base class.
35  *
36  * @throws convert_exception
37  */
38 abstract class base_converter {
40     /** @var string unique identifier of this converter instance */
41     protected $id;
42     /** @var string the name of the directory containing the unpacked backup being converted */
43     protected $tempdir;
44     /** @var string the name of the directory where the backup is converted to */
45     protected $workdir;
47     /**
48      * Constructor
49      *
50      * @param string $tempdir the relative path to the directory containing the unpacked backup to convert
51      */
52     public function __construct($tempdir) {
54         $this->tempdir  = $tempdir;
55         $this->id       = convert_helper::generate_id($this->workdir);
56         $this->workdir  = $tempdir . '_' . $this->get_name() . '_' . $this->id;
57         $this->init();
58     }
60     /**
61      * Get instance identifier
62      *
63      * @return string the unique identifier of this converter instance
64      */
65     public function get_id() {
66         return $this->id;
67     }
69     /**
70      * Get converter name
71      *
72      * @return string the system name of the converter
73      */
74     public function get_name() {
75         return array_shift(explode('_', get_class($this)));
76     }
78     /**
79      * Converts the backup directory
80      */
81     public function convert() {
83         try {
84             $this->create_workdir();
85             $this->execute();
86             $this->replace_tempdir();
87         } catch (Exception $e) {
88         }
90         // clean-up stuff if needed
91         $this->destroy();
93         // eventually re-throw the execution exception
94         if (isset($e) and ($e instanceof Exception)) {
95             throw $e;
96         }
97     }
99     /// public static methods //////////////////////////////////////////////////
101     /**
102      * Makes sure that this converter is available at this site
103      *
104      * This is intended for eventual PHP extensions check, environment check etc.
105      * All checks that do not depend on actual backup data should be done here.
106      *
107      * @return boolean true if this converter should be considered as available
108      */
109     public static function is_available() {
110         return true;
111     }
113     /**
114      * Detects the format of the backup directory
115      *
116      * Moodle 2.x format is being detected by the core itself. The converters are
117      * therefore supposed to detect the source format. Eventually, if the target
118      * format os not {@link backup::FORMAT_MOODLE} then they should be able to
119      * detect both source and target formats.
120      *
121      * @param string $tempdir the name of the backup directory
122      * @return null|string null if not recognized, backup::FORMAT_xxx otherwise
123      */
124     public static function detect_format($tempdir) {
125         return null;
126     }
128     /**
129      * Returns the basic information about the converter
130      *
131      * The returned array must contain the following keys:
132      * 'from' - the supported source format, eg. backup::FORMAT_MOODLE1
133      * 'to'   - the supported target format, eg. backup::FORMAT_MOODLE
134      * 'cost' - the cost of the conversion, non-negative non-zero integer
135      */
136     public static function description() {
138         return array(
139             'from'  => null,
140             'to'    => null,
141             'cost'  => null,
142         );
143     }
145     /**
146      * @return string the full path to the working directory
147      */
148     public function get_workdir_path() {
149         global $CFG;
151         return "$CFG->dataroot/temp/backup/$this->workdir";
152     }
154     /**
155      * @return string the full path to the directory with the source backup
156      */
157     public function get_tempdir_path() {
158         global $CFG;
160         return "$CFG->dataroot/temp/backup/$this->tempdir";
161     }
163     /// end of public API //////////////////////////////////////////////////////
165     /**
166      * Initialize the instance if needed, called by the constructor
167      */
168     protected function init() {
169     }
171     /**
172      * Converts the contents of the tempdir into the target format in the workdir
173      */
174     protected abstract function execute();
176     /**
177      * Prepares a new empty working directory
178      */
179     protected function create_workdir() {
181         fulldelete($this->get_workdir_path());
182         if (!check_dir_exists($this->get_workdir_path())) {
183             throw new convert_exception('failed_create_workdir');
184         }
185     }
187     /**
188      * Replaces the source backup directory with the converted version
189      *
190      * If $CFG->keeptempdirectoriesonbackup is defined, the original source
191      * source backup directory is kept for debugging purposes.
192      */
193     protected function replace_tempdir() {
194         global $CFG;
196         if (empty($CFG->keeptempdirectoriesonbackup)) {
197             fulldelete($this->get_tempdir_path());
198         } else {
199             if (!rename($this->get_tempdir_path(), $this->get_tempdir_path()  . '_' . $this->get_name() . '_' . $this->id . '_source')) {
200                 throw new convert_exception('failed_rename_source_tempdir');
201             }
202         }
204         if (!rename($this->get_workdir_path(), $this->get_tempdir_path())) {
205             throw new convert_exception('failed_move_converted_into_place');
206         }
207     }
209     /**
210      * Cleans up stuff after the execution
211      *
212      * Note that we do not know if the execution was successful or not.
213      * An exception might have been thrown.
214      */
215     protected function destroy() {
216         global $CFG;
218         if (empty($CFG->keeptempdirectoriesonbackup)) {
219             fulldelete($this->get_workdir_path());
220         }
221     }
224 /**
225  * General convert-related exception
226  *
227  * @author David Mudrak <david@moodle.com>
228  */
229 class convert_exception extends moodle_exception {
231     /**
232      * Constructor
233      *
234      * @param string $errorcode key for the corresponding error string
235      * @param object $a extra words and phrases that might be required in the error string
236      * @param string $debuginfo optional debugging information
237      */
238     public function __construct($errorcode, $a = null, $debuginfo = null) {
239         parent::__construct($errorcode, '', '', $a, $debuginfo);
240     }