From 55ff6e13c3c463063fcdc9c0e2998cd208ace7a4 Mon Sep 17 00:00:00 2001 From: Dominique Fournier Date: Tue, 1 Aug 2017 09:42:31 +0000 Subject: [PATCH] Add sqlMigrate tool git-svn-id: https://svn.fournier38.fr/svn/ProgSVN/trunk@3855 bf3deb0d-5f1a-0410-827f-c0cc1f45334c --- tools/sqlMigrate.php | 340 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 340 insertions(+) create mode 100755 tools/sqlMigrate.php diff --git a/tools/sqlMigrate.php b/tools/sqlMigrate.php new file mode 100755 index 0000000..c095c79 --- /dev/null +++ b/tools/sqlMigrate.php @@ -0,0 +1,340 @@ +#!/usr/bin/php +default = array ( + "db" => array ( + "srcDSN" => "", + "srcUser" => null, + "srcPassword" => null, + "dstDSN" => "", + "dstUser" => null, + "dstPassword" => null, + ), + "tables" => array ( + ), + "tablesRel" => array ( + ), + "fields" => array ( + ), + "tablesOrder" => array ( + ), + "deleteContent" => null, + ); + } +} + +class main +{ + public function __construct () + { + global $argv; + if (! key_exists (1, $argv)) + throw new Exception ("No configuration file provided"); + if (! file_exists ($argv[1])) + touch ($argv[1]); + $config = new configuration (); + $config->confFile = $argv[1]; + $db = $config->get ("db"); + $tables = $config->get ("tables"); + $tablesRel = $config->get ("tablesRel"); + $fields = $config->get ("fields"); + $tablesOrder = $config->get ("tablesOrder"); + $deleteContent = $config->get ("deleteContent"); + if ($db["srcDSN"] === "" || $db["dstDSN"] === "") + $step = 0; + elseif (empty ($tables)) + $step = 1; + elseif (empty ($tablesRel)) + $step = 2; + elseif (empty ($fields)) + $step = 3; + elseif (empty ($tablesOrder)) + $step = 4; + elseif ($deleteContent === null) + $step = 5; + else + $step = 6; + + // TODO : Overload here the steps with the getopts + if ($step === 0) + { + // Step 0: ask the connection parameters + echo "#### Entering step 0 : ask the connection parameters\n"; + $srcDSN = $this->ask ("Enter SRC DSN"); + $srcUser = $this->ask ("Enter SRC User"); + $srcPassword = $this->ask ("Enter SRC Password"); + $dstDSN = $this->ask ("Enter DST DSN"); + $dstUser = $this->ask ("Enter DST User"); + $dstPassword = $this->ask ("Enter DST Password"); + if ($srcUser === "") + { + $srcUser = null; + $srcPassword = null; + } + if ($dstUser === "") + { + $dstUser = null; + $dstPassword = null; + } + $value = array ( + "srcDSN" => $srcDSN, + "srcUser" => $srcUser, + "srcPassword" => $srcPassword, + "dstDSN" => $dstDSN, + "dstUser" => $dstUser, + "dstPassword" => $dstPassword,); + $config->set ("db", $value); + $db = $config->get ("db"); + $step++; + } + if ($step === 1) + { + echo "#### Entering step 1: read the existing databases schemes\n"; + $srcDB = new dblayeroo ($db["srcDSN"], $db["srcUser"], + $db["srcPassword"]); + $srcTables = $srcDB->listTables (); + $dstDB = new dblayeroo ($db["dstDSN"], $db["dstUser"], + $db["dstPassword"]); + $dstTables = $dstDB->listTables (); + $value = array ( + "srcTables" => $srcTables, + "dstTables" => $dstTables, + ); + $config->set ("tables", $value); + $step++; + echo "\n"; + } + + echo "#### Connect to the defined databases\n"; + $srcDB = new dblayeroo ($db["srcDSN"], $db["srcUser"], + $db["srcPassword"]); + $dstDB = new dblayeroo ($db["dstDSN"], $db["dstUser"], + $db["dstPassword"]); + echo "\n"; + + if ($step == 2) + { + echo "#### Entering step 2: ask the relations between tables\n"; + $tables = $config->get ("tables"); + echo "# For each destination table, please provide the source table\n"; + sort ($tables["srcTables"]); + echo "# Allowed source tables : ". implode (", ", $tables["srcTables"]). + "\n"; + $value = array (); + natsort ($tables["dstTables"]); + foreach ($tables["dstTables"] as $table) + { + while (1) + { + $value[$table] = $this->ask ( + "Destination Table '$table' filled by source table"); + if (in_array ($value[$table], $tables["srcTables"]) || + $value[$table] === "") + continue 2; + $this->error ("The table '".$value[$table]." doesn't exists"); + echo "# Allowed source tables : ". + implode (", ", $tables["srcTables"])."\n"; + } + } + $config->set ("tablesRel", $value); + $step++; + echo "\n"; + } + + $tablesRel = $config->get ("tablesRel"); + if ($step === 3) + { + echo "#### Entering step 3: ask the relation between fields\n"; + echo "# For each destination table, if a source table is provided,\n". + "# for each field, provide the source SQL request (can be field,\n". + "# CONCAT(), text between simple quotes, null...)\n"; + $value = array (); + foreach ($tablesRel as $dstTable=>$srcTable) + { + echo "- Destination Table '$dstTable': "; + if ($srcTable === "") + { + echo "No source table. SKIPPED\n"; + continue; + } + echo "\n"; + $dstSchema = $dstDB->getTableSchema ($dstTable); + $srcSchema = $srcDB->getTableSchema ($srcTable); + echo " List of the allowed fields: ". + implode (", ", array_keys ($srcSchema["fields"]))."\n"; + foreach (array_keys ($dstSchema["fields"]) as $field) + { + if (! key_exists ($dstTable, $value)) + $value[$dstTable] = array (); + if (! key_exists ($field, $value[$dstTable])) + $value[$dstTable][$field] = ""; + while (1) + { + $value[$dstTable][$field] = $this->ask ( + "Destination Table '$dstTable' field '$field'"); + if (trim ($value[$dstTable][$field]) !== "") + continue 2; + // TODO : Check if the field is provided (think about function) + $this->error ("The field source must be defined !"); + } + } + $config->set ("fields", $value); + } + $step++; + echo "\n"; + } + $fields = $config->get ("fields"); + if ($step === 4) + { + echo "#### Entering step 4: Order the tables by foreign keys\n"; + echo "# The tables with foreign keys constraint must be populated \n". + "# after the tables depending of them\n"; + $tablesToOrder = array (); + foreach ($tablesRel as $dstTable=>$srcTable) + { + if ($srcTable !== "") + $tablesToOrder[] = $dstTable; + } + while (1) + { + echo "# Here are the tables to order: ". implode (",", $tablesToOrder). + "\n"; + $tablesOrder = $this->ask ("Order the tables, separated by commas"); + $tablesOrder = explode (",", $tablesOrder); + if (count ($tablesToOrder) === count ($tablesOrder)) + break; + $this->error ("Not all the tables are ordered"); + } + $config->set ("tablesOrder", $tablesOrder); + $step++; + echo "\n"; + } + + $tablesOrder = $config->get ("tablesOrder"); + if ($step === 5) + { + if ($deleteContent === null) + { + echo "# The content of the destination tables can be deleted before\n". + "# adding the source data.\n"; + echo "# Attention: the order is important if there is foreign keys!\n". + "# Remove the most constraint tables before deleting the less\n". + "# constraint ones\n"; + echo "# List of the destination tables: ". + implode (",", array_keys (array_diff ($tablesRel, array ("")))). + "\n"; + $deleteContent = $this->ask ("Get the list of the tables to be ". + "cleaned, separated by comas"); + $config->set ("deleteContent", $deleteContent); + $deleteContent = $config->get ("deleteContent"); + } + } + if ($deleteContent !== "") + { + echo "#### Entering step 5: delete tables content\n"; + foreach (explode (",", $deleteContent) as $table) + { + $table = trim ($table); + echo "- Delete content of table '$table'\n"; + $dstDB->table ($table)->unique (array ())->delete ()->execute (); + } + $step = 6; + echo "\n"; + } + else + { + echo "#### Entering step5: Skipped delete tables content\n"; + $step = 6; + } + if ($step === 6) + { + echo "#### Entering step 6: populate the destination database with the ". + "configured data\n"; + foreach ($tablesOrder as $dstTable) + { + echo "- Populate table $dstTable:\n"; + // Create the source SQL request. Add the alias name of the destination + // table to allow to import directely in the destination + $sql = "SELECT "; + $i = 0; + foreach ($fields[$dstTable] as $key=>$val) + { + if ($i > 0) + $sql .= ","; + $sql .= "$val AS $key"; + $i++; + } + $sql .= " FROM ".$tablesRel[$dstTable]; + echo " $sql\n"; + echo " "; + // Define all the variables needed to insert + $dstSchema = $dstDB->getTableSchema ($dstTable); + $dstDB->table ($dstTable); + $dstDB->fields ($dstSchema["fields"]); + $dstDB->primary ($dstSchema["primary"]); + foreach ($srcDB->directQuery ($sql) as $row) + { + echo "."; + //print_r ($row); + $dstDB->clearRequest (); + $dstDB->insert () + ->setValues ($row) + ->execute (); + } + echo "\n"; + } + $step++; + } + // Last step + echo "#### Entering step $step: End of process\n"; + } + + /** Ask a question to the user and return the answer + * @param string $question the question message + * @return string The answer + */ + public function ask ($question) + { + echo "$question: "; + $fp = fopen ("php://stdin", "r"); + $rc = trim (fgets ($fp)); + return $rc; + } + + /** Display an error to the user + * @param string $msg The error message to display + */ + public function error ($msg) + { + file_put_contents ("php://stderr", "ERROR: ".$msg."\n"); + } +} + +try +{ + $main = new \main (); +} +catch (Exception $e) +{ + file_put_contents ("php://stderr", $e->getMessage ()."\n"); + exit (4); +}