first commit
This commit is contained in:
@@ -0,0 +1,254 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file classes/db/DBDataXMLParser.php
|
||||
*
|
||||
* Copyright (c) 2014-2021 Simon Fraser University
|
||||
* Copyright (c) 2000-2021 John Willinsky
|
||||
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* @class DBDataXMLParser
|
||||
*
|
||||
* @ingroup db
|
||||
*
|
||||
* @brief Class to import and export database data from an XML format.
|
||||
* See dbscripts/xml/dtd/xmldata.dtd for the XML schema used.
|
||||
*/
|
||||
|
||||
namespace PKP\db;
|
||||
|
||||
use Exception;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use PKP\config\Config;
|
||||
use PKP\xml\PKPXMLParser;
|
||||
use PKP\xml\XMLNode;
|
||||
|
||||
class DBDataXMLParser
|
||||
{
|
||||
/** @var array the array of parsed SQL statements */
|
||||
public $sql;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->sql = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse an XML data file into SQL statements.
|
||||
*
|
||||
* @param string $file path to the XML file to parse
|
||||
*
|
||||
* @return array the array of SQL statements parsed
|
||||
*/
|
||||
public function parseData($file)
|
||||
{
|
||||
$this->sql = [];
|
||||
$parser = new PKPXMLParser();
|
||||
$tree = $parser->parse($file);
|
||||
if (!$tree) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$allTables = DB::getDoctrineSchemaManager()->listTableNames();
|
||||
|
||||
foreach ($tree->getChildren() as $type) {
|
||||
switch ($type->getName()) {
|
||||
case 'table':
|
||||
$fieldDefaultValues = [];
|
||||
|
||||
// Match table element
|
||||
foreach ($type->getChildren() as $row) {
|
||||
switch ($row->getName()) {
|
||||
case 'row':
|
||||
// Match a row element
|
||||
$fieldValues = [];
|
||||
|
||||
foreach ($row->getChildren() as $field) {
|
||||
// Get the field names and values for this INSERT
|
||||
[$fieldName, $value] = $this->_getFieldData($field);
|
||||
$fieldValues[$fieldName] = $value;
|
||||
}
|
||||
|
||||
$fieldValues = array_merge($fieldDefaultValues, $fieldValues);
|
||||
|
||||
if (count($fieldValues) > 0) {
|
||||
$this->sql[] = sprintf(
|
||||
'INSERT INTO %s (%s) VALUES (%s)',
|
||||
$type->getAttribute('name'),
|
||||
join(', ', array_keys($fieldValues)),
|
||||
join(', ', array_values($fieldValues))
|
||||
);
|
||||
}
|
||||
break;
|
||||
default: assert(false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'sql':
|
||||
// Match sql element (set of SQL queries)
|
||||
foreach ($type->getChildren() as $child) {
|
||||
switch ($child->getName()) {
|
||||
case 'drop':
|
||||
$table = $child->getAttribute('table');
|
||||
$column = $child->getAttribute('column');
|
||||
if ($column) {
|
||||
$this->sql = array_merge($this->sql, array_column(DB::pretend(function () use ($table, $column) {
|
||||
Schema::table($table, function (Blueprint $table) use ($column) {
|
||||
$table->dropColumn($column);
|
||||
});
|
||||
}), 'query'));
|
||||
} else {
|
||||
$this->sql = array_merge($this->sql, array_column(DB::pretend(function () use ($table) {
|
||||
Schema::drop($table);
|
||||
}), 'query'));
|
||||
}
|
||||
break;
|
||||
case 'rename':
|
||||
$table = $child->getAttribute('table');
|
||||
$column = $child->getAttribute('column');
|
||||
$to = $child->getAttribute('to');
|
||||
if ($column) {
|
||||
// Rename a column.
|
||||
$this->sql = array_merge($this->sql, array_column(DB::pretend(function () use ($table, $column, $to) {
|
||||
Schema::table($table, function (Blueprint $table) use ($column, $to) {
|
||||
$table->renameColumn($column, $to);
|
||||
});
|
||||
}), 'query'));
|
||||
} else {
|
||||
// Rename the table.
|
||||
$this->sql = array_merge($this->sql, array_column(DB::pretend(function () use ($table, $to) {
|
||||
Schema::rename($table, $to);
|
||||
}), 'query'));
|
||||
}
|
||||
break;
|
||||
case 'dropindex':
|
||||
$table = $child->getAttribute('table');
|
||||
$index = $child->getAttribute('index');
|
||||
if (!$table || !$index) {
|
||||
throw new Exception('dropindex called without table or index');
|
||||
}
|
||||
|
||||
$schemaManager = DB::getDoctrineSchemaManager();
|
||||
if ($child->getAttribute('ifexists') && !in_array($index, array_keys($schemaManager->listTableIndexes($table)))) {
|
||||
break;
|
||||
}
|
||||
$this->sql = array_merge($this->sql, array_column(DB::pretend(function () use ($table, $index) {
|
||||
Schema::table($table, function (Blueprint $table) use ($index) {
|
||||
$table->dropIndex($index);
|
||||
});
|
||||
}), 'query'));
|
||||
break;
|
||||
case 'query':
|
||||
// If a "driver" attribute is specified, multiple drivers can be
|
||||
// specified with a comma separator.
|
||||
$driver = $child->getAttribute('driver');
|
||||
if (empty($driver) || in_array(Config::getVar('database', 'driver'), array_map('trim', explode(',', $driver)))) {
|
||||
$this->sql[] = $child->getValue();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $this->sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the parsed SQL statements.
|
||||
*
|
||||
* @param bool $continueOnError continue to execute remaining statements if a failure occurs
|
||||
*
|
||||
* @return bool success
|
||||
*/
|
||||
public function executeData($continueOnError = false)
|
||||
{
|
||||
foreach ($this->sql as $stmt) {
|
||||
try {
|
||||
DB::statement($stmt);
|
||||
} catch (Exception $e) {
|
||||
if (!$continueOnError) {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the parsed SQL statements.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getSQL()
|
||||
{
|
||||
return $this->sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Quote a string to be appear as a value in an SQL INSERT statement.
|
||||
*
|
||||
* @param string $str
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function quoteString($str)
|
||||
{
|
||||
return DB::getPdo()->quote($str);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Private helper methods
|
||||
//
|
||||
/**
|
||||
* retrieve a field name and value from a field node
|
||||
*
|
||||
* @param XMLNode $fieldNode
|
||||
*
|
||||
* @return array an array with two entries: the field
|
||||
* name and the field value
|
||||
*/
|
||||
public function _getFieldData($fieldNode)
|
||||
{
|
||||
$fieldName = $fieldNode->getAttribute('name');
|
||||
$fieldValue = $fieldNode->getValue();
|
||||
|
||||
// Is this field empty? If so: do we want NULL or
|
||||
// an empty string?
|
||||
$isEmpty = $fieldNode->getAttribute('null');
|
||||
if (!is_null($isEmpty)) {
|
||||
assert(is_null($fieldValue));
|
||||
switch ($isEmpty) {
|
||||
case 1:
|
||||
$fieldValue = null;
|
||||
break;
|
||||
|
||||
case 0:
|
||||
$fieldValue = '';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Translate null to 'NULL' for SQL use.
|
||||
if (is_null($fieldValue)) {
|
||||
$fieldValue = 'NULL';
|
||||
} else {
|
||||
// Quote the value.
|
||||
if (!is_numeric($fieldValue)) {
|
||||
$fieldValue = $this->quoteString($fieldValue);
|
||||
}
|
||||
}
|
||||
|
||||
return [$fieldName, $fieldValue];
|
||||
}
|
||||
}
|
||||
|
||||
if (!PKP_STRICT_MODE) {
|
||||
class_alias('\PKP\db\DBDataXMLParser', '\DBDataXMLParser');
|
||||
}
|
||||
Reference in New Issue
Block a user