See Release Notes
Long Term Support Release
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 /** 18 * General database importer class 19 * 20 * @package core_dtl 21 * @copyright 2008 Andrei Bautu 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 */ 24 25 defined('MOODLE_INTERNAL') || die(); 26 27 /** 28 * Base class for database import operations. This class implements 29 * basic callbacks for import operations and defines the @see import_database 30 * method as a common method for all importers. In general, subclasses will 31 * override import_database and call other methods in appropriate moments. 32 * Between a single pair of calls to @see begin_database_import and 33 * @see finish_database_import, multiple non-overlapping pairs of calls may 34 * be made to @see begin_table_import and @see finish_database_import for 35 * different tables. 36 * Between one pair of calls to @see begin_table_import and 37 * @see finish_database_import multiple calls may be made to 38 * @see import_table_data for the same table. 39 * This class can be used directly, if the standard control flow (defined above) 40 * is respected. 41 */ 42 class database_importer { 43 /** @var moodle_database Connection to the target database (a @see moodle_database object). */ 44 protected $mdb; 45 /** @var database_manager Database manager of the target database (a @see database_manager object). */ 46 protected $manager; 47 /** @var xmldb_structure Target database schema in XMLDB format (a @see xmldb_structure object). */ 48 protected $schema; 49 /** 50 * Boolean flag - whether or not to check that XML database schema matches 51 * the RDBMS database schema before importing (used by 52 * @see begin_database_import). 53 * @var bool 54 */ 55 protected $check_schema; 56 /** @var string How to use transactions. */ 57 protected $transactionmode = 'allinone'; 58 /** @var moodle_transaction Transaction object */ 59 protected $transaction; 60 61 /** 62 * Object constructor. 63 * 64 * @param moodle_database $mdb Connection to the target database (a 65 * @see moodle_database object). Use null to use the current $DB connection. 66 * @param boolean $check_schema - whether or not to check that XML database 67 * schema matches the RDBMS database schema before importing (inside 68 * @see begin_database_import). 69 */ 70 public function __construct(moodle_database $mdb, $check_schema=true) { 71 $this->mdb = $mdb; 72 $this->manager = $mdb->get_manager(); 73 $this->schema = $this->manager->get_install_xml_schema(); 74 $this->check_schema = $check_schema; 75 } 76 77 /** 78 * How to use transactions during the import. 79 * @param string $mode 'pertable', 'allinone' or 'none'. 80 */ 81 public function set_transaction_mode($mode) { 82 if (!in_array($mode, array('pertable', 'allinone', 'none'))) { 83 throw new coding_exception('Unknown transaction mode', $mode); 84 } 85 $this->transactionmode = $mode; 86 } 87 88 /** 89 * Callback function. Should be called only once database per import 90 * operation, before any database changes are made. It will check the database 91 * schema if @see check_schema is true 92 * 93 * @throws dbtransfer_exception if any checking (e.g. database schema, Moodle 94 * version) fails 95 * 96 * @param float $version the version of the system which generated the data 97 * @param string $timestamp the timestamp of the data (in ISO 8601) format. 98 * @return void 99 */ 100 public function begin_database_import($version, $timestamp) { 101 global $CFG; 102 103 if (!$this->mdb->get_tables()) { 104 // No tables present yet, time to create all tables. 105 $this->manager->install_from_xmldb_structure($this->schema); 106 } 107 108 if (round($version, 2) !== round($CFG->version, 2)) { // version might be in decimal format too 109 $a = (object)array('schemaver'=>$version, 'currentver'=>$CFG->version); 110 throw new dbtransfer_exception('importversionmismatchexception', $a); 111 } 112 113 $options = [ 114 'changedcolumns' => false, // Column types may be fixed by transfer. 115 'missingindexes' => false, // No need to worry about indexes for transfering data. 116 'extraindexes' => false 117 ]; 118 if ($this->check_schema and $errors = $this->manager->check_database_schema($this->schema, $options)) { 119 $details = ''; 120 foreach ($errors as $table=>$items) { 121 $details .= '<div>'.get_string('table').' '.$table.':'; 122 $details .= '<ul>'; 123 foreach ($items as $item) { 124 $details .= '<li>'.$item.'</li>'; 125 } 126 $details .= '</ul></div>'; 127 } 128 throw new dbtransfer_exception('importschemaexception', $details); 129 } 130 if ($this->transactionmode == 'allinone') { 131 $this->transaction = $this->mdb->start_delegated_transaction(); 132 } 133 } 134 135 /** 136 * Callback function. Should be called only once per table import operation, 137 * before any table changes are made. It will delete all table data. 138 * 139 * @throws dbtransfer_exception an unknown table import is attempted 140 * @throws ddl_table_missing_exception if the table is missing 141 * 142 * @param string $tablename - the name of the table that will be imported 143 * @param string $schemaHash - the hash of the xmldb_table schema of the table 144 * @return void 145 */ 146 public function begin_table_import($tablename, $schemaHash) { 147 if ($this->transactionmode == 'pertable') { 148 $this->transaction = $this->mdb->start_delegated_transaction(); 149 } 150 if (!$table = $this->schema->getTable($tablename)) { 151 throw new dbtransfer_exception('unknowntableexception', $tablename); 152 } 153 if ($schemaHash != $table->getHash()) { 154 throw new dbtransfer_exception('differenttableexception', $tablename); 155 } 156 // this should not happen, unless someone drops tables after import started 157 if (!$this->manager->table_exists($table)) { 158 throw new ddl_table_missing_exception($tablename); 159 } 160 $this->mdb->delete_records($tablename); 161 } 162 163 /** 164 * Callback function. Should be called only once per table import operation, 165 * after all table changes are made. It will reset table sequences if any. 166 * @param string $tablename 167 * @return void 168 */ 169 public function finish_table_import($tablename) { 170 $table = $this->schema->getTable($tablename); 171 $fields = $table->getFields(); 172 foreach ($fields as $field) { 173 if ($field->getSequence()) { 174 $this->manager->reset_sequence($tablename); 175 return; 176 } 177 } 178 if ($this->transactionmode == 'pertable') { 179 $this->transaction->allow_commit(); 180 } 181 } 182 183 /** 184 * Callback function. Should be called only once database per import 185 * operation, after all database changes are made. It will commit changes. 186 * @return void 187 */ 188 public function finish_database_import() { 189 if ($this->transactionmode == 'allinone') { 190 $this->transaction->allow_commit(); 191 } 192 } 193 194 /** 195 * Callback function. Should be called only once per record import operation, only 196 * between @see begin_table_import and @see finish_table_import calls. 197 * It will insert table data. 198 * 199 * @throws dml_exception if data insert operation failed 200 * 201 * @param string $tablename - the name of the table in which data will be 202 * imported 203 * @param object $data - data object (fields and values will be inserted 204 * into table) 205 * @return void 206 */ 207 public function import_table_data($tablename, $data) { 208 $this->mdb->import_record($tablename, $data); 209 } 210 211 /** 212 * Common import method 213 * @return void 214 */ 215 public function import_database() { 216 // implement in subclasses 217 } 218 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body