]> git.mjollnir.org Git - moodle.git/commitdiff
MDL-15635 DTL refactoring, adding release field to xml file
authorskodak <skodak>
Sat, 30 Aug 2008 18:54:57 +0000 (18:54 +0000)
committerskodak <skodak>
Sat, 30 Aug 2008 18:54:57 +0000 (18:54 +0000)
14 files changed:
admin/dbtransfer/exportlib.php [deleted file]
admin/dbtransfer/importlib.php [deleted file]
admin/dbtransfer/lib.php [deleted file]
lib/dtl/database_exporter.php [new file with mode: 0644]
lib/dtl/database_importer.php [new file with mode: 0644]
lib/dtl/database_mover.php [new file with mode: 0644]
lib/dtl/dbdata.xsd [moved from admin/dbtransfer/dbdata.xsd with 75% similarity]
lib/dtl/file_xml_database_exporter.php [new file with mode: 0644]
lib/dtl/file_xml_database_importer.php [new file with mode: 0644]
lib/dtl/string_xml_database_exporter.php [new file with mode: 0644]
lib/dtl/string_xml_database_importer.php [new file with mode: 0644]
lib/dtl/xml_database_exporter.php [new file with mode: 0644]
lib/dtl/xml_database_importer.php [new file with mode: 0644]
lib/dtllib.php [new file with mode: 0644]

diff --git a/admin/dbtransfer/exportlib.php b/admin/dbtransfer/exportlib.php
deleted file mode 100644 (file)
index c8bffc0..0000000
+++ /dev/null
@@ -1,380 +0,0 @@
-<?php  //$Id$
-
-/**
- * General database import classes
- * @author Andrei Bautu
- * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
- * @package dbtransfer
- */
-
-/**
- * Base class for database export operations. This class defines basic callbacks
- * for export operations and implements the @see export_database and
- * @export_table methods generic export processing. In general, subclasses will
- * override callback methods to provide specific output and (optionally)
- * @see export_database to add functionality.
- * Between a single pair of calls to @see begin_database_export and
- * @see finish_database_export, multiple non-overlapping pairs of calls may
- * be made to @see begin_table_export and @see finish_database_export for
- * different tables. Between one pair of calls to @see begin_table_export and
- * @see finish_database_export multiple calls may be made to
- * @see export_table_data for the same table.
- */
-abstract class database_exporter {
-    /** Connection to the source database (a @see moodle_database object). */
-    protected $mdb;
-    /** Database manager of the source database (a @see database_manager object). */
-    protected $manager;
-    /** Source database schema in XMLDB format (a @see xmldb_structure object). */
-    protected $schema;
-    /**
-     * Boolean flag - whether or not to check that XML database schema matches
-     * the RDBMS database schema before exporting (used by
-     * @see export_database).
-     */
-    protected $check_schema;
-
-    /**
-     * Object constructor.
-     *
-     * @param moodle_database $mdb Connection to the source database (a
-     * @see moodle_database object).
-     * @param xmldb_structure $schema Source database schema in XMLDB format (a
-     * @see xmldb_structure object). Use null to load the schema from the
-     * system's install.xml files.
-     * @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, xmldb_structure $schema=null, $check_schema=true) {
-        if (is_null($schema)) {
-            $schema = database_manager::get_install_xml_schema();
-        }
-        $this->mdb          = $mdb;
-        $this->manager      = $mdb->get_manager();
-        $this->schema       = $schema;
-        $this->check_schema = $check_schema;
-    }
-
-    /**
-     * Callback function. Should be called only once database per export
-     * operation, before any other export operations. Subclasses should export
-     * basic database information (version and timestamp).
-     *
-     * @param float $version the version of the system which generating the data
-     * @param string $timestamp the timestamp of the data (in ISO 8601) format.
-     * @param string $description a user description of the data.
-     * @return void
-     */
-    public function begin_database_export($version, $timestamp, $description) {
-    }
-
-    /**
-     * Callback function. Should be called only once per table export operation,
-     * before any other table export operations. Subclasses should export
-     * basic database information (name and schema's hash).
-     *
-     * @param xmldb_table $table - XMLDB object for the exported table
-     * @return void
-     */
-    public function begin_table_export(xmldb_table $table) {
-    }
-
-    /**
-     * Callback function. Should be called only once per table export operation,
-     * after all other table export operations.
-     *
-     * @param xmldb_table $table - XMLDB object for the exported table
-     */
-    public function finish_table_export(xmldb_table $table) {
-    }
-
-    /**
-     * Callback function. Should be called only once database per export
-     * operation, after all database export operations.
-     */
-    public function finish_database_export() {
-    }
-
-    /**
-     * Callback function. Should be called only once per record export operation,
-     * only between @see begin_table_export and @see finish_table_export calls.
-     * It will insert table data. Subclasses should export basic record
-     * information (data values).
-     *
-     * @param xmldb_table $table - XMLDB object of the table from which data was retrived
-     * @param object $data - data object (fields and values from record)
-     * @return void
-     */
-    public abstract function export_table_data(xmldb_table $table, $data);
-
-    /**
-     * Generic method to export the database. It checks the schema (if
-     * @see $check_schema is true), queries the database and calls
-     * appropiate callbacks.
-     *
-     * @exception export_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 && $this->manager->check_database_schema($this->schema)) {
-            //TODO put message in error lang
-            throw new export_exception('XMLDB schema does not match database schema.');
-        }
-        $tables = $this->schema->getTables();
-        $this->begin_database_export($CFG->version, 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.');
-            }
-            $this->begin_table_export($table);
-            foreach ($rs as $row) {
-                $this->export_table_data($table, $row);
-            }
-            $this->finish_table_export($table);
-        }
-        $this->finish_database_export();
-    }
-
-}
-
-/**
- * XML format exporter class.
- * Provides logic for writing XML tags and data inside appropiate callbacks.
- * Subclasses should define XML data sinks.
- */
-abstract class xml_database_exporter extends database_exporter {
-    /**
-     * Generic output method. Subclasses should implement it with code specific
-     * to the target XML sink.
-     */
-    protected abstract function output($text);
-
-    /**
-     * Callback function. Outputs open XML PI and moodle_database opening tag.
-     *
-     * @param float $version the version of the system which generating the data
-     * @param string $timestamp the timestamp of the data (in ISO 8601) format.
-     * @param string $description a user description of the data.
-     * @return void
-     */
-    public function begin_database_export($version, $timestamp, $description) {
-        $this->output('<?xml version="1.0" encoding="utf-8"?>');
-        //TODO add xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" and schema information
-        $this->output('<moodle_database version="'.$version.'" timestamp="'.$timestamp.'"'.(empty ($description) ? '' : ' comment="'.htmlspecialchars($description, ENT_QUOTES).'"').'>');
-    }
-
-    /**
-     * Callback function. Outputs table opening tag.
-     *
-     * @param xmldb_table $table - XMLDB object for the exported table
-     * @return void
-     */
-    public function begin_table_export(xmldb_table $table) {
-        $this->output('<table name="'.$table->getName().'" schemaHash="'.$table->getHash().'">');
-    }
-
-    /**
-     * Callback function. Outputs table closing tag.
-     *
-     * @param xmldb_table $table - XMLDB object for the exported table
-     */
-    public function finish_table_export(xmldb_table $table) {
-        $this->output('</table>');
-    }
-
-    /**
-     * Callback function. Outputs moodle_database closing tag.
-     */
-    public function finish_database_export() {
-        $this->output('</moodle_database>');
-    }
-
-    /**
-     * Callback function. Outputs record tag with field subtags and data.
-     *
-     * @param xmldb_table $table - XMLDB object of the table from which data was retrived
-     * @param object $data - data object (fields and values from record)
-     * @return void
-     */
-    public function export_table_data(xmldb_table $table, $data) {
-        $this->output('<record>');
-        foreach ($data as $key => $value) {
-            if (is_null($value)) {
-                $this->output('<field name="'.$key.'" value="null" />');
-            } else {
-                $this->output('<field name="'.$key.'">'.htmlspecialchars($value, ENT_NOQUOTES).'</field>');
-            }
-        }
-        $this->output('</record>');
-    }
-}
-
-/**
- * XML format exporter class to file storage.
- */
-class file_xml_database_exporter extends xml_database_exporter {
-    /** Path to the XML data file. */
-    protected $filepath;
-    /** File descriptor for the output file. */
-    protected $file;
-
-    /**
-     * Object constructor.
-     *
-     * @param string $filepath - path to the XML data file. Use null for PHP
-     * output stream.
-     * @param moodle_database $mdb Connection to the source database
-     * @see xml_database_exporter::__construct()
-     * @param xmldb_structure $schema Source database schema in XMLDB format
-     * @see xml_database_exporter::__construct()
-     * @param boolean $check_schema - whether or not to check that XML database
-     * @see xml_database_exporter::__construct()
-     */
-    function __construct($filepath, moodle_database $mdb, xmldb_structure $schema=null, $check_schema=true) {
-        parent::__construct($mdb, $schema, $check_schema);
-        if (is_null($filepath)) {
-            $filepath = 'php://output';
-        }
-        $this->filepath = $filepath;
-    }
-
-    /**
-     * Specific output method for the file XML sink.
-     */
-    protected function output($text) {
-        fwrite($this->file, $text);
-    }
-
-    /**
-     * 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
-     *
-     * @param string $description a user description of the data.
-     */
-    public function export_database($description=null) {
-        $this->file = fopen($this->filepath, 'wb');
-        parent::export_database($description);
-        fclose($this->file);
-    }
-}
-
-/**
- * XML format exporter class to memory storage (i.e. a string).
- */
-class string_xml_database_exporter extends xml_database_exporter {
-    /** String with XML data. */
-    protected $data;
-
-    /**
-     * Specific output method for the memory XML sink.
-     */
-    protected function output($text) {
-        $this->data .= $text;
-    }
-
-    /**
-     * Returns the output of the exporters
-     * @return string XML data from exporter
-     */
-    public function get_output() {
-        return $this->data;
-    }
-
-    /**
-     * 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
-     * @param string $description a user description of the data.
-     * @return void
-     */
-    public function export_database($description=null) {
-        $this->data = '';
-        parent::export_database($description);
-    }
-}
-
-class database_mover extends database_exporter {
-    /** Importer object used to transfer data. */
-    protected $importer;
-
-    /**
-     * 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 xmldb_structure $schema Source database schema in XMLDB format (a
-     * @see xmldb_structure object). Use null to load the schema from the
-     * system's install.xml files.
-     * @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, xmldb_structure $schema=null, $check_schema=true) {
-        parent::__construct($mdb_source, $schema, $check_schema);
-        $this->importer = new database_importer($mdb_target, $schema, $check_schema);
-    }
-
-    /**
-     * Callback function. Calls importer's begin_database_import callback method.
-     *
-     * @param float $version the version of the system which generating the data
-     * @param string $timestamp the timestamp of the data (in ISO 8601) format.
-     * @param string $description a user description of the data.
-     * @return void
-     */
-    public function begin_database_export($version, $timestamp, $description) {
-        $this->importer->init_database();
-        $this->importer->begin_database_import($version, $timestamp, $description);
-    }
-
-    /**
-     * Callback function. Calls importer's begin_table_import callback method.
-     *
-     * @param xmldb_table $table - XMLDB object for the exported table
-     * @return void
-     */
-    public function begin_table_export(xmldb_table $table) {
-        $this->importer->begin_table_import($table->getName(), $table->getHash());
-    }
-
-    /**
-     * Callback function. Calls importer's import_table_data callback method.
-     *
-     * @param xmldb_table $table - XMLDB object of the table from which data
-     * was retrived
-     * @param object $data - data object (fields and values from record)
-     * @return void
-     */
-    public function export_table_data(xmldb_table $table, $data) {
-        $this->importer->import_table_data($table->getName(), $data);
-    }
-
-    /**
-     * Callback function. Calls importer's finish_table_import callback method.
-     * @param xmldb_table $table - XMLDB object for the exported table
-     * @return void
-     */
-    public function finish_table_export(xmldb_table $table) {
-        $this->importer->finish_table_import($table->getName());
-    }
-
-    /**
-     * Callback function. Calls importer's finish_database_import callback method.
-     * @return void
-     */
-    public function finish_database_export() {
-        $this->importer->finish_database_import();
-    }
-}
diff --git a/admin/dbtransfer/importlib.php b/admin/dbtransfer/importlib.php
deleted file mode 100644 (file)
index 3f12ec4..0000000
+++ /dev/null
@@ -1,351 +0,0 @@
-<?php  //$Id$
-
-/**
- * General database import classes
- * @author Andrei Bautu
- * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
- * @package dbtransfer
- */
-
-/**
- * Base class for database import operations. This class implements
- * basic callbacks for import operations and defines the @see import_database
- * method as a common method for all importers. In general, subclasses will
- * override import_database and call other methods in appropriate moments.
- * Between a single pair of calls to @see begin_database_import and
- * @see finish_database_import, multiple non-overlapping pairs of calls may
- * be made to @see begin_table_import and @see finish_database_import for
- * different tables.
- * Between one pair of calls to @see begin_table_import and
- * @see finish_database_import multiple calls may be made to
- * @see import_table_data for the same table.
- * This class can be used directly, if the standard control flow (defined above)
- * is respected.
- */
-class database_importer {
-    /** Connection to the target database (a @see moodle_database object). */
-    protected $mdb;
-    /** Database manager of the target database (a @see database_manager object). */
-    protected $manager;
-    /** Target database schema in XMLDB format (a @see xmldb_structure object). */
-    protected $schema;
-    /**
-     * Boolean flag - whether or not to check that XML database schema matches
-     * the RDBMS database schema before importing (used by
-     * @see begin_database_import).
-     */
-    protected $check_schema;
-
-    /**
-     * Object constructor.
-     *
-     * @param moodle_database $mdb Connection to the target database (a
-     * @see moodle_database object). Use null to use the curent $DB connection.
-     * @param xmldb_structure $schema Target database schema in XMLDB format (a
-     * @see xmldb_structure object). Use null to load the schema from the
-     * system's install.xml files.
-     * @param boolean $check_schema - whether or not to check that XML database
-     * schema matches the RDBMS database schema before importing (inside
-     * @see begin_database_import).
-     */
-    public function __construct(moodle_database $mdb, xmldb_structure $schema=null, $check_schema=true) {
-        if (is_null($schema)) {
-            $schema = database_manager::get_install_xml_schema();
-        }
-        $this->mdb          = $mdb;
-        $this->manager      = $mdb->get_manager();
-        $this->schema       = $schema;
-        $this->check_schema = $check_schema;
-    }
-
-    /**
-     * Callback function. Should be called only once database per import
-     * 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
-     * version) fails
-     *
-     * @param float $version the version of the system which generated the data
-     * @param string $timestamp the timestamp of the data (in ISO 8601) format.
-     * @return void
-     */
-    public function begin_database_import($version, $timestamp) {
-        global $CFG;
-
-        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.');
-        }
-        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.');
-        }
-        $this->mdb->begin_sql();
-    }
-
-    /**
-     * 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 ddl_table_missing_exception if the table is missing
-     *
-     * @param string $tablename - the name of the table that will be imported
-     * @param string $schemaHash - the hash of the xmldb_table schema of the table
-     * @return void
-     */
-    public function begin_table_import($tablename, $schemaHash) {
-        $table = $this->schema->getTable($tablename);
-        if (is_null($table)) {
-            //TODO put message in error lang
-            throw new import_exception('Unknown table in import data');
-        }
-        if ($schemaHash != $table->getHash()) {
-            throw new import_exception('XMLDB schema does not match database schema.');
-        }
-        // 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);
-    }
-
-    /**
-     * Callback function. Should be called only once per table import operation,
-     * after all table changes are made. It will reset table sequences if any.
-     * @param string $tablename
-     * @return void
-     */
-    public function finish_table_import($tablename) {
-        $table  = $this->schema->getTable($tablename);
-        $fields = $table->getFields();
-        foreach ($fields as $field) {
-            if ($field->getSequence()) {
-                //TODO make sure that there aren't tables using two sequences (probably there is none)
-                $this->mdb->reset_sequence($tablename);
-                return;
-            }
-        }
-    }
-
-    /**
-     * Callback function. Should be called only once database per import
-     * operation, after all database changes are made. It will commit changes.
-     * @return void
-     */
-    public function finish_database_import() {
-        $this->mdb->commit_sql();
-    }
-
-    /**
-     * Callback function. Should be called only once per record import operation, only
-     * between @see begin_table_import and @see finish_table_import calls.
-     * It will insert table data.
-     *
-     * @exception dml_exception if data insert operation failed
-     *
-     * @param string $tablename - the name of the table in which data will be
-     * imported
-     * @param object $data - data object (fields and values will be inserted
-     * into table)
-     * @return void
-     */
-    public function import_table_data($tablename, $data) {
-        $this->mdb->import_record($tablename, $data);
-    }
-
-    /**
-     * All subclases must call this
-     * @return void
-     */
-    public function init_database() {
-        if (!$this->mdb->get_tables()) {
-            // not tables yet, time to create all tables
-            $this->manager->install_from_xmldb_structure($this->schema);
-        }
-    }
-}
-
-/**
- * XML format importer class (uses SAX for speed and low memory footprint).
- * Provides logic for parsing XML data and calling appropiate callbacks.
- * Subclasses should define XML data sources.
- */
-abstract class xml_database_importer extends database_importer {
-    /**
-     * Creates and setups a SAX parser. Subclasses should use this method to
-     * create the XML parser.
-     *
-     * @return resource XML parser resource.
-     */
-    protected function get_parser() {
-        $parser = xml_parser_create();
-        xml_set_object($parser, $this);
-        xml_set_element_handler($parser, 'tag_open', 'tag_close');
-        xml_set_character_data_handler($parser, 'cdata');
-        xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, false);
-        return $parser;
-    }
-
-    /**
-     * Callback function. Called by the XML parser for opening tags processing.
-     *
-     * @param resource $parser XML parser resource.
-     * @param string $tag name of opening tag
-     * @param array $attributes set of opening tag XML attributes
-     * @return void
-     */
-    protected function tag_open($parser, $tag, $attributes) {
-        switch ($tag) {
-            case 'moodle_database' :
-                $this->begin_database_import($attributes['version'], $attributes['timestamp']);
-                break;
-            case 'table' :
-                $this->current_table = $attributes['name'];
-                $this->begin_table_import($this->current_table, $attributes['schemaHash']);
-                break;
-            case 'record' :
-                $this->current_row = new object();
-                break;
-            case 'field' :
-                $this->current_field = $attributes['name'];
-                $this->current_data = @$attributes['value'] == 'null' ? null : '';
-                break;
-            default :
-                //TODO put message in error lang
-                throw new import_exception('XML content not valid for import operation.');
-        }
-    }
-
-    /**
-     * Callback function. Called by the XML parser for closing tags processing.
-     *
-     * @param resource $parser XML parser resource.
-     * @param string $tag name of opening tag
-     * @return void
-     */
-    protected function tag_close($parser, $tag) {
-        switch ($tag) {
-            case 'moodle_database' :
-                $this->finish_database_import();
-                break;
-            case 'table' :
-                $this->finish_table_import($this->current_table);
-                unset ($this->current_table);
-                break;
-            case 'record' :
-                $this->import_table_data($this->current_table, $this->current_row);
-                unset ($this->current_row);
-                break;
-            case 'field' :
-                $field = $this->current_field;
-                unset ($this->current_field);
-                $this->current_row-> $field = $this->current_data;
-                unset ($this->current_data);
-                break;
-            default :
-                //TODO put message in error lang
-                throw new import_exception('XML content not valid for import operation.');
-        }
-    }
-
-    /**
-     * Callback function. Called by the XML parser for character data processing.
-     *
-     * @param resource $parser XML parser resource.
-     * @param string $data character data to be processed
-     * @return void
-     */
-    protected function cdata($parser, $cdata) {
-        if (isset($this->current_field)) {
-            $this->current_data .= $cdata;
-        }
-    }
-
-    /**
-     * Common import method
-     * @return void
-     */
-    public abstract function import_database();
-}
-
-/**
- * XML format importer class from file storage.
- */
-class file_xml_database_importer extends xml_database_importer {
-    /** Path to the XML data file. */
-    protected $filepath;
-
-    /**
-     * Object constructor.
-     *
-     * @param string $filepath - path to the XML data file. Use null for PHP
-     * input stream.
-     * @param moodle_database $mdb Connection to the target database
-     * @see xml_database_importer::__construct()
-     * @param xmldb_structure $schema Target database schema in XMLDB format
-     * @see xml_database_importer::__construct()
-     * @param boolean $check_schema - whether or not to check that XML database
-     * @see xml_database_importer::__construct()
-     */
-    public function __construct($filepath, moodle_database $mdb, xmldb_structure $schema=null) {
-        parent::__construct($mdb, $schema);
-        if (is_null($filepath)) {
-            $filepath = 'php://input';
-        }
-        $this->filepath = $filepath;
-    }
-
-    /**
-     * Common import method: it opens the file storage, creates the parser, feeds
-     * the XML parser with data, releases the parser and closes the file storage.
-     * @return void
-     */
-    public function import_database() {
-        $this->init_database();
-        $file = fopen($this->filepath, 'r');
-        $parser = $this->get_parser();
-        while (($data = fread($file, 65536)) && xml_parse($parser, $data, feof($file)));
-        xml_parser_free($parser);
-        fclose($file);
-    }
-}
-
-/**
- * XML format importer class from memory storage (i.e. string).
- */
-class string_xml_database_importer extends xml_database_importer {
-    /** String with XML data. */
-    protected $data;
-
-    /**
-     * Object constructor.
-     *
-     * @param string data - string with XML data
-     * @param moodle_database $mdb Connection to the target database
-     * @see xml_database_importer::__construct()
-     * @param xmldb_structure $schema Target database schema in XMLDB format
-     * @see xml_database_importer::__construct()
-     * @param boolean $check_schema - whether or not to check that XML database
-     * @see xml_database_importer::__construct()
-     */
-    public function __construct($data, moodle_database $mdb, xmldb_structure $schema=null) {
-        parent::__construct($mdb, $schema);
-        $this->data = $data;
-    }
-
-    /**
-     * Common import method: it creates the parser, feeds the XML parser with
-     * data, releases the parser.
-     * @return void
-     */
-    public function import_database() {
-        $this->init_database();
-        $parser = $this->get_parser();
-        xml_parse($parser, $this->data, true);
-        xml_parser_free($parser);
-    }
-}
diff --git a/admin/dbtransfer/lib.php b/admin/dbtransfer/lib.php
deleted file mode 100644 (file)
index daf000e..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-<?php  //$Id$
-
-/**
- * Database transfer related code.
- * @author Andrei Bautu
- * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
- * @package dbtransfer
-*/
-
-require_once $CFG->libdir.'/xmldb/xmldb_structure.php';
-require_once $CFG->libdir.'/ddl/database_manager.php';
-require_once $CFG->dirroot.'/'.$CFG->admin.'/dbtransfer/exportlib.php';
-require_once $CFG->dirroot.'/'.$CFG->admin.'/dbtransfer/importlib.php';
-
-/**
- * Exception class for export operations.
- * @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);
-    }
-}
-
-/**
- * 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);
-    }
-}
diff --git a/lib/dtl/database_exporter.php b/lib/dtl/database_exporter.php
new file mode 100644 (file)
index 0000000..2c6b573
--- /dev/null
@@ -0,0 +1,136 @@
+<?php  //$Id$
+
+/**
+ * General database import classes
+ * @author Andrei Bautu
+ * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
+ * @package dbtransfer
+ */
+
+/**
+ * Base class for database export operations. This class defines basic callbacks
+ * for export operations and implements the @see export_database and
+ * @export_table methods generic export processing. In general, subclasses will
+ * override callback methods to provide specific output and (optionally)
+ * @see export_database to add functionality.
+ * Between a single pair of calls to @see begin_database_export and
+ * @see finish_database_export, multiple non-overlapping pairs of calls may
+ * be made to @see begin_table_export and @see finish_database_export for
+ * different tables. Between one pair of calls to @see begin_table_export and
+ * @see finish_database_export multiple calls may be made to
+ * @see export_table_data for the same table.
+ */
+abstract class database_exporter {
+    /** Connection to the source database (a @see moodle_database object). */
+    protected $mdb;
+    /** Database manager of the source database (a @see database_manager object). */
+    protected $manager;
+    /** Source database schema in XMLDB format (a @see xmldb_structure object). */
+    protected $schema;
+    /**
+     * Boolean flag - whether or not to check that XML database schema matches
+     * the RDBMS database schema before exporting (used by
+     * @see export_database).
+     */
+    protected $check_schema;
+
+    /**
+     * Object constructor.
+     *
+     * @param moodle_database $mdb Connection to the source 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, $check_schema=true) {
+        $this->mdb          = $mdb;
+        $this->manager      = $mdb->get_manager();
+        $this->schema       = $this->manager->get_install_xml_schema();
+        $this->check_schema = $check_schema;
+    }
+
+    /**
+     * Callback function. Should be called only once database per export
+     * operation, before any other export operations. Subclasses should export
+     * basic database information (version and timestamp).
+     *
+     * @param float $version the version of the system which generating the data
+     * @param string $release moodle release info
+     * @param string $timestamp the timestamp of the data (in ISO 8601) format.
+     * @param string $description a user description of the data.
+     * @return void
+     */
+    public abstract function begin_database_export($version, $release, $timestamp, $description);
+
+    /**
+     * Callback function. Should be called only once per table export operation,
+     * before any other table export operations. Subclasses should export
+     * basic database information (name and schema's hash).
+     *
+     * @param xmldb_table $table - XMLDB object for the exported table
+     * @return void
+     */
+    public abstract function begin_table_export(xmldb_table $table);
+
+    /**
+     * Callback function. Should be called only once per table export operation,
+     * after all other table export operations.
+     *
+     * @param xmldb_table $table - XMLDB object for the exported table
+     */
+    public abstract function finish_table_export(xmldb_table $table);
+
+    /**
+     * Callback function. Should be called only once database per export
+     * operation, after all database export operations.
+     */
+    public abstract function finish_database_export();
+
+    /**
+     * Callback function. Should be called only once per record export operation,
+     * only between @see begin_table_export and @see finish_table_export calls.
+     * It will insert table data. Subclasses should export basic record
+     * information (data values).
+     *
+     * @param xmldb_table $table - XMLDB object of the table from which data was retrived
+     * @param object $data - data object (fields and values from record)
+     * @return void
+     */
+    public abstract function export_table_data(xmldb_table $table, $data);
+
+    /**
+     * Generic method to export the database. It checks the schema (if
+     * @see $check_schema is true), queries the database and calls
+     * appropiate callbacks.
+     *
+     * @exception export_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.');
+        }
+        $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.');
+            }
+            $this->begin_table_export($table);
+            foreach ($rs as $row) {
+                $this->export_table_data($table, $row);
+            }
+            $this->finish_table_export($table);
+        }
+        $this->finish_database_export();
+    }
+
+}
diff --git a/lib/dtl/database_importer.php b/lib/dtl/database_importer.php
new file mode 100644 (file)
index 0000000..24cf79d
--- /dev/null
@@ -0,0 +1,165 @@
+<?php  //$Id$
+
+/**
+ * General database import classes
+ * @author Andrei Bautu
+ * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
+ * @package dbtransfer
+ */
+
+/**
+ * Base class for database import operations. This class implements
+ * basic callbacks for import operations and defines the @see import_database
+ * method as a common method for all importers. In general, subclasses will
+ * override import_database and call other methods in appropriate moments.
+ * Between a single pair of calls to @see begin_database_import and
+ * @see finish_database_import, multiple non-overlapping pairs of calls may
+ * be made to @see begin_table_import and @see finish_database_import for
+ * different tables.
+ * Between one pair of calls to @see begin_table_import and
+ * @see finish_database_import multiple calls may be made to
+ * @see import_table_data for the same table.
+ * This class can be used directly, if the standard control flow (defined above)
+ * is respected.
+ */
+class database_importer {
+    /** Connection to the target database (a @see moodle_database object). */
+    protected $mdb;
+    /** Database manager of the target database (a @see database_manager object). */
+    protected $manager;
+    /** Target database schema in XMLDB format (a @see xmldb_structure object). */
+    protected $schema;
+    /**
+     * Boolean flag - whether or not to check that XML database schema matches
+     * the RDBMS database schema before importing (used by
+     * @see begin_database_import).
+     */
+    protected $check_schema;
+
+    /**
+     * Object constructor.
+     *
+     * @param moodle_database $mdb Connection to the target database (a
+     * @see moodle_database object). Use null to use the curent $DB connection.
+     * @param boolean $check_schema - whether or not to check that XML database
+     * schema matches the RDBMS database schema before importing (inside
+     * @see begin_database_import).
+     */
+    public function __construct(moodle_database $mdb, $check_schema=true) {
+        $this->mdb          = $mdb;
+        $this->manager      = $mdb->get_manager();
+        $this->schema       = $this->manager->get_install_xml_schema();
+        $this->check_schema = $check_schema;
+    }
+
+    /**
+     * Callback function. Should be called only once database per import
+     * 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
+     * version) fails
+     *
+     * @param float $version the version of the system which generated the data
+     * @param string $timestamp the timestamp of the data (in ISO 8601) format.
+     * @return void
+     */
+    public function begin_database_import($version, $timestamp) {
+        global $CFG;
+
+        if (!$this->mdb->get_tables()) {
+            // not tables yet, time to create all tables
+            $this->manager->install_from_xmldb_structure($this->schema);
+        }
+
+        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.');
+        }
+
+        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.');
+        }
+        $this->mdb->begin_sql();
+    }
+
+    /**
+     * 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 ddl_table_missing_exception if the table is missing
+     *
+     * @param string $tablename - the name of the table that will be imported
+     * @param string $schemaHash - the hash of the xmldb_table schema of the table
+     * @return void
+     */
+    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');
+        }
+        if ($schemaHash != $table->getHash()) {
+            throw new import_exception('XMLDB schema does not match database schema.');
+        }
+        // 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);
+    }
+
+    /**
+     * Callback function. Should be called only once per table import operation,
+     * after all table changes are made. It will reset table sequences if any.
+     * @param string $tablename
+     * @return void
+     */
+    public function finish_table_import($tablename) {
+        $table  = $this->schema->getTable($tablename);
+        $fields = $table->getFields();
+        foreach ($fields as $field) {
+            if ($field->getSequence()) {
+                $this->mdb->reset_sequence($tablename);
+                return;
+            }
+        }
+    }
+
+    /**
+     * Callback function. Should be called only once database per import
+     * operation, after all database changes are made. It will commit changes.
+     * @return void
+     */
+    public function finish_database_import() {
+        $this->mdb->commit_sql();
+    }
+
+    /**
+     * Callback function. Should be called only once per record import operation, only
+     * between @see begin_table_import and @see finish_table_import calls.
+     * It will insert table data.
+     *
+     * @exception dml_exception if data insert operation failed
+     *
+     * @param string $tablename - the name of the table in which data will be
+     * imported
+     * @param object $data - data object (fields and values will be inserted
+     * into table)
+     * @return void
+     */
+    public function import_table_data($tablename, $data) {
+        $this->mdb->import_record($tablename, $data);
+    }
+
+    /**
+     * Common import method
+     * @return void
+     */
+    public function import_database() {
+        // implement in subclasses
+    }
+}
diff --git a/lib/dtl/database_mover.php b/lib/dtl/database_mover.php
new file mode 100644 (file)
index 0000000..cdadf24
--- /dev/null
@@ -0,0 +1,73 @@
+<?php  //$Id$
+
+class database_mover extends database_exporter {
+    /** Importer object used to transfer data. */
+    protected $importer;
+
+    /**
+     * 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 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) {
+        parent::__construct($mdb_source, $check_schema);
+        $this->importer = new database_importer($mdb_target, $check_schema);
+    }
+
+    /**
+     * Callback function. Calls importer's begin_database_import callback method.
+     *
+     * @param float $version the version of the system which generating the data
+     * @param string $timestamp the timestamp of the data (in ISO 8601) format.
+     * @param string $description a user description of the data.
+     * @return void
+     */
+    public function begin_database_export($version, $release, $timestamp, $description) {
+        $this->importer->begin_database_import($version, $timestamp, $description);
+    }
+
+    /**
+     * Callback function. Calls importer's begin_table_import callback method.
+     *
+     * @param xmldb_table $table - XMLDB object for the exported table
+     * @return void
+     */
+    public function begin_table_export(xmldb_table $table) {
+        $this->importer->begin_table_import($table->getName(), $table->getHash());
+    }
+
+    /**
+     * Callback function. Calls importer's import_table_data callback method.
+     *
+     * @param xmldb_table $table - XMLDB object of the table from which data
+     * was retrived
+     * @param object $data - data object (fields and values from record)
+     * @return void
+     */
+    public function export_table_data(xmldb_table $table, $data) {
+        $this->importer->import_table_data($table->getName(), $data);
+    }
+
+    /**
+     * Callback function. Calls importer's finish_table_import callback method.
+     * @param xmldb_table $table - XMLDB object for the exported table
+     * @return void
+     */
+    public function finish_table_export(xmldb_table $table) {
+        $this->importer->finish_table_import($table->getName());
+    }
+
+    /**
+     * Callback function. Calls importer's finish_database_import callback method.
+     * @return void
+     */
+    public function finish_database_export() {
+        $this->importer->finish_database_import();
+    }
+}
similarity index 75%
rename from admin/dbtransfer/dbdata.xsd
rename to lib/dtl/dbdata.xsd
index 6abf66c0271ba17e78938ff04448e3bc8cf992f6..174aaba022fe62f66c2c04628c3930f49953d48d 100644 (file)
@@ -1,14 +1,17 @@
 <?xml version="1.0" encoding="utf-8" ?> 
 <xs:schema elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema"> 
     <xs:element name="moodle_database" type="databaseType" /> 
-    <xs:complexType name="databaseType"> 
-        <xs:sequence> 
-            <xs:element maxOccurs="unbounded" name="table" type="tableType" /> 
-        </xs:sequence> 
-        <xs:attribute name="version" type="xs:float" use="required" /> 
-        <xs:attribute name="timestamp" type="xs:dateTime" use="required" /> 
-        <xs:attribute name="comment" type="xs:string" /> 
-    </xs:complexType> 
+    <xs:complexType name="databaseType">
+       <xs:sequence>
+               <xs:element maxOccurs="unbounded" name="table"
+                       type="tableType" />
+       </xs:sequence>
+       <xs:attribute name="version" type="xs:float" use="required" />
+        <xs:attribute name="release" type="xs:string"></xs:attribute>
+        <xs:attribute name="timestamp" type="xs:dateTime"
+               use="required" />
+       <xs:attribute name="comment" type="xs:string" />
+    </xs:complexType>
     <xs:complexType name="tableType"> 
         <xs:sequence> 
             <xs:element maxOccurs="unbounded" name="record" type="recordType" /> 
diff --git a/lib/dtl/file_xml_database_exporter.php b/lib/dtl/file_xml_database_exporter.php
new file mode 100644 (file)
index 0000000..6fec2e4
--- /dev/null
@@ -0,0 +1,51 @@
+<?php  //$Id$
+
+/**
+ * XML format exporter class to file storage.
+ */
+class file_xml_database_exporter extends xml_database_exporter {
+    /** Path to the XML data file. */
+    protected $filepath;
+    /** File descriptor for the output file. */
+    protected $file;
+
+    /**
+     * Object constructor.
+     *
+     * @param string $filepath - path to the XML data file. Use null for PHP
+     * output stream.
+     * @param moodle_database $mdb Connection to the source database
+     * @see xml_database_exporter::__construct()
+     * @param boolean $check_schema - whether or not to check that XML database
+     * @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;
+    }
+
+    /**
+     * Specific output method for the file XML sink.
+     */
+    protected function output($text) {
+        fwrite($this->file, $text);
+    }
+
+    /**
+     * 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
+     *
+     * @param string $description a user description of the data.
+     */
+    public function export_database($description=null) {
+        // TODO: add exception if file creation fails
+        $this->file = fopen($this->filepath, 'wb');
+        parent::export_database($description);
+        fclose($this->file);
+    }
+}
diff --git a/lib/dtl/file_xml_database_importer.php b/lib/dtl/file_xml_database_importer.php
new file mode 100644 (file)
index 0000000..8d6dfc6
--- /dev/null
@@ -0,0 +1,45 @@
+<?php  //$Id$
+
+/**
+ * XML format importer class from file storage.
+ */
+class file_xml_database_importer extends xml_database_importer {
+    /** Path to the XML data file. */
+    protected $filepath;
+
+    /**
+     * Object constructor.
+     *
+     * @param string $filepath - path to the XML data file. Use null for PHP
+     * input stream.
+     * @param moodle_database $mdb Connection to the target database
+     * @see xml_database_importer::__construct()
+     * @param boolean $check_schema - whether or not to check that XML database
+     * @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);
+    }
+
+    /**
+     * Common import method: it opens the file storage, creates the parser, feeds
+     * the XML parser with data, releases the parser and closes the file storage.
+     * @return void
+     */
+    public function import_database() {
+        $file = fopen($this->filepath, 'r');
+        $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.");
+            }
+        }
+        xml_parser_free($parser);
+        fclose($file);
+    }
+}
diff --git a/lib/dtl/string_xml_database_exporter.php b/lib/dtl/string_xml_database_exporter.php
new file mode 100644 (file)
index 0000000..8464992
--- /dev/null
@@ -0,0 +1,37 @@
+<?php  //$Id$
+
+/**
+ * XML format exporter class to memory storage (i.e. a string).
+ */
+class string_xml_database_exporter extends xml_database_exporter {
+    /** String with XML data. */
+    protected $data;
+
+    /**
+     * Specific output method for the memory XML sink.
+     */
+    protected function output($text) {
+        $this->data .= $text;
+    }
+
+    /**
+     * Returns the output of the exporters
+     * @return string XML data from exporter
+     */
+    public function get_output() {
+        return $this->data;
+    }
+
+    /**
+     * 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
+     * @param string $description a user description of the data.
+     * @return void
+     */
+    public function export_database($description=null) {
+        $this->data = '';
+        parent::export_database($description);
+    }
+}
diff --git a/lib/dtl/string_xml_database_importer.php b/lib/dtl/string_xml_database_importer.php
new file mode 100644 (file)
index 0000000..983d566
--- /dev/null
@@ -0,0 +1,37 @@
+<?php  //$Id$
+
+/**
+ * XML format importer class from memory storage (i.e. string).
+ */
+class string_xml_database_importer extends xml_database_importer {
+    /** String with XML data. */
+    protected $data;
+
+    /**
+     * Object constructor.
+     *
+     * @param string data - string with XML data
+     * @param moodle_database $mdb Connection to the target database
+     * @see xml_database_importer::__construct()
+     * @param boolean $check_schema - whether or not to check that XML database
+     * @see xml_database_importer::__construct()
+     */
+    public function __construct($data, moodle_database $mdb, $check_schema=true) {
+        parent::__construct($mdb, $check_schema);
+        $this->data = $data;
+    }
+
+    /**
+     * Common import method: it creates the parser, feeds the XML parser with
+     * data, releases the parser.
+     * @return void
+     */
+    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.");
+        }
+        xml_parser_free($parser);
+    }
+}
diff --git a/lib/dtl/xml_database_exporter.php b/lib/dtl/xml_database_exporter.php
new file mode 100644 (file)
index 0000000..e58e339
--- /dev/null
@@ -0,0 +1,74 @@
+<?php  //$Id$
+
+/**
+ * XML format exporter class.
+ * Provides logic for writing XML tags and data inside appropiate callbacks.
+ * Subclasses should define XML data sinks.
+ */
+abstract class xml_database_exporter extends database_exporter {
+    /**
+     * Generic output method. Subclasses should implement it with code specific
+     * to the target XML sink.
+     */
+    protected abstract function output($text);
+
+    /**
+     * Callback function. Outputs open XML PI and moodle_database opening tag.
+     *
+     * @param float $version the version of the system which generating the data
+     * @param string $release moodle release info
+     * @param string $timestamp the timestamp of the data (in ISO 8601) format.
+     * @param string $description a user description of the data.
+     * @return void
+     */
+    public function begin_database_export($version, $release, $timestamp, $description) {
+        $this->output('<?xml version="1.0" encoding="utf-8"?>');
+        //TODO add xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" and schema information
+        $this->output('<moodle_database version="'.$version.'" release="'.$release.'" timestamp="'.$timestamp.'"'.(empty ($description) ? '' : ' comment="'.htmlspecialchars($description, ENT_QUOTES).'"').'>');
+    }
+
+    /**
+     * Callback function. Outputs table opening tag.
+     *
+     * @param xmldb_table $table - XMLDB object for the exported table
+     * @return void
+     */
+    public function begin_table_export(xmldb_table $table) {
+        $this->output('<table name="'.$table->getName().'" schemaHash="'.$table->getHash().'">');
+    }
+
+    /**
+     * Callback function. Outputs table closing tag.
+     *
+     * @param xmldb_table $table - XMLDB object for the exported table
+     */
+    public function finish_table_export(xmldb_table $table) {
+        $this->output('</table>');
+    }
+
+    /**
+     * Callback function. Outputs moodle_database closing tag.
+     */
+    public function finish_database_export() {
+        $this->output('</moodle_database>');
+    }
+
+    /**
+     * Callback function. Outputs record tag with field subtags and data.
+     *
+     * @param xmldb_table $table - XMLDB object of the table from which data was retrived
+     * @param object $data - data object (fields and values from record)
+     * @return void
+     */
+    public function export_table_data(xmldb_table $table, $data) {
+        $this->output('<record>');
+        foreach ($data as $key => $value) {
+            if (is_null($value)) {
+                $this->output('<field name="'.$key.'" value="null" />');
+            } else {
+                $this->output('<field name="'.$key.'">'.htmlspecialchars($value, ENT_NOQUOTES).'</field>');
+            }
+        }
+        $this->output('</record>');
+    }
+}
diff --git a/lib/dtl/xml_database_importer.php b/lib/dtl/xml_database_importer.php
new file mode 100644 (file)
index 0000000..4badbc2
--- /dev/null
@@ -0,0 +1,133 @@
+<?php  //$Id$
+
+/**
+ * XML format importer class (uses SAX for speed and low memory footprint).
+ * Provides logic for parsing XML data and calling appropiate callbacks.
+ * Subclasses should define XML data sources.
+ */
+abstract class xml_database_importer extends database_importer {
+    protected $current_table;
+    protected $current_row;
+    protected $current_field;
+    protected $current_data;
+    protected $current_data_is_null;
+
+    /**
+     * Creates and setups a SAX parser. Subclasses should use this method to
+     * create the XML parser.
+     *
+     * @return resource XML parser resource.
+     */
+    protected function get_parser() {
+        $parser = xml_parser_create();
+        xml_set_object($parser, $this);
+        xml_set_element_handler($parser, 'tag_open', 'tag_close');
+        xml_set_character_data_handler($parser, 'cdata');
+        xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, false);
+        return $parser;
+    }
+
+    /**
+     * Callback function. Called by the XML parser for opening tags processing.
+     *
+     * @param resource $parser XML parser resource.
+     * @param string $tag name of opening tag
+     * @param array $attributes set of opening tag XML attributes
+     * @return void
+     */
+    protected function tag_open($parser, $tag, $attributes) {
+        switch ($tag) {
+            case 'moodle_database' :
+                if (empty($attributes['version']) || empty($attributes['timestamp'])) {
+                    throw new import_exception('Missing tag attribute in data file.');
+                }
+                $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.');
+                }
+                if (empty($attributes['name']) || empty($attributes['schemaHash'])) {
+                    throw new import_exception('Missing tag attribute in data file.');
+                }
+                $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.');
+                }
+                $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.');
+                }
+                $this->current_field = $attributes['name'];
+                $this->current_data = '';
+                if (isset($attributes['value']) and $attributes['value'] === 'null') {
+                    $this->current_data_is_null = true;
+                } else {
+                    $this->current_data_is_null = false;
+                }
+                break;
+            default :
+                //TODO localize
+                throw new import_exception('XML content not valid for import operation.');
+        }
+    }
+
+    /**
+     * Callback function. Called by the XML parser for closing tags processing.
+     *
+     * @param resource $parser XML parser resource.
+     * @param string $tag name of opening tag
+     * @return void
+     */
+    protected function tag_close($parser, $tag) {
+        switch ($tag) {
+            case 'moodle_database' :
+                $this->finish_database_import();
+                break;
+
+            case 'table' :
+                $this->finish_table_import($this->current_table);
+                $this->current_table = null;
+                break;
+
+            case 'record' :
+                $this->import_table_data($this->current_table, $this->current_row);
+                $this->current_row = null;;
+                break;
+
+            case 'field' :
+                $field = $this->current_field;
+                if ($this->current_data_is_null) {
+                    $this->current_row->$field = null;
+                } else {
+                    $this->current_row->$field = $this->current_data;
+                }
+                $this->current_field        = null;
+                $this->current_data         = null;
+                $this->current_data_is_null = null;
+                break;
+
+            default :
+                //TODO put message in error lang
+                throw new import_exception('XML content not valid for import operation.');
+        }
+    }
+
+    /**
+     * Callback function. Called by the XML parser for character data processing.
+     *
+     * @param resource $parser XML parser resource.
+     * @param string $data character data to be processed
+     * @return void
+     */
+    protected function cdata($parser, $cdata) {
+        if (isset($this->current_field)) {
+            $this->current_data .= $cdata;
+        }
+    }
+}
diff --git a/lib/dtllib.php b/lib/dtllib.php
new file mode 100644 (file)
index 0000000..d5e8874
--- /dev/null
@@ -0,0 +1,63 @@
+<?php // $Id$
+
+///////////////////////////////////////////////////////////////////////////
+//                                                                       //
+// NOTICE OF COPYRIGHT                                                   //
+//                                                                       //
+// Moodle - Modular Object-Oriented Dynamic Learning Environment         //
+//          http://moodle.com                                            //
+//                                                                       //
+// Copyright (C) 1999 onwards Martin Dougiamas     http://dougiamas.com  //
+// Copyright (C) 2008 onwards Andrei Bautu                               //
+//                                                                       //
+// This program is free software; you can redistribute it and/or modify  //
+// it under the terms of the GNU General Public License as published by  //
+// the Free Software Foundation; either version 2 of the License, or     //
+// (at your option) any later version.                                   //
+//                                                                       //
+// This program is distributed in the hope that it will be useful,       //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of        //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         //
+// GNU General Public License for more details:                          //
+//                                                                       //
+//          http://www.gnu.org/copyleft/gpl.html                         //
+//                                                                       //
+///////////////////////////////////////////////////////////////////////////
+
+// DTL == Dtatabase Transfer Library
+// This library includes all the required functions used to handle
+// transfer of data from one database to another.
+
+require_once($CFG->libdir.'/ddllib.php');
+
+require_once($CFG->libdir.'/dtl/database_exporter.php');
+require_once($CFG->libdir.'/dtl/xml_database_exporter.php');
+require_once($CFG->libdir.'/dtl/file_xml_database_exporter.php');
+require_once($CFG->libdir.'/dtl/string_xml_database_exporter.php');
+require_once($CFG->libdir.'/dtl/database_mover.php');
+require_once($CFG->libdir.'/dtl/database_importer.php');
+require_once($CFG->libdir.'/dtl/xml_database_importer.php');
+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.
+ * @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);
+    }
+}
+
+/**
+ * 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);
+    }
+}