2021-05-01 21:47:29 +09:00
|
|
|
#!/usr/bin/env php
|
2020-04-09 08:17:20 +09:00
|
|
|
|
|
|
|
<?php
|
|
|
|
|
|
|
|
define('INSTALL_DIR', dirname(__DIR__));
|
|
|
|
|
|
|
|
require INSTALL_DIR . '/vendor/autoload.php';
|
|
|
|
|
2021-05-01 21:47:29 +09:00
|
|
|
use App\Util\Formatting;
|
2020-04-09 08:17:20 +09:00
|
|
|
use App\Util\HTML as H;
|
|
|
|
use Functional as F;
|
|
|
|
|
|
|
|
$template = '
|
2020-04-20 23:51:53 +09:00
|
|
|
graph database {
|
2020-04-09 08:17:20 +09:00
|
|
|
|
|
|
|
%tables%
|
|
|
|
|
|
|
|
%edges%
|
|
|
|
|
2020-04-20 23:51:53 +09:00
|
|
|
}
|
2020-04-09 08:17:20 +09:00
|
|
|
';
|
|
|
|
|
|
|
|
$files = glob(INSTALL_DIR . '/src/Entity/*.php');
|
|
|
|
|
|
|
|
$tables = [];
|
|
|
|
$edges = [];
|
2021-05-01 21:47:29 +09:00
|
|
|
$classes = [];
|
2020-04-09 08:17:20 +09:00
|
|
|
foreach ($files as $file) {
|
|
|
|
require_once $file;
|
|
|
|
|
2021-05-01 21:47:29 +09:00
|
|
|
$class = '';
|
2020-04-09 08:17:20 +09:00
|
|
|
$declared = get_declared_classes();
|
2021-05-01 21:47:29 +09:00
|
|
|
foreach ($declared as $dc) {
|
|
|
|
if (preg_match('/^(App|(Component|Plugin)\\\\[^\\\\]+)\\\\Entity/', $dc) && !in_array($dc, $classes)) {
|
|
|
|
$class = $dc;
|
|
|
|
$classes[] = $class;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-09 08:17:20 +09:00
|
|
|
$schema = $class::schemaDef();
|
2021-05-01 21:47:29 +09:00
|
|
|
$table = preg_replace(',`?([^`]+)`?,', '$1', $schema['name']);
|
2020-04-09 08:17:20 +09:00
|
|
|
$fields = [['name' => $table, 'type' => '']];
|
|
|
|
foreach ($schema['fields'] as $name => $opts) {
|
|
|
|
$fields[] = [
|
|
|
|
'name' => $name,
|
|
|
|
'type' => ": {$opts['type']}" . ($opts['type'] == 'varchar' ? "({$opts['length']})" : ''),
|
|
|
|
];
|
|
|
|
}
|
|
|
|
|
2021-05-01 21:47:29 +09:00
|
|
|
foreach ($schema['fields'] as $field => $opts) {
|
|
|
|
if (isset($opts['foreign key'])) {
|
|
|
|
[$foreign_entity, $foreign_key] = explode('.', $opts['target']);
|
2021-09-18 11:22:27 +09:00
|
|
|
$foreign_table = Formatting::camelCaseToSnakeCase(preg_replace('/Actor/', 'actor', $foreign_entity));
|
2021-05-01 21:47:29 +09:00
|
|
|
$edges[] = "{$table}:{$field} -- {$foreign_table}:{$foreign_key}";
|
2020-04-09 08:17:20 +09:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$cell = function ($field) {
|
|
|
|
$def = $field['name'] . $field['type'];
|
|
|
|
return ['tr' => ['td' => ['attrs' => ['port' => $field['name']], $def]]];
|
|
|
|
};
|
|
|
|
$html = ['table' => array_merge(
|
|
|
|
['attrs' => ['border' => '0', 'cellborder' => '1', 'cellspacing' => '0']],
|
|
|
|
F\map($fields, $cell)),
|
|
|
|
];
|
|
|
|
|
2021-05-01 21:47:29 +09:00
|
|
|
$tables[] = Formatting::indent("{$table} [shape=none, label=<\n" . Formatting::indent(H::html($html)) . "\n>]");
|
2020-04-09 08:17:20 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
$replace = [
|
2021-05-01 21:47:29 +09:00
|
|
|
'/%tables%/' => Formatting::indent(implode("\n", $tables)),
|
|
|
|
'/%edges%/' => Formatting::indent(implode("\n", $edges)),
|
2020-04-09 08:17:20 +09:00
|
|
|
// '/_/' => '\textunderscore ',
|
|
|
|
];
|
|
|
|
|
|
|
|
$out = $template;
|
|
|
|
foreach ($replace as $from => $to) {
|
|
|
|
$out = preg_replace($from, $to, $out);
|
|
|
|
}
|
|
|
|
|
2021-05-01 21:47:29 +09:00
|
|
|
$path = dirname(__DIR__) . '/docs/developer/src/database';
|
2020-04-09 08:17:20 +09:00
|
|
|
|
2020-04-20 23:51:53 +09:00
|
|
|
$outfile = $path . '/database.dot';
|
|
|
|
file_put_contents($outfile, $out);
|
|
|
|
|
2020-04-09 08:17:20 +09:00
|
|
|
system("neato -Goverlap=false -Gsplines=true -Tpdf {$path}/database.dot -o {$path}/database.pdf");
|
|
|
|
|
|
|
|
echo "Generated database diagram. See {$path}/database.pdf\n";
|