183 lines
5.5 KiB
PHP
Executable File
183 lines
5.5 KiB
PHP
Executable File
#!/usr/bin/php
|
|
<?php
|
|
|
|
/**
|
|
* DomFramework
|
|
* @package domframework
|
|
* @author Dominique Fournier <dominique@fournier38.fr>
|
|
*/
|
|
|
|
require_once(__DIR__ . "/../src/Dblayeroo.php");
|
|
|
|
/**
|
|
* modelGraph
|
|
* Allow to create the relational graph of an existing database
|
|
* Use GraphViz to generate the graph
|
|
* Request the database DSN to operate
|
|
*/
|
|
class Modelgraph
|
|
{
|
|
// PROPERTIES
|
|
/**
|
|
* The connected object dblayeroo
|
|
*/
|
|
private $db;
|
|
/**
|
|
* The output file
|
|
*/
|
|
private $output;
|
|
|
|
/**
|
|
* The constructor wait for $dsn
|
|
* @param string $dsn The DSN to connect to database
|
|
* @param string $username The username to connect to database
|
|
* @param string $password The password to connect to database
|
|
* @param string $output The output file to generate
|
|
*/
|
|
public function __construct($dsn, $username, $password, $output)
|
|
{
|
|
$this->output = $output;
|
|
$this->db = new Domframework\Dblayeroo($dsn, $username, $password);
|
|
$this->graphvizCommande();
|
|
}
|
|
|
|
/**
|
|
* Generate the output file
|
|
*/
|
|
public function generate()
|
|
{
|
|
$tables = [];
|
|
foreach ($this->db->listTables() as $table) {
|
|
$tables[$table] = $this->db->getTableSchema($table);
|
|
}
|
|
$d = "digraph G {\n";
|
|
$d .= " graph [\n";
|
|
$d .= " label = <" .
|
|
"<B>Database " . $this->db->databasename() . "</B><BR/>" .
|
|
"<B>" . date("Y-m-d") . "</B>" .
|
|
">\n";
|
|
$d .= " ]\n";
|
|
$d .= " node [\n";
|
|
$d .= " shape=box\n";
|
|
$d .= " fontname = \"helvetica\"\n";
|
|
$d .= " ];\n";
|
|
$d .= " rankdir=RL\n";
|
|
|
|
// Generate the tables objects with the fields
|
|
foreach ($tables as $table => $schema) {
|
|
$d .= " /**
|
|
* TABLE '$table'
|
|
*/\n";
|
|
$d .= " \"$table\" [\n";
|
|
$d .= " shape = \"plaintext\"\n";
|
|
$d .= " label = <\n";
|
|
$d .= " <TABLE BORDER=\"0\" CELLBORDER=\"1\" CELLSPACING=\"0\">\n";
|
|
// Display the name of the table as title
|
|
$d .= " <TR><TD COLSPAN=\"3\" BGCOLOR=\"#00B0E0\">";
|
|
$d .= "$table</TD></TR>\n";
|
|
// Display the fields
|
|
$i = 0;
|
|
foreach ($schema["fields"] as $field => $params) {
|
|
$d .= " <TR>\n";
|
|
$d .= " <TD SIDES=\"TBL\" PORT=\"OUT-$field\">";
|
|
if (key_exists($field, $schema["foreign"])) {
|
|
// Foreign Key
|
|
$d .= "<FONT COLOR=\"#F02020\">!</FONT>";
|
|
} elseif (
|
|
key_exists("primary", $schema) &&
|
|
$field === $schema["primary"]
|
|
) {
|
|
$d .= "🔑";
|
|
} elseif (in_array("not null", $params)) {
|
|
// Primary key found
|
|
$d .= "<FONT COLOR=\"#00B0E0\">◆</FONT>";
|
|
} else {
|
|
// NOT NULL
|
|
$d .= "◇";
|
|
}
|
|
$d .= "</TD>\n";
|
|
$d .= " <TD ALIGN=\"LEFT\" SIDES=\"TB\">";
|
|
$d .= $field;
|
|
$d .= "</TD>\n";
|
|
$d .= " <TD ALIGN=\"LEFT\" PORT=\"IN-$field\" SIDES=\"TBR\">";
|
|
$d .= $params[0];
|
|
$d .= "</TD>\n";
|
|
$d .= " </TR>\n";
|
|
$i++;
|
|
}
|
|
$d .= " </TABLE>>\n";
|
|
$d .= " ];\n";
|
|
}
|
|
// Generate the links between the tables
|
|
foreach ($tables as $table => $schema) {
|
|
// "node1":"f2" -> "node5":"f0" [];
|
|
foreach ($schema["foreign"] as $field => $params) {
|
|
$d .= "\"$table\":\"OUT-$field\" -> \"" . $params[0] .
|
|
"\":\"IN-" . $params[1] . "\" ";
|
|
$d .= "[];\n";
|
|
}
|
|
}
|
|
$d .= "}\n";
|
|
//echo $d;
|
|
$this->createJPG($d);
|
|
}
|
|
|
|
/**
|
|
* Look for the dot command
|
|
* @return the full path of 'dot' command
|
|
*/
|
|
private function graphvizCommande()
|
|
{
|
|
foreach (explode(":", getenv("PATH")) as $path) {
|
|
if (file_exists("$path/dot")) {
|
|
return "$path/dot";
|
|
}
|
|
}
|
|
throw new \Exception(
|
|
"Can not find 'dot' executable. Install graphviz",
|
|
500
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Generate the JPEG file with graphviz
|
|
* @param string $content The content of the GV file
|
|
*/
|
|
private function createJPG($content)
|
|
{
|
|
$tmp = tempnam("/tmp", "modelgraph_");
|
|
file_put_contents($tmp, $content);
|
|
$cmd = $this->graphvizCommande() . " -T jpeg $tmp " .
|
|
"-o " . escapeshellarg($this->output) . " 2>&1";
|
|
exec($cmd, $output);
|
|
unlink($tmp);
|
|
if (!empty($output)) {
|
|
echo "ERROR : " . implode("\n", $output);
|
|
exit(2);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// MAIN PROGRAM
|
|
if (isset($argv[1]) && $argv[1] === "-h") {
|
|
echo "Create the ER Diagram of a SQL database\n";
|
|
echo "Usage : \n";
|
|
echo $argv[0] . " DSN username password outputfile.jpg\n";
|
|
echo "DSN Examples : 'mysql:dbname=databaseName'\n";
|
|
}
|
|
if (! isset($argv[1])) {
|
|
die("No DSN provided\n");
|
|
}
|
|
if (! isset($argv[2])) {
|
|
die("No username provided\n");
|
|
}
|
|
if (! isset($argv[3])) {
|
|
die("No password provided\n");
|
|
}
|
|
if (! isset($argv[4])) {
|
|
die("No output file provided\n");
|
|
}
|
|
$modelgraph = new Modelgraph($argv[1], $argv[2], $argv[3], $argv[4]);
|
|
$modelgraph->generate();
|