]> git.mjollnir.org Git - moodle.git/commitdiff
MDL-15635 dtl refactoring and basic export and transfer ui (the import UI will be...
authorskodak <skodak>
Tue, 2 Sep 2008 21:20:45 +0000 (21:20 +0000)
committerskodak <skodak>
Tue, 2 Sep 2008 21:20:45 +0000 (21:20 +0000)
17 files changed:
admin/dbtransfer/database_export_form.php [new file with mode: 0644]
admin/dbtransfer/database_transfer_form.php [new file with mode: 0644]
admin/dbtransfer/dbexport.php [new file with mode: 0644]
admin/dbtransfer/index.php [new file with mode: 0644]
admin/dbtransfer/lib.php [new file with mode: 0644]
admin/settings/misc.php
lang/en_utf8/admin.php
lang/en_utf8/dbtransfer.php [new file with mode: 0644]
lib/dtl/database_exporter.php
lib/dtl/database_importer.php
lib/dtl/database_mover.php
lib/dtl/file_xml_database_exporter.php
lib/dtl/file_xml_database_importer.php
lib/dtl/string_xml_database_exporter.php
lib/dtl/string_xml_database_importer.php
lib/dtl/xml_database_importer.php
lib/dtllib.php

diff --git a/admin/dbtransfer/database_export_form.php b/admin/dbtransfer/database_export_form.php
new file mode 100644 (file)
index 0000000..9ea1e37
--- /dev/null
@@ -0,0 +1,15 @@
+<?php //$Id$
+
+require_once $CFG->libdir.'/formslib.php';
+
+class database_export_form extends moodleform {
+
+    function definition() {
+        $mform = $this->_form;
+
+        $mform->addElement('header', 'database', get_string('dbexport', 'dbtransfer'));
+        $mform->addElement('textarea', 'description', get_string('description'), array('rows'=>5, 'cols'=>60));
+
+        $this->add_action_buttons(false, get_string('exportdata', 'dbtransfer'));
+    }
+}
diff --git a/admin/dbtransfer/database_transfer_form.php b/admin/dbtransfer/database_transfer_form.php
new file mode 100644 (file)
index 0000000..4dcd1d3
--- /dev/null
@@ -0,0 +1,47 @@
+<?php //$Id$
+
+require_once $CFG->libdir.'/formslib.php';
+
+class database_transfer_form extends moodleform {
+
+    function definition() {
+        $mform = $this->_form;
+
+        $mform->addElement('header', 'database', get_string('dbtransfer', 'dbtransfer'));
+
+        $supported = array (
+            'mysqli/adodb',
+            'mysql/adodb',
+            'postgres7/adodb',
+            'mssql_n/adodb',
+            'mssql/adodb',
+            'odbc_mssql/adodb',
+            'oci8po/adodb',
+            'sqlite3/pdo',
+        );
+        $drivers = array();
+        foreach($supported as $driver) {
+            list($dbtype, $dblibrary) = explode('/', $driver);
+            $targetdb = moodle_database::get_driver_instance($dbtype, $dblibrary);
+            if ($targetdb->driver_installed() !== true) {
+                continue;
+            }
+            $drivers[$driver] = $driver;
+        }
+
+        $mform->addElement('select', 'driver', get_string('dbtype', 'install'), $drivers);
+        $mform->addElement('text', 'dbhost', get_string('dbhost', 'install'));
+        $mform->addElement('text', 'dbname', get_string('database', 'install'));
+        $mform->addElement('text', 'dbuser', get_string('user'));
+        $mform->addElement('text', 'dbpass', get_string('password'));
+        $mform->addElement('text', 'prefix', get_string('dbprefix', 'install'));
+
+        $mform->addRule('dbhost', get_string('required'), 'required', null);
+        $mform->addRule('dbname', get_string('required'), 'required', null);
+        $mform->addRule('dbuser', get_string('required'), 'required', null);
+        $mform->addRule('dbpass', get_string('required'), 'required', null);
+        $mform->addRule('prefix', get_string('required'), 'required', null);
+
+        $this->add_action_buttons(false, get_string('transferdata', 'dbtransfer'));
+    }
+}
diff --git a/admin/dbtransfer/dbexport.php b/admin/dbtransfer/dbexport.php
new file mode 100644 (file)
index 0000000..02d28f0
--- /dev/null
@@ -0,0 +1,21 @@
+<?php  //$Id$
+
+require('../../config.php');
+require_once('lib.php');
+require_once('database_export_form.php');
+
+require_login();
+admin_externalpage_setup('dbexport');
+
+//create form
+$form = new database_export_form();
+
+if ($data = $form->get_data()) {
+    dbtransfer_export_xml_database($data->description, $DB);
+    die;
+}
+
+admin_externalpage_print_header();
+// TODO: add some more info here
+$form->display();
+admin_externalpage_print_footer();
diff --git a/admin/dbtransfer/index.php b/admin/dbtransfer/index.php
new file mode 100644 (file)
index 0000000..cb25530
--- /dev/null
@@ -0,0 +1,34 @@
+<?php  //$Id$
+
+require('../../config.php');
+require_once('lib.php');
+require_once('database_transfer_form.php');
+
+require_login();
+admin_externalpage_setup('dbtransfer');
+
+//create form
+$form = new database_transfer_form();
+
+if ($data = $form->get_data()) {
+    list($dbtype, $dblibrary) = explode('/', $data->driver);
+    $targetdb = moodle_database::get_driver_instance($dbtype, $dblibrary);
+    if (!$targetdb->connect($data->dbhost, $data->dbuser, $data->dbpass, $data->dbname, false, $data->prefix, null)) {
+        throw new dbtransfer_exception('notargetconectexception', null, "$CFG->wwwroot/$CFG->admin/dbtransfer/");
+    }
+    if ($targetdb->get_tables()) {
+        // TODO add exception or string...
+        error('Sorry, tables already exist in selected database. Can not continue.'); 
+    }
+    admin_externalpage_print_header();
+    dbtransfer_transfer_database($DB, $targetdb);
+    notify(get_string('success'), 'notifysuccess');
+    print_continue("$CFG->wwwroot/$CFG->admin/");
+    admin_externalpage_print_footer();
+    die;
+}
+
+admin_externalpage_print_header();
+// TODO: add some more info here
+$form->display();
+admin_externalpage_print_footer();
diff --git a/admin/dbtransfer/lib.php b/admin/dbtransfer/lib.php
new file mode 100644 (file)
index 0000000..4241c30
--- /dev/null
@@ -0,0 +1,52 @@
+<?php  //$Id$
+
+/*
+
+TODO:
+  - exporting to server file >2GB fails in 32bit operating systems - needs warning
+  - we may run out of disk space exporting to srever file - we must verify the file is not truncated; read from the end of file?
+  - when sending file >4GB - FAT32 limit, Apache limit, browser limit - needs warning
+  - there must be some form of progress bar during export, transfer - new tracking class could be passed around
+  - command line operation - could work around some 2G/4G limits in PHP; useful for cron full backups
+  - by default allow exporting into empty database only (no tables with the same prefix yet)
+  - all dangerous operation (like deleting of all data) should be confirmed by key found in special file in dataroot
+    (user would need file access to dataroot which might prevent various "accidents")
+  - implement "Export/import running" notification in lib/setup.php (similar to new upgrade flag in config table)
+  - gzip compression when storing xml file - the xml is very verbose and full of repeated tags (zip is not suitable here at all)
+    this could help us keep the files bellow 2G (expected ratio is > 10:1)
+
+*/
+
+require_once($CFG->libdir.'/adminlib.php');
+require_once($CFG->libdir.'/dtllib.php');
+
+
+function dbtransfer_export_xml_database($description, $mdb) {
+    @set_time_limit(0);
+
+    session_write_close(); // release session
+
+    header('Content-Type: application/xhtml+xml');
+    header('Content-Disposition: attachment; filename=database.xml');
+    header('Expires: 0');
+    header('Cache-Control: must-revalidate,post-check=0,pre-check=0');
+    header('Pragma: public');
+
+    while(@ob_flush());
+
+    $var = new file_xml_database_exporter('php://output', $mdb);
+    $var->export_database($description);
+
+    // no more output
+    die;
+}
+
+
+function dbtransfer_transfer_database($sourcedb, $targetdb) {
+    @set_time_limit(0);
+
+    session_write_close(); // release session
+
+    $var = new database_mover($sourcedb, $targetdb);
+    $var->export_database(null);
+}
index b4cb7160976d44d2e1e5d74547234324317c1cec..21ef81e0d4d3f3ecf74e859e20f8434534ec852f 100644 (file)
@@ -5,10 +5,12 @@
 if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
 
     // Experimental settings page
-    $temp = new admin_settingpage('experimental', get_string('experimental', 'admin'));
+    $ADMIN->add('misc', new admin_category('experimental', get_string('experimental','admin')));
+
+    $temp = new admin_settingpage('experimentalsettings', get_string('experimentalsettings', 'admin'));
     $temp->add(new admin_setting_configcheckbox('enableglobalsearch', get_string('enableglobalsearch', 'admin'), get_string('configenableglobalsearch', 'admin'), 0));
     $temp->add(new admin_setting_configcheckbox('smartpix', get_string('smartpix', 'admin'), get_string('configsmartpix', 'admin'), 0));
-    $item = new admin_setting_configcheckbox('enablehtmlpurifier', get_string('enablehtmlpurifier', 'admin'), get_string('configenablehtmlpurifier', 'admin'), 0); 
+    $item = new admin_setting_configcheckbox('enablehtmlpurifier', get_string('enablehtmlpurifier', 'admin'), get_string('configenablehtmlpurifier', 'admin'), 0);
     $item->set_updatedcallback('reset_text_filters_cache');
     $temp->add($item);
 
@@ -17,7 +19,11 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
     $temp->add(new admin_setting_configcheckbox('enablecompletion', get_string('enablecompletion','completion'), get_string('configenablecompletion','completion'), COMPLETION_DISABLED));
     $temp->add(new admin_setting_pickroles('progresstrackedroles', get_string('progresstrackedroles','completion'), get_string('configprogresstrackedroles', 'completion'), array('moodle/legacy:student')));
 
-    $ADMIN->add('misc', $temp);
+    $ADMIN->add('experimental', $temp);
+
+    // DB transfer related pages
+    $ADMIN->add('experimental', new admin_externalpage('dbtransfer', get_string('dbtransfer', 'dbtransfer'), $CFG->wwwroot.'/'.$CFG->admin.'/dbtransfer/index.php', 'moodle/site:config', false));
+    $ADMIN->add('experimental', new admin_externalpage('dbexport', get_string('dbexport', 'dbtransfer'), $CFG->wwwroot.'/'.$CFG->admin.'/dbtransfer/dbexport.php', 'moodle/site:config', false));
 
     // XMLDB editor
     $ADMIN->add('misc', new admin_externalpage('xmldbeditor', get_string('xmldbeditor'), "$CFG->wwwroot/$CFG->admin/xmldb/"));
index a17d998c95ba4edcbe9df9c6b2fac0dfa27cf15e..88f29d7f064e17d76138dcba82fd8996ab5fa9c1 100644 (file)
@@ -361,6 +361,7 @@ $string['errors'] = 'Errors';
 $string['errorsetting'] = 'Could not save setting:';
 $string['errorwithsettings'] = 'Some settings were not changed due to an error.';
 $string['experimental'] = 'Experimental';
+$string['experimentalsettings'] = 'Experimental settings';
 $string['extendedusernamechars'] = 'Allow extended characters in usernames';
 $string['filecreated'] = 'New file created';
 $string['filestoredin'] = 'Save file into folder :';
diff --git a/lang/en_utf8/dbtransfer.php b/lang/en_utf8/dbtransfer.php
new file mode 100644 (file)
index 0000000..3adbaba
--- /dev/null
@@ -0,0 +1,13 @@
+<?php // $Id$
+
+$string['dbexport'] = 'Database export';
+$string['dbtransfer'] = 'Database transfer';
+$string['differenttableexception'] = 'Table $a structure does not match.';
+$string['exportdata'] = 'Export data';
+$string['exportschemaexception'] = 'Current database structure does not match all install.xml files. <br /> $a';
+$string['importschemaexception'] = 'Current database structure does not match all install.xml files. <br /> $a';
+$string['importversionmismatchexception'] = 'Current version $->currentver does match exported version $a->schemaver.';
+$string['malformedxmlexception'] = 'Malformed XML found, can not continue.';
+$string['notargetconectexception'] = 'Can not connect target database, sorry.';
+$string['transferdata'] = 'Transfer data';
+$string['unknowntableexception'] = 'Unknown table $a found in export file.';
index 2c6b573c28c6bbf2a82a118ec9d359bb9c6b463c..34789ab5a0b2b420841bc8e0943b5cadd90f26ae 100644 (file)
@@ -104,25 +104,31 @@ abstract class database_exporter {
      * @see $check_schema is true), queries the database and calls
      * appropiate callbacks.
      *
-     * @exception export_exception if any checking (e.g. database schema) fails
+     * @exception dbtransfer_exception if any checking (e.g. database schema) fails
      *
      * @param string $description a user description of the data.
      */
     public function export_database($description=null) {
         global $CFG;
 
-        if ($this->check_schema and $this->manager->check_database_schema($this->schema)) {
-            //TODO put message in error lang
-            throw new export_exception('XMLDB schema does not match database schema.');
+        if ($this->check_schema and $errors = $this->manager->check_database_schema($this->schema)) {
+            $details = '';
+            foreach ($errors as $table=>$items) {
+                $details .= '<div>'.get_string('table').' '.$table.':';
+                $details .= '<ul>';
+                foreach ($items as $item) {
+                    $details .= '<li>'.$item.'</li>';
+                }
+                $details .= '</ul></div>';
+            }
+            throw new dbtransfer_exception('exportschemaexception', $details);
         }
         $tables = $this->schema->getTables();
         $this->begin_database_export($CFG->version, $CFG->release, date('c'), $description);
         foreach ($tables as $table) {
             $rs = $this->mdb->get_recordset_sql('SELECT * FROM {'.$table->getName().'}');
-            //TODO remove this when dml will have exceptions
             if (!$rs) {
-                //TODO put message in error lang
-                throw new export_exception('An error occured while reading the database.');
+                throw new ddl_table_missing_exception($table->getName());
             }
             $this->begin_table_export($table);
             foreach ($rs as $row) {
index 24cf79d7d90904509a7767b835d4c1b788cb8996..e88f66c12c96ab56da7b95da0385886275286ee1 100644 (file)
@@ -57,7 +57,7 @@ class database_importer {
      * operation, before any database changes are made. It will check the database
      * schema if @see check_schema is true
      *
-     * @exception import_exception if any checking (e.g. database schema, Moodle
+     * @exception dbtransfer_exception if any checking (e.g. database schema, Moodle
      * version) fails
      *
      * @param float $version the version of the system which generated the data
@@ -73,13 +73,21 @@ class database_importer {
         }
 
         if (round($version, 2) !== round($CFG->version, 2)) { // version might be in decimal format too
-            //TODO put message in error lang
-            throw new import_exception('Current Moodle version does not match exported Moodle version.');
+            $a = (object)array('schemaver'=>$version, 'currentver'=>$CFG->version);
+            throw new dbtransfer_exception('importversionmismatchexception', $a);
         }
 
-        if ($this->check_schema && $this->manager->check_database_schema($this->schema)) {
-            //TODO put message in error lang
-            throw new import_exception('XMLDB schema does not match database schema.');
+        if ($this->check_schema and $errors = $this->manager->check_database_schema($this->schema)) {
+            $details = '';
+            foreach ($errors as $table=>$items) {
+                $details .= '<div>'.get_string('table').' '.$table.':';
+                $details .= '<ul>';
+                foreach ($items as $item) {
+                    $details .= '<li>'.$item.'</li>';
+                }
+                $details .= '</ul></div>';
+            }
+            throw new dbtransfer_exception('importschemaexception', $details);
         }
         $this->mdb->begin_sql();
     }
@@ -88,7 +96,7 @@ class database_importer {
      * Callback function. Should be called only once per table import operation,
      * before any table changes are made. It will delete all table data.
      *
-     * @exception import_exception an unknown table import is attempted
+     * @exception dbtransfer_exception an unknown table import is attempted
      * @exception ddl_table_missing_exception if the table is missing
      *
      * @param string $tablename - the name of the table that will be imported
@@ -97,16 +105,13 @@ class database_importer {
      */
     public function begin_table_import($tablename, $schemaHash) {
         if (!$table = $this->schema->getTable($tablename)) {
-            //TODO put message in error lang
-            throw new import_exception('Unknown table in import data');
+            throw new dbtransfer_exception('unknowntableexception', $tablename);
         }
         if ($schemaHash != $table->getHash()) {
-            throw new import_exception('XMLDB schema does not match database schema.');
+            throw new dbtransfer_exception('differenttableexception', $tablename);
         }
         // this should not happen, unless someone drops tables after import started
         if (!$this->manager->table_exists($table)) {
-            // in the future, missing tables will be recreated with
-            //$this->manager->create_table($table);
             throw new ddl_table_missing_exception($tablename);
         }
         $this->mdb->delete_records($tablename);
index cdadf243efe77fba5389d2490d05eff32848997f..415b753d8d1a48cc0ae62e14e1c5cb492259053c 100644 (file)
@@ -7,15 +7,15 @@ class database_mover extends database_exporter {
     /**
      * Object constructor.
      *
-     * @param moodle_database $mdb_target Connection to the target database (a
-     * @see moodle_database object).
      * @param moodle_database $mdb Connection to the source database (a
      * @see moodle_database object).
+     * @param moodle_database $mdb_target Connection to the target database (a
+     * @see moodle_database object).
      * @param boolean $check_schema - whether or not to check that XML database
      * schema matches the RDBMS database schema before exporting (used by
      * @see export_database).
      */
-    public function __construct(moodle_database $mdb_target, moodle_database $mdb_source, $check_schema=true) {
+    public function __construct(moodle_database $mdb_source, moodle_database $mdb_target, $check_schema=true) {
         parent::__construct($mdb_source, $check_schema);
         $this->importer = new database_importer($mdb_target, $check_schema);
     }
index 6fec2e4610d9e733fe8d29719b8b506cc81649d2..e0f5c3e268a63b6349e744ddec351fe49e83bb88 100644 (file)
@@ -12,7 +12,7 @@ class file_xml_database_exporter extends xml_database_exporter {
     /**
      * Object constructor.
      *
-     * @param string $filepath - path to the XML data file. Use null for PHP
+     * @param string $filepath - path to the XML data file. Use 'php://output' for PHP
      * output stream.
      * @param moodle_database $mdb Connection to the source database
      * @see xml_database_exporter::__construct()
@@ -20,9 +20,6 @@ class file_xml_database_exporter extends xml_database_exporter {
      * @see xml_database_exporter::__construct()
      */
     public function __construct($filepath, moodle_database $mdb, $check_schema=true) {
-        if (is_null($filepath)) {
-            $filepath = 'php://output';
-        }
         parent::__construct($mdb, $check_schema);
         $this->filepath = $filepath;
     }
@@ -38,7 +35,7 @@ class file_xml_database_exporter extends xml_database_exporter {
      * Specific implementation for file exporting the database: it opens output stream, calls
      * superclass @see database_exporter::export_database() and closes output stream.
      *
-     * @exception export_exception if any checking (e.g. database schema) fails
+     * @exception dbtransfer_exception if any checking (e.g. database schema) fails
      *
      * @param string $description a user description of the data.
      */
index 8d6dfc63091e8dbed935915ec1df3139de730c70..5a0ef0f22c9d6a56f4df0f033fab999d6eac667b 100644 (file)
@@ -10,7 +10,7 @@ class file_xml_database_importer extends xml_database_importer {
     /**
      * Object constructor.
      *
-     * @param string $filepath - path to the XML data file. Use null for PHP
+     * @param string $filepath - path to the XML data file. Use 'php://input' for PHP
      * input stream.
      * @param moodle_database $mdb Connection to the target database
      * @see xml_database_importer::__construct()
@@ -18,9 +18,6 @@ class file_xml_database_importer extends xml_database_importer {
      * @see xml_database_importer::__construct()
      */
     public function __construct($filepath, moodle_database $mdb, $check_schema=true) {
-        if (is_null($filepath)) {
-            $filepath = 'php://input';
-        }
         $this->filepath = $filepath;
         parent::__construct($mdb, $check_schema);
     }
@@ -35,8 +32,7 @@ class file_xml_database_importer extends xml_database_importer {
         $parser = $this->get_parser();
         while ($data = fread($file, 65536)) {
             if (!xml_parse($parser, $data, feof($file))) {
-                //TODO localize
-                throw new import_exception("XML data not well-formed.");
+                throw new dbtransfer_exception('malformedxmlexception');
             }
         }
         xml_parser_free($parser);
index 84649929191ef834b2393308642d3a5129e501db..3bc9e8e641efeb7f7555abd73389df32c92bdf52 100644 (file)
@@ -26,7 +26,7 @@ class string_xml_database_exporter extends xml_database_exporter {
      * Specific implementation for memory exporting the database: it clear the buffer
      * and calls superclass @see database_exporter::export_database().
      *
-     * @exception export_exception if any checking (e.g. database schema) fails
+     * @exception dbtransfer_exception if any checking (e.g. database schema) fails
      * @param string $description a user description of the data.
      * @return void
      */
index 983d566df5d683349efe6aa8cba5a42332041513..42e8a1391b585a09f10d37c06826bd3885b0b588 100644 (file)
@@ -29,8 +29,7 @@ class string_xml_database_importer extends xml_database_importer {
     public function import_database() {
         $parser = $this->get_parser();
         if (!xml_parse($parser, $this->data, true)) {
-            //TODO localize
-            throw new import_exception("XML data not well-formed.");
+            throw new dbtransfer_exception('malformedxmlexception');
         }
         xml_parser_free($parser);
     }
index 4badbc2edb7e267fb396f2e986d59e34a2b9fac3..4f4e9c6f567000e24c0013117143a3f5282e427f 100644 (file)
@@ -39,29 +39,29 @@ abstract class xml_database_importer extends database_importer {
         switch ($tag) {
             case 'moodle_database' :
                 if (empty($attributes['version']) || empty($attributes['timestamp'])) {
-                    throw new import_exception('Missing tag attribute in data file.');
+                    throw new dbtransfer_exception('malformedxmlexception');
                 }
                 $this->begin_database_import($attributes['version'], $attributes['timestamp']);
                 break;
             case 'table' :
                 if (isset($this->current_table)) {
-                    throw new import_exception('Unexpected tag in data file.');
+                    throw new dbtransfer_exception('malformedxmlexception');
                 }
                 if (empty($attributes['name']) || empty($attributes['schemaHash'])) {
-                    throw new import_exception('Missing tag attribute in data file.');
+                    throw new dbtransfer_exception('malformedxmlexception');
                 }
                 $this->current_table = $attributes['name'];
                 $this->begin_table_import($this->current_table, $attributes['schemaHash']);
                 break;
             case 'record' :
                 if (isset($this->current_row) || !isset($this->current_table)) {
-                    throw new import_exception('Unexpected tag in data file.');
+                    throw new dbtransfer_exception('malformedxmlexception');
                 }
                 $this->current_row = new object();
                 break;
             case 'field' :
                 if (isset($this->current_field) || !isset($this->current_row)) {
-                    throw new import_exception('Unexpected tag in data file.');
+                    throw new dbtransfer_exception('malformedxmlexception');
                 }
                 $this->current_field = $attributes['name'];
                 $this->current_data = '';
@@ -72,8 +72,7 @@ abstract class xml_database_importer extends database_importer {
                 }
                 break;
             default :
-                //TODO localize
-                throw new import_exception('XML content not valid for import operation.');
+                throw new dbtransfer_exception('malformedxmlexception');
         }
     }
 
@@ -113,8 +112,7 @@ abstract class xml_database_importer extends database_importer {
                 break;
 
             default :
-                //TODO put message in error lang
-                throw new import_exception('XML content not valid for import operation.');
+                throw new dbtransfer_exception('malformedxmlexception');
         }
     }
 
index d5e8874fc100925269e5bf13ebd58db59bb1dcd1..34ce69436a751678b8886ef87b7b8d7c272e5f91 100644 (file)
@@ -41,23 +41,16 @@ require_once($CFG->libdir.'/dtl/file_xml_database_importer.php');
 require_once($CFG->libdir.'/dtl/string_xml_database_importer.php');
 
 /**
- * Exception class for export operations.
+ * Exception class for db transfer
  * @see moodle_exception
- * TODO subclass for specific purposes
  */
-class export_exception extends moodle_exception {
-    function __construct($errorcode, $a=null, $debuginfo=null) {
-        parent::__construct($errorcode, '', '', $a, $debuginfo);
+class dbtransfer_exception extends moodle_exception {
+    function __construct($errorcode, $a=null, $link='', $debuginfo=null) {
+        global $CFG;
+        if (empty($link)) {
+            $link = "$CFG->wwwroot/$CFG->admin/";
+        }
+        parent::__construct($errorcode, 'dbtransfer', $link, $a, $debuginfo);
     }
 }
 
-/**
- * Exception class for import operations.
- * @see moodle_exception
- * TODO subclass for specific purposes
- */
-class import_exception extends moodle_exception {
-    function __construct($errorcode, $a=null, $debuginfo=null) {
-        parent::__construct($errorcode, '', '', $a, $debuginfo);
-    }
-}