Flourish PHP Unframework
This is an archived copy of the forum for reference purposes

fSchema visualization (NOT A PROBLEM)

posted by mblarsen 9 years ago

I wrote this piece of code to visualize the database schema as a UML diagram using http:://yuml.me/

It doesn't produce 100% correct UML, but it is close enough for myself. Please leave feedback if you make improvements.

<?php
	// example usage http://127.0.0.1/schema_to_yuml.php?style=boring&direction=right&scale=80

        $db     = .. setup your database ..;
	$schema = new fSchema($db);
	
	$direction_options = array(
		'left' => 'LR',
		'right' => 'RL',
		'top' => 'TB');
		
	$style_options = array(
		'scruffy' => 'scruffy', 
		'boring'  => 'nofunky', 
		'plain'   => 'plain');
	
	$style 	   = fRequest::getValid('style', array_keys($style_options));
	$direction = fRequest::getValid('direction', array_keys($direction_options));
	$scale	   = fRequest::get('scale', 'integer', 100);
		
	$yuml_url  = 'http://yuml.me/diagram/' . $style_options[$style] . ';dir:' . $direction_options[$direction] . ';scale:' . $scale . '/class/';
	$yuml_code = '';
	
	$tables = $schema->getTables();
	
	$relationship_syntax = array(
		'one-to-one'   => '1<-->1',
		'many-to-one'  => '*--<>',
		'one-to-many'  => '<>--*',
		'many-to-many' => '*--*',
		);
	$relations_to_skip = array('many-to-one');
	
	$tables_to_skip = array();
	
        // Skip join tables
	foreach ($tables as $table) {
		$many_to_many_relationships = $schema->getRelationships($table, 'many-to-many');
		foreach ($many_to_many_relationships as $relationship) {
			$tables_to_skip[] = $relationship['join_table'];
		}
	}

	// Build classes and their properties
	foreach ($tables as $table) {
		if (in_array($table, $tables_to_skip)) { continue; }
		$yuml_code .= '[' . fGrammar::camelize(fGrammar::singularize($table), TRUE);
		$columns = array_keys($schema->getColumnInfo($table));
		$yuml_code .= '|' . implode(';', array_map('fGrammar::camelize', $columns, array(FALSE)));
		$yuml_code .= '], ';
	}
	
	$relationship_history = array(); // this ensures that reverse relation ships are not represented twice;
	
	foreach ($tables as $table) {
		if (in_array($table, $tables_to_skip)) { continue; }
		$relationship_types = $schema->getRelationships($table);
		foreach ($relationship_types as $relationship_type => $relationships) {
			if (is_array($relationships) && count($relationships) > 0 && !in_array($relationship_type, $relations_to_skip)) {
				$syntax = $relationship_syntax[$relationship_type];
				foreach ($relationships as $relationship) {
					$related_table = $relationship['related_table'];
					$relationship_key = $relationship_type . (strcmp($table, $related_table) < 1 ? $table . $related_table : $related_table . $table);
					if (in_array($relationship_key, $relationship_history) === FALSE) {
						$yuml_code .= '[' . fGrammar::camelize(fGrammar::singularize($table), TRUE)                         . ']';
						$yuml_code .= $syntax;
						$yuml_code .= '[' . fGrammar::camelize(fGrammar::singularize($related_table), TRUE) . ']';
						$yuml_code .= ', ';	
						$relationship_history[] = $relationship_key;					
					}
				}
			}
		}
	}
	
	$yuml_code = fUTF8::sub($yuml_code, 0, -2);			
	
	echo '<pre>' . $yuml_url . $yuml_code . '</pre>';
	
	echo '<img src="' . $yuml_url . $yuml_code . '" />';

Here is the second version. Can hide attributes. And it is possible to define a subset of tables to view. Attributes of related classes are left out.

Example usage:

http://127.0.0.1/schema_to_yuml.php?direction=right&style=plain&table[]=offerings&table[]=shops&table[]=products&attributes=0
<?php

	
	$schema = new fSchema($db);
	
	$direction_options = array(
		'left'  => 'LR',
		'right' => 'RL',
		'top'   => 'TB');
		
	$style_options = array(
		'scruffy' => 'scruffy', 
		'boring'  => 'nofunky', 
		'plain'   => 'plain');
	
	$style 	    = fRequest::getValid('style', array_keys($style_options));
	$direction  = fRequest::getValid('direction', array_keys($direction_options));
	$scale	    = fRequest::get('scale', 'integer', 100);
	$attributes = fRequest::get('attributes', 'boolean', TRUE);
	$tables     = fRequest::get('table', 'array', array());

		
	$yuml_url  = 'http://yuml.me/diagram/' . $style_options[$style] . ';dir:' . $direction_options[$direction] . ';scale:' . $scale . '/class/';
	$yuml_code = '';
	
	$did_select_tables = FALSE;
	
	if (empty($tables)) {
		$tables = $schema->getTables();	
	} else {
		$did_select_tables = TRUE;
		$yuml_code .= '[note: partial diagram.{bg:cornsilk}]';
	}
	
	$relationship_syntax = array(
		'one-to-one'   => '1<-->1',
		'many-to-one'  => '*--<>',
		'one-to-many'  => '<>--*',
		'many-to-many' => '*--*',
		);
	
	$tables_to_skip = array();
	
	foreach ($tables as $table) {
		$many_to_many_relationships = $schema->getRelationships($table, 'many-to-many');
		foreach ($many_to_many_relationships as $relationship) {
			$tables_to_skip[] = $relationship['join_table'];
		}
	}
	
	foreach ($tables as $table) {
		if (in_array($table, $tables_to_skip)) { continue; }
		
		$yuml_code .= '[' . fGrammar::camelize(fGrammar::singularize($table), TRUE);
		
		$columns = array_keys($schema->getColumnInfo($table));
		if ($attributes === TRUE) {
			$yuml_code .= '|' . implode(';', array_map('fGrammar::camelize', $columns, array(FALSE)));
		}
		if ($did_select_tables) {
			$yuml_code .= '{bg:green}';
		}
		$yuml_code .= '], ';
	}
	
	$relationship_history = array();
	
	foreach ($tables as $table) {
		if (in_array($table, $tables_to_skip)) { continue; }
		$relationship_types = $schema->getRelationships($table);
		foreach ($relationship_types as $relationship_type => $relationships) {
			if (is_array($relationships) && count($relationships) > 0) {
				$syntax = $relationship_syntax[$relationship_type];
				foreach ($relationships as $relationship) {
					$related_table = $relationship['related_table'];
					$relationship_key = ($relationship_type === 'many-to-one' ? 'one-to-many' : $relationship_type) . (strcmp($table, $related_table) < 1 ? $table . $related_table : $related_table . $table);
					if (in_array($relationship_key, $relationship_history) === FALSE) {
						$yuml_code .= '[' . fGrammar::camelize(fGrammar::singularize($table), TRUE)                         . ']';
						$yuml_code .= $syntax;
						$yuml_code .= '[' . fGrammar::camelize(fGrammar::singularize($related_table), TRUE) . ']';
						$yuml_code .= ', ';	
						$relationship_history[] = $relationship_key;					
					}
				}
			}
		}
	}
	
	$yuml_code = fUTF8::sub($yuml_code, 0, -2);			
	
	echo '<pre>' . $yuml_url . $yuml_code . '</pre>';
	
	echo '<img src="' . $yuml_url . $yuml_code . '" />';
posted by mblarsen 9 years ago

This is awesome!

posted by jeffturcotte 9 years ago