Update "tools" directory to be compliant with the php-cs-fixer

This commit is contained in:
2023-04-13 21:53:13 +02:00
parent ba83207264
commit e719b3e11c
5 changed files with 791 additions and 715 deletions

View File

@@ -1,383 +1,407 @@
#!/usr/bin/php
<?php
/** DomFramework
* @package domframework
* @author Dominique Fournier <dominique@fournier38.fr>
*
* SQL Migrate
* This tool allow to migrate the data from one SQL database to another.
* The DB engine can also be different.
*
* You must have the source DB and create a target DB with all the destination
* tables available.
* You must pass one parameter : the configuration file where all the
* informations will be stored. The file will be created if it doesn't exists.
*/
require_once (__DIR__."/../src/Console.php");
require_once (__DIR__."/../src/Dblayeroo.php");
require_once (__DIR__."/../src/Getopts.php");
require_once (__DIR__."/../src/Config.php");
/**
* DomFramework
* @package domframework
* @author Dominique Fournier <dominique@fournier38.fr>
*
* SQL Migrate
* This tool allow to migrate the data from one SQL database to another.
* The DB engine can also be different.
*
* You must have the source DB and create a target DB with all the destination
* tables available.
* You must pass one parameter : the configuration file where all the
* informations will be stored. The file will be created if it doesn't exists.
*/
/** Manage the configuration file
*/
class configuration extends \config
require_once(__DIR__ . "/../src/Console.php");
require_once(__DIR__ . "/../src/Dblayeroo.php");
require_once(__DIR__ . "/../src/Getopts.php");
require_once(__DIR__ . "/../src/Config.php");
/**
* Manage the configuration file
*/
class Configuration extends \Domframework\Config
{
/** The constructor of the configuration set the differents params
*/
function __construct ()
{
$this->default = array (
"db" => array (
"srcDSN" => "",
"srcUser" => null,
"srcPassword" => null,
"dstDSN" => "",
"dstUser" => null,
"dstPassword" => null,
),
"tables" => array (
),
"tablesRel" => array (
),
"fields" => array (
),
"tablesOrder" => array (
),
"deleteContent" => null,
);
}
/**
* The constructor of the configuration set the differents params
*/
public function __construct()
{
$this->default = [
"db" => [
"srcDSN" => "",
"srcUser" => null,
"srcPassword" => null,
"dstDSN" => "",
"dstUser" => null,
"dstPassword" => null,
],
"tables" => [
],
"tablesRel" => [
],
"fields" => [
],
"tablesOrder" => [
],
"deleteContent" => null,
];
}
}
/** The main class
*/
class main
/**
* The main class
*/
class Main
{
/** The constructor of the class do the main job
*/
public function __construct ()
{
// Manage the Getopts
$getopts = new Domframework\Getopts ();
$getopts->add ("Help", "?h", array ("help"), "Help of the software");
$getopts->add ("Step", "", array ("step:"), "Restart at provided step",
"StepIdentifier");
$getopts->add ("Debug", "", array ("debug"), "Display the SQL requests");
$getopts->add ("Execute", "", array ("execute"),
"Execute the configuration without requesting data (start at step 5)");
if ($getopts->get ("Help"))
die ($getopts->help ());
if ($getopts->get ("Step"))
/**
* The constructor of the class do the main job
*/
public function __construct()
{
if (intval ($getopts->get ("Step")) < 0 ||
intval ($getopts->get ("Step")) > 6)
die ("Invalid Step provided (Must be between 0 and 6)\n");
}
if (empty ($getopts->restOfLine ()))
throw new \Exception ("No configuration file provided");
if (count ($getopts->restOfLine ()) > 1)
throw new \Exception ("Too much configuration file provided");
$configurationFile = current ($getopts->restOfLine ());
if (! file_exists ($configurationFile))
touch ($configurationFile);
$config = new Domframework\Configuration ();
$config->confFile = $configurationFile;
$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;
if ($getopts->get ("Step"))
$step = intval ($getopts->get ("Step"));
if ($getopts->get ("Execute"))
$step = 5;
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 Domframework\Dblayeroo ($db["srcDSN"], $db["srcUser"],
$db["srcPassword"]);
$srcTables = $srcDB->listTables ();
$dstDB = new Domframework\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 Domframework\Dblayeroo ($db["srcDSN"], $db["srcUser"],
$db["srcPassword"]);
$dstDB = new Domframework\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";
// Manage the Getopts
$getopts = new Domframework\Getopts();
$getopts->add("Help", "?h", ["help"], "Help of the software");
$getopts->add(
"Step",
"",
["step:"],
"Restart at provided step",
"StepIdentifier"
);
$getopts->add("Debug", "", ["debug"], "Display the SQL requests");
$getopts->add(
"Execute",
"",
["execute"],
"Execute the configuration without requesting data (start at step 5)"
);
if ($getopts->get("Help")) {
die($getopts->help());
}
}
$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";
if ($config->get("fields"))
$value = $config->get("fields");
else
$value = array ();
foreach ($tablesRel as $dstTable=>$srcTable)
{
echo "- Destination Table '$dstTable': ";
if ($srcTable === "")
{
echo "No source table. SKIPPED\n";
continue;
if ($getopts->get("Step")) {
if (
intval($getopts->get("Step")) < 0 ||
intval($getopts->get("Step")) > 6
) {
die("Invalid Step provided (Must be between 0 and 6)\n");
}
}
if (empty($getopts->restOfLine())) {
throw new \Exception("No configuration file provided");
}
if (count($getopts->restOfLine()) > 1) {
throw new \Exception("Too much configuration file provided");
}
$configurationFile = current($getopts->restOfLine());
if (! file_exists($configurationFile)) {
touch($configurationFile);
}
$config = new Domframework\Configuration();
$config->confFile = $configurationFile;
$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;
}
if ($getopts->get("Step")) {
$step = intval($getopts->get("Step"));
}
if ($getopts->get("Execute")) {
$step = 5;
}
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 = [
"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 Domframework\Dblayeroo(
$db["srcDSN"],
$db["srcUser"],
$db["srcPassword"]
);
$srcTables = $srcDB->listTables();
$dstDB = new Domframework\Dblayeroo(
$db["dstDSN"],
$db["dstUser"],
$db["dstPassword"]
);
$dstTables = $dstDB->listTables();
$value = [
"srcTables" => $srcTables,
"dstTables" => $dstTables,
];
$config->set("tables", $value);
$step++;
echo "\n";
}
echo "#### Connect to the defined databases\n";
$srcDB = new Domframework\Dblayeroo(
$db["srcDSN"],
$db["srcUser"],
$db["srcPassword"]
);
$dstDB = new Domframework\Dblayeroo(
$db["dstDSN"],
$db["dstUser"],
$db["dstPassword"]
);
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)
{
$oldval = (isset ($config->get("fields")[$dstTable][$field])) ?
$config->get("fields")[$dstTable][$field] : "";
$answer = $this->ask (
"Destination Table '$dstTable' field '$field'", $oldval);
$value[$dstTable][$field] = $answer;
if (trim ($value[$dstTable][$field]) !== "")
break;
// TODO : Check if the field is valid (think about function)
$this->error ("The field source must be defined !");
}
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 = [];
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";
}
$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";
$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";
if ($config->get("fields")) {
$value = $config->get("fields");
} else {
$value = [];
}
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] = [];
}
if (! key_exists($field, $value[$dstTable])) {
$value[$dstTable][$field] = "";
}
while (1) {
$oldval = (isset($config->get("fields")[$dstTable][$field])) ?
$config->get("fields")[$dstTable][$field] : "";
$answer = $this->ask(
"Destination Table '$dstTable' field '$field'",
$oldval
);
$value[$dstTable][$field] = $answer;
if (trim($value[$dstTable][$field]) !== "") {
break;
}
// TODO : Check if the field is valid (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 = [];
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, [""]))) .
"\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([])->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) {
//print_r ($row);
$dstDB->clearRequest();
$dstDB->insert()
->setValues($row);
if (! $getopts->get("Debug")) {
echo ".";
} else {
echo $dstDB->getDisplayQuery();
}
$dstDB->execute();
}
echo "\n";
}
$step++;
}
// Last step
echo "#### Entering step $step: End of process\n";
}
$tablesOrder = $config->get ("tablesOrder");
if ($step === 5)
/**
* Ask a question to the user and return the answer
* @param string $question the question message
* @param string|null $proposal The optional pre-filled proposal
* @return string The answer
*/
public function ask($question, $proposal = "")
{
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");
}
$console = new Domframework\Console();
$console->echo("$question: ");
return trim($console->readline($proposal));
}
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)
{
//print_r ($row);
$dstDB->clearRequest ();
$dstDB->insert ()
->setValues ($row);
if (! $getopts->get ("Debug"))
echo ".";
else
echo $dstDB->getDisplayQuery ();
$dstDB->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
* @param string|null $proposal The optional pre-filled proposal
* @return string The answer
*/
public function ask ($question, $proposal = "")
{
$console = new Domframework\Console ();
$console->echo ("$question: ");
return trim ($console->readline ($proposal));
}
/** 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");
}
/**
* 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);
try {
$main = new \main();
} catch (Exception $e) {
file_put_contents("php://stderr", $e->getMessage() . "\n");
exit(4);
}