Skip to content

Instantly share code, notes, and snippets.

@coudenysj
Last active August 29, 2015 14:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • 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