Skip to content

Instantly share code, notes, and snippets.

@coudenysj
Last active August 29, 2015 14:15
Show Gist options
  • Save coudenysj/a73fc2fb29f7c5729472 to your computer and use it in GitHub Desktop.
Save coudenysj/a73fc2fb29f7c5729472 to your computer and use it in GitHub Desktop.
Using reStructuredText to generate an ERD
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE document PUBLIC "+//IDN docutils.sourceforge.net//DTD Docutils Generic//EN//XML" "http://docutils.sourceforge.net/docs/ref/docutils.dtd">
<!-- Generated by Docutils 0.12 -->
<document ids="entity-relationship-diagram" names="entity-relationship\ diagram" source="source.rst" title="Entity-Relationship Diagram"><title>Entity-Relationship Diagram</title><paragraph>This file is used to describe all entities, their properties and how they relate.</paragraph><section ids="user" names="user"><title>User</title><paragraph>A user entity is used to...</paragraph><section dupnames="fields" ids="fields"><title>Fields</title><field_list><field><field_name>username</field_name><field_body><paragraph>The username a user will use to login to his/her account</paragraph></field_body></field><field><field_name>email</field_name><field_body><paragraph>...</paragraph></field_body></field></field_list></section><section ids="relations" names="relations"><title>Relations</title><field_list><field><field_name><reference name="Group" refid="group">Group</reference></field_name><field_body><paragraph>A user can be part of one group.</paragraph></field_body></field></field_list></section></section><section ids="group" names="group"><title>Group</title><paragraph>A group of users can have specific roles in the application.</paragraph><section dupnames="fields" ids="id1"><title>Fields</title><field_list><field><field_name>name</field_name><field_body><paragraph>The group name.
This should be...</paragraph></field_body></field><field><field_name>roles</field_name><field_body><paragraph>An list of roles</paragraph></field_body></field></field_list></section></section></document>
rst2xml.py source.rst > ERD.xml && php parse.php ERD.xml dot | dot -o ERD.png -Tpng && open ERD.png
#!/usr/bin/env php
<?php
/**
* Generate a format from the XML file.
*
* <code>
* ./parse.php ERD.xml dot
* ./parse.php ERD.xml dump
* </code>
*
* @author Jachim Coudenys <jachimcoudenys@gmail.com>
*
* @todo Only detect links on the owning side
* @todo Use the tags to create sub diagrams so they are grouped together
*/
$file = isset($argv[1]) ? $argv[1] : false;
if (!$file || !is_file($file)) {
echo 'Supply a valid file.' . PHP_EOL;
exit(1);
}
$format = isset($argv[2]) ? $argv[2] : 'dump';
$nodes = array();
$xml = simplexml_load_file($file);
foreach ($xml as $node) {
if (isset($node->section)) {
$title = (string) ($node->title);
$nodes[$title] = array(
'fields' => array(),
'relations' => array(),
);
foreach ($node as $subNode) {
if (isset($subNode->title)
&& $subNode->title == 'Fields'
&& isset($subNode->field_list->field)
) {
foreach ($subNode->field_list->field as $f) {
$description = (string) $f->field_body->paragraph;
$dataType = '';
$matches = array();
if (preg_match('#\{([a-zA-Z]+)\}#', $description, $matches)) {
$dataType = $matches[1];
}
$nodes[$title]['fields'][(string) $f->field_name] = array(
'description' => $description,
'dataType' => $dataType,
);
}
}
if (isset($subNode->title)
&& $subNode->title == 'Relations'
&& isset($subNode->field_list->field)
) {
foreach ($subNode->field_list->field as $f) {
$description = (string) $f->field_body->paragraph;
$type = 'normal';
if (stripos($description, 'optional') !== false) {
$type = 'optional';
}
$nodes[$title]['relations'][(string) $f->field_name->reference] = array(
'description' => $description,
'type' => $type,
);
}
}
}
}
}
if ($format == 'dot') {
echo 'digraph G {' . PHP_EOL;
echo ' node [shape=record, fontname=Calibri, fontsize=11]' . PHP_EOL;
//echo ' edge [arrowhead=crow,arrowtail=dot]' . PHP_EOL;
foreach ($nodes as $node => $attributes) {
//echo ' ' . $node . ' [label="{{' . $node . '}|' . implode('|', array_keys($attributes['fields'])) . '}"]' . PHP_EOL;
$table = '<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4">';
$table .= '<TR><TD BGCOLOR="lightgrey" COLSPAN="2">' . $node . '</TD></TR>';
foreach ($attributes['fields'] as $field => $fieldAttributes) {
$table .= '<TR>';
$table .= '<TD ALIGN="left">' . $fieldAttributes['dataType'] . '</TD>';
$table .= '<TD ALIGN="left">' . $field . '</TD>';
$table .= '</TR>';
}
$table .= '</TABLE>';
echo ' ' . $node . ' [shape=none, margin=0, label=<' . $table . '>]';
foreach ($attributes['relations'] as $relation => $relationAttributes) {
echo ' ' . $node . ' -> ' . $relation . ' [label=""';
if ($relationAttributes['type'] == 'optional') {
echo ',style=dashed';
}
echo ']' . PHP_EOL;
}
}
echo '}' . PHP_EOL;
} else { // dump is default
print_r($nodes);
}

Entity-Relationship Diagram

This file is used to describe all entities, their properties and how they relate.

User

A user entity is used to...

Fields

username:The username a user will use to login to his/her account
email:...

Relations

Group:A user can be part of one group.

Group

A group of users can have specific roles in the application.

Fields

name:The group name. This should be...
roles:An list of roles
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment