Simple task for build graphic representation of cake schema based on graphwiz.
For this task need to have installed graphviz in path or use “-tool path/to/graphwiz/dot”
Graphviz youcan dowload from http://www.graphviz.org/Download..php
Live example was generated on well known aplication – Bakery. I also include bakery schema made in designer. For me generated graphviz schema looks more pretty and easier to explore.
Example of schema – bakery application
<?php/**
*
*
* PHP versions 4 and 5
*
* Copyright (c) Tomenko Yevgeny
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
*/uses(‘Folder’,‘File’,‘model’.DS.‘connection_manager’ );class VisualizeShell extends Shell { var $DOC_DIR ;
var $PREFIX;
var $graphToolPath = ‘dot.exe’;
// cake visualize -tool C:\dev\_tools_\graphviz-2.16\bin\dot.exe
function help() {
$this->out(‘CakePHP visualise:’);
$this->out(“cake visualise [-tool graphVizTool]”);
$this->hr();
} function initialize() {
$this->DOC_DIR = APP . “doc”;
$this->PREFIX= “img_”;
if (isset($this->params[‘tool’])) {
$this->graphToolPath =$this->params[‘tool’];
}
return true;
}
function main() {
$this->help();
$this->doVisualize();
}
function getSchemaInfo($modelName,$table_name) {
$attrs = array();
if (App::import(‘model’,$modelName)) {
$model = & new $modelName();
$attrs=$model->schema();
return $attrs;
} else {
$DynamicModel = new Model(array(‘name’=> $modelName, ‘table’=> $table_name));
$attrs=$DynamicModel->schema();
return $attrs;
}
return false;
}
function doVisualize() {
$header=$this->PREFIX+strftime(‘%Y-%m-%d %H:%M:%S’,time());
$version=0;
if ($version > 0) {
$header .= “\\nSchema version $version”;
}
$tableInfos = array();
foreach($this->getAllTables() as $table_name) {
$this->out(“Looking at table: {$table_name}”);
$modelName=$this->_modelName($table_name);
$tableInfos[$modelName] = $this->getSchemaInfo($modelName,$table_name);
} if (!file_exists($this->DOC_DIR) || !is_dir($this->DOC_DIR)) {
$this->out(“Creating directory \”{$this->DOC_DIR}\”…”);
$folder = & new Folder($this->DOC_DIR, true);
}
$this->writeDotFile($header, $this->DOC_DIR, $tableInfos);
} function getAllTables($useDbConfig = ‘default’) {
$db =& ConnectionManager::getDataSource($useDbConfig);
$usePrefix = empty($db->config[‘prefix’]) ? ” : $db->config[‘prefix’];
if ($usePrefix) {
$tables = array();
foreach ($db->listSources() as $table) {
if (!strncmp($table, $usePrefix, strlen($usePrefix))) {
$tables[] = substr($table, strlen($usePrefix));
}
}
} else {
$tables = $db->listSources();
}
$this->__tables = $tables;
return $tables;
} function writeDotFile($header, $target_dir, $tableInfos) {
$tmp_dot_file = $target_dir .DS. “model_information.dot”; $f = & new File($tmp_dot_file, true );
// Define a graph and some global settings
$f->append(“digraph G {\n”);
$f->append(“\toverlap=false;\n”);
$f->append(“\tsplines=true;\n”);
$f->append(“\tnode [fontname=\”Helvetica\”,fontsize=9];\n”);
$f->append(“\tedge [fontname=\”Helvetica\”,fontsize=8];\n”);
$f->append(“\tranksep=0.1;\n”);
$f->append(“\tnodesep=0.1;\n”);
// $f->append(“\tedge [decorate=\”true\”];\n”); // Write header info
$f->append(“\t_schema_info [shape=\”plaintext\”, label=\”{$header}\”, fontname=\”Helvetica\”,fontsize=8];\n”);
$assocs = array();
// Draw the tables as boxes
foreach ($tableInfos as $table=>$attributes) {
$attrs = “”;
if (is_array($attributes) && count($attributes)>0) {
foreach ($attributes as $attrname=>$attr) {
if (substr($attrname, –3) == ‘_id’) {
# Create an association to other table
$table_name = Inflector::camelize(r(‘_id’,”,$attrname));
if (!empty($tableInfos[$table_name])) {
$other_table = $tableInfos[$table_name];
$assocs[] = array(‘label’=> $attrname, ‘node1’=> $table, ‘node2’=> $table_name);
}
}
if (!empty($attr[‘length’])) $attr[‘type’].=“[{$attr[‘length’]}]”;
$attrtype=$attr[‘type’];
$attrs .= “{$attrname} : {$attrtype}”;
if (!empty($attr[‘default’])) $attrs .= “, default: \\\”{$attr[‘default’]}\\\””;
$attrs .= “\\n”;
}
}
$f->append(“\t\”{$table}\” [label=\”{{$table}|{$attrs}}\” shape=\”record\”];\n”);
}
// Draw the relations
foreach ($assocs as $assoc) {
$f->append(“\t\”{$assoc[‘node1’]}\” -> \”{$assoc[‘node2’]}\” [label=\”{$assoc[‘label’]}\”]\n”);
}
// Close the graph
$f->append(“}\n”);
$f->close(); // Create the images by using dot and neato (grapviz tools)
// We’ll create several images with different layout. There is no “prefect” layout algorithm that suits all models
$this->createImg($this->graphToolPath, “-Gmode=hier”, $tmp_dot_file, $target_dir .DS. “model_overview_neato_hier”);
$this->createImg($this->graphToolPath, “”, $tmp_dot_file, $target_dir. DS. “model_overview_neato_plain”);
// Remove the .dot file
$f->delete();
}
function createImg($app, $args, $dot_file, $img_file_base) {
$img_file = “$img_file_base.png”;
$command = “{$app} {$args} -Tpng -o\”{$img_file}\” \”{$dot_file}\””;
system($command,$retval);
if (!$retval) {
$this->out(“Generated {$img_file}\n”);
} else {
$this->out(“Failed to execute the ‘{$app}’ command! Is grapviz (www.graphviz.org) installed?\n”);
}
}
}?>
December 14, 2007 at 10:39 am
I managed to change the script to work with my cake app version, but im still getting this error: Failed to execute the ‘C:\[path]\dot.exe’ command!
It is installed, abd at the correct path (that i cut from the error msg above). Is it possible that it cant handle “Program Files” because of the space?
December 16, 2007 at 2:36 pm
sample image! sample image! 😉
December 17, 2007 at 8:57 am