pastebin - collaborative debugging

pastebin is a collaborative debugging tool allowing you to share and modify code snippets while chatting on IRC, IM or a message board.

This site is developed to XHTML and CSS2 W3C standards. If you see this paragraph, your browser does not support those standards and you need to upgrade. Visit WaSP for a variety of options.

PHP pastebin - collaborative debugging tool View Help


Posted by ruxkor on Wed 17 Dec 16:10 (modification of post by ruxkor view diff)
report abuse | download | new post

  1. <?php
  2. /**
  3.  * Visualize console task
  4.  *
  5.  * This task can be used to generate a graphical representation of your tables or models.
  6.  *
  7.  * PHP versions 4 and 5
  8.  *
  9.  * Copyright (c) Tomenko Yevgeny
  10.  *
  11.  * Licensed under The MIT License
  12.  * Redistributions of files must retain the above copyright notice.
  13.  *
  14.  * @version             1.2.0
  15.  * @modifiedby          Andy Dawson
  16.  * @lastmodified        2007-12-20 23:39:02 +0100 (Thu, 16 Aug 2007) $
  17.  * @license             http://www.opensource.org/licenses/mit-license.php The MIT License
  18.  */
  19. uses('Folder','File','model'.DS.'connection_manager');
  20. class VisualizeShell extends Shell {
  21.  
  22.         var $DOC_DIR ;
  23.  
  24.         var $PREFIX = APP_DIR;
  25.  
  26.         var $graphToolPath = 'dot.exe'; // cake visualize -tool C:\dev\_tools_\graphviz-2.16\bin\dot.exe
  27.  
  28.  
  29.         function help() {
  30.                 $this->out('CakePHP visualise, Usage examples:');
  31.                 $this->out('cake visualize help');
  32.                 $this->out('    - this text');
  33.                 $this->out('cake visualize tables');
  34.                 $this->out('    - generate graphic based on table structure');
  35.                 $this->out('cake visualize models');
  36.                 $this->out('    - generate graphic based on model association definitions');
  37.                 $this->out('cake visualise [-tool graphVizTool]');
  38.                 $this->hr();
  39.         }
  40.  
  41.         function initialize() {
  42.                 if (DS == '/') {
  43.                         $this->graphToolPath = array(
  44.                                 'dot',
  45.                                 'dot -Gmode=heir',
  46.                                 'neato',
  47.                                 'neato -Gmodel=subset'
  48.                         );
  49.                 }
  50.                 $this->DOC_DIR = APP . 'config' . DS . 'sql';
  51.                 $this->PREFIX= 'img_';
  52.                 if (isset($this->params['tool'])) {
  53.                         $this->graphToolPath = $this->params['tool'];
  54.                 }
  55.                 return true;
  56.         }
  57.  
  58.         function main() {
  59.                 if (!isset($this->args[0])) {
  60.                         $this->args[0] = 'filtered';
  61.                 }
  62.                 if ($this->args[0] == 'help') {
  63.                         $this->help();
  64.                         return;
  65.                 } elseif ($this->args[0] == 'tables') {
  66.                         $mode = 't';
  67.                         $this->generateDataFromTables();    
  68.                 } elseif ($this->args[0] == 'models') {
  69.                         $mode = 'm';
  70.                         $this->generateDataFromModels();    
  71.                 } elseif ($this->args[0] == 'combined') {
  72.                         $mode = 'combined';
  73.                         $this->generateDataFromTables();
  74.                         $this->generateDataFromModels();
  75.                 } elseif ($this->args[0] == 'filtered') {
  76.                         $mode = 'filtered';
  77.                         $this->generateDataFromTables();
  78.                         $this->generateDataFromModels();
  79.                         $this->filterPotentialDuplicates();
  80.                 }
  81.                
  82.                 $this->writeDotFile($this->DOC_DIR, $mode);
  83.         }
  84.  
  85.         function generateDataFromModels() {
  86.                 foreach($this->getAllModels() as $model) {
  87.                         $this->out("Looking at model: {$model}");
  88.                         $model = new $model();
  89.                         if (!$model->useTable) {
  90.                                 continue;
  91.                         }
  92.                         $this->data['tables'][$model->name] = $model->schema(true);
  93.                         foreach ($this->data['tables'][$model->name] as $attrname => $attr) {
  94.                                 if (!empty($attr['length'])) {
  95.                                         $attr['type'] .= "[{$attr['length']}]";
  96.                                 }
  97.                                 $this->data['nodes'][$model->name][$attrname] = $attr['type'];
  98.                                 if (!empty($attr['default'])) {
  99.                                         $this->data['nodes'][$model->name][$attrname] .= ", default: \\\"{$attr['default']}\\\"";
  100.                                 }
  101.                         }
  102.                         foreach($model->__associations as $type) {
  103.                                 foreach ($model->$type as $alias => $association) {
  104.                                         $otherModel = $association['className'];
  105.                                         if ($type == 'belongsTo') {
  106.                                                 $this->data['associations'][$model->name.$otherModel] =
  107.                                                         array(
  108.                                                                 'label'=> $model->name . '->' . $alias,
  109.                                                                 'node1'=> $model->name,
  110.                                                                 'node2'=> $otherModel,
  111.                                                                 'foreignKey' => $association['foreignKey'],
  112.                                                                 'assType'=>'n:1'
  113.                                                         );
  114.                                         } elseif (in_array($type, array('hasOne', 'hasMany'))) {
  115.                                                 $this->data['associations'][$otherModel.$model->name] =
  116.                                                         array(
  117.                                                                 'label'=> $otherModel . '->' . $model->name,
  118.                                                                 'node1'=> $otherModel,
  119.                                                                 'node2'=> $model->name,
  120.                                                                 'foreignKey' => $association['foreignKey'],
  121.                                                                 'assType'=>($type=='hasOne')?'1:1':'n:1'
  122.                                                         );
  123.                                         } elseif ($type == 'hasAndBelongsToMany') {
  124.                                                 $names[] = $model->name;
  125.                                                 $names[] = $otherModel;
  126.                                                 sort($names);
  127.                                                 $modelName = implode($names, '');
  128.                                                 if (!isset($modelName)) {
  129.                                                         $DynamicModel = new Model(array('name'=> $modelName, 'table'=> $association['joinTable']));
  130.                                                         $this->data['tables'][$modelName] = $DynamicModel->schema(true);
  131.                                                         foreach ($this->data['tables'][$modelName] as $attrname => $attr) {
  132.                                                                 if (!empty($attr['length'])) {
  133.                                                                         $attr['type'] .= "[{$attr['length']}]";
  134.                                                                 }
  135.                                                                 $this->data['nodes'][$modelName][$attrname] = $attr['type'];
  136.                                                                 $attrtype = $attr['type'];
  137.                                                                 if (!empty($attr['default'])) {
  138.                                                                         $this->data['nodes'][$modelName][$attrname] .= ", default: \\\"{$attr['default']}\\\"";
  139.                                                                 }
  140.                                                         }
  141.                                                         $this->data['associations'][$model->name.$otherModel] =
  142.                                                                 array(
  143.                                                                         'label'=> $model->name . '->' . $modelName,
  144.                                                                         'node1'=> $model->name,
  145.                                                                         'node2'=> $modelName,
  146.                                                                         'foreignKey' => $association['foreignKey'],
  147.                                                                         'assType'=>'1:n'
  148.                                                                 );
  149.                                                         $this->data['associations'][$otherModel.$model->name] =
  150.                                                                 array(
  151.                                                                         'label'=> $otherModel . '->' . $modelName,
  152.                                                                         'node1'=> $otherModel,
  153.                                                                         'node2'=> $modelName,
  154.                                                                         'foreignKey' => $association['foreignKey'],
  155.                                                                         'assType'=>'1:n'
  156.                                                                 );
  157.                                                 }
  158.                                         }
  159.                                 }
  160.                         }
  161.                 }
  162.         }
  163.  
  164.         function generateDataFromTables() {
  165.                 foreach($this->getAllTables() as $table_name) {
  166.                         $this->out("Looking at table: {$table_name}");
  167.                         $modelName=$this->_modelName($table_name);
  168.                         $this->data['tables'][$modelName] = $this->getSchemaInfo($modelName,$table_name);
  169.                 }
  170.                 foreach ($this->data['tables'] as $table => $attributes) {
  171.                         if (is_array($attributes) && count($attributes)>0) {
  172.                                 foreach ($attributes as $attrname => $attr) {
  173.                                         if (substr($attrname, -3) == '_id') {
  174.                                                 # Create an association to other table
  175.                                                 $otherTable = Inflector::camelize(r('_id','',$attrname));
  176.                                                 if (!empty($this->data['tables'][$otherTable])) {
  177.                                                         $other_table = $this->data['tables'][$otherTable];
  178.                                                         $this->data['associations'][] = array('label'=> $attrname, 'node1'=> $table, 'node2'=> $otherTable);
  179.                                                 }
  180.                                         }
  181.                                         if (!empty($attr['length'])) {
  182.                                                 $attr['type'] .= "[{$attr['length']}]";
  183.                                         }
  184.                                         $this->data['nodes'][$table][$attrname] = $attr['type'];
  185.                                         $attrtype = $attr['type'];
  186.                                         if (!empty($attr['default'])) {
  187.                                                 $this->data['nodes'][$table][$attrname] .= ", default: \\\"{$attr['default']}\\\"";
  188.                                         }
  189.                                 }
  190.                         }
  191.                 }
  192.         }
  193.  
  194.         function getAllModels() {
  195.                 $Inflector =& Inflector::getInstance();
  196.                 uses('Folder');
  197.                 $folder = new Folder(MODELS);
  198.                 $models = $folder->findRecursive('.*php');
  199.                 $folder = new Folder(BEHAVIORS);
  200.                 $behaviors = $folder->findRecursive('.*php');
  201.                 $models = array_diff($models, $behaviors);
  202.                 foreach ($models as $id => $model) {
  203.                         $file = new File($model);
  204.                         $models[$id] = $file->name();
  205.                 }
  206.                 $models = array_map(array(&$Inflector, 'camelize'), $models);
  207.                 App::import('Model', $models);
  208.                 return $models;
  209.         }
  210.  
  211.         function getAllTables($useDbConfig = 'default') {
  212.                 $db =& ConnectionManager::getDataSource($useDbConfig);
  213.                 $usePrefix = empty($db->config['prefix']) ? '': $db->config['prefix'];
  214.                 if ($usePrefix) {
  215.                         $tables = array();
  216.                         foreach ($db->listSources() as $table) {
  217.                                 if (!strncmp($table, $usePrefix, strlen($usePrefix))) {
  218.                                         $tables[] = substr($table, strlen($usePrefix));
  219.                                 }
  220.                         }
  221.                 } else {
  222.                         $tables = $db->listSources();
  223.                 }
  224.                 $this->__tables = $tables;
  225.                 return $tables;
  226.         }
  227.  
  228.         function getSchemaInfo($modelName,$table_name) {
  229.                 $attrs = array();
  230.                 if (App::import('model',$modelName)) {
  231.                         $model = & new $modelName();
  232.                         $attrs=$model->schema();
  233.                         return $attrs;
  234.                 } else {
  235.                         $DynamicModel = new Model(array('name'=> $modelName, 'table'=> $table_name));
  236.                         $attrs=$DynamicModel->schema();
  237.                         return $attrs;
  238.                 }
  239.                 return false;
  240.         }  
  241.  
  242.         function writeDotFile($target_dir, $mode) {
  243.                 if (!file_exists($target_dir) || !is_dir($target_dir)) {
  244.                         $this->out("Creating directory \"{$target_dir}\"&#65533;");
  245.                         $folder = & new Folder($target_dir, true);
  246.                 }
  247.                 $header = $this->PREFIX+strftime('%Y-%m-%d %H:%M:%S',time());
  248.                 $version=0;
  249.                 if ($version > 0) {
  250.                         $header .= "\\nSchema version $version";
  251.                 }
  252.                 $dotFile = $target_dir .DS. 'mode_' . $mode . '.dot';
  253.                 if (file_exists($dotFile)) {
  254.                         $f = & new File($dotFile);
  255.                         $f->delete();
  256.                 }
  257.                 $f = & new File($dotFile, true );
  258.  
  259.                 // Define a graph and some global settings
  260.                 $f->append("digraph G {\n");
  261.                 $f->append("\toverlap=false;\n");
  262.                 $f->append("\tsplines=true;\n");
  263.                 $f->append("\tnode [fontname=\"Helvetica\",fontsize=9];\n");
  264.                 $f->append("\tedge [fontname=\"Helvetica\",fontsize=8];\n");
  265.                 $f->append("\tranksep=0.1;\n");
  266.                 $f->append("\tnodesep=0.1;\n");
  267. //              $f->append("\tedge [decorate=\"true\"];\n");
  268.                 // Write header info
  269.                 $f->append("\t_schema_info [shape=\"plaintext\", label=\"{$header}\", fontname=\"Helvetica\",fontsize=8];\n");
  270.  
  271.                 $assocs = array();
  272.                 // Draw the tables as boxes
  273.                
  274.                 foreach ($this->data['nodes'] as $table=>$attributes) {
  275.                         $f->append("\t\"{$table}\" [label=\"{{$table}|");
  276.                         foreach ($attributes as $field=>$label) {
  277.                                 $f->append("{$field} : {$label}\\n");
  278.                         }
  279.                         $f->append("}\" shape=\"record\"];\n");
  280.                 }
  281.                 // Draw the relations
  282.                 foreach ($this->data['associations'] as $assoc) {
  283.                         if (isset($assoc['assType'])) $assoc['label'].= ' ('.$assoc['assType'].')';
  284.                         $f->append("\t\"{$assoc['node1']}\" -> \"{$assoc['node2']}\" [label=\"{$assoc['label']}\"]\n");
  285.                 }
  286.  
  287.                 // Close the graph
  288.                 $f->append("}\n");
  289.                 $f->close();        // Create the images by using dot and neato (grapviz tools)
  290.                 $this->out("Generated {$dotFile}\n");
  291.  
  292.                 $this->createImgs($dotFile, $target_dir, $mode);
  293.  
  294.                 // Remove the .dot file // Keep it for debugging and general info
  295.                 $f->delete();
  296.         }
  297.  
  298.         function createImgs($dotFile, $path, $mode) {
  299.                 if (is_string($this->graphToolPath)) {
  300.                         $commands = array($this->graphToolPath);
  301.                 } else {
  302.                         $commands = $this->graphToolPath;
  303.                 }
  304.                 uses ('Sanitize');
  305.                 foreach ($commands as $command) {
  306.                         $imgFile = $path . DS . 'schematic_' . $mode . '_' . Sanitize::paranoid($command) . ".png";
  307.                         if (file_exists($imgFile)) {
  308.                                 $f = & new File($imgFile);
  309.                                 $f->delete();
  310.                         }
  311.                         if ($this->createImg($command, $dotFile, $imgFile)) {
  312.                                 $this->out("Generated {$imgFile}\n");
  313.                         } else {
  314.                                 break;
  315.                         }
  316.                 }
  317.         }
  318.  
  319.         function createImg($command, $dotFile, $imgFile) {
  320.                 $command = $command.' -v -Tpng -o"'.$imgFile.'" "'.$dotFile.'"';
  321.                 ob_start();
  322.                 system($command,$return);
  323.                 ob_clean();
  324.                 if ($return != 0) {
  325.                         $this->out("Command Error ($return):\n");          
  326.                         $this->out("$command\n");
  327.                         return false;
  328.                 }
  329.                 return true;
  330.         }
  331.         function filterPotentialDuplicates() {
  332.                 $associations =& $this->data['associations'];
  333.                 $duplicates = array();
  334.                 foreach ($associations as $k=>$v) {
  335.                         if (is_numeric($k)) {
  336.                                 foreach ($associations as $ik=>$iv) {
  337.                                         if (
  338.                                                 (!is_numeric($ik)) &&
  339.                                                 ($iv['node1']==$v['node1']) &&
  340.                                                 ($iv['node2']==$v['node2']) &&
  341.                                                 ($iv['foreignKey']==$v['label'])
  342.                                         ) {
  343.                                                  $duplicates[] = $k;
  344.                                         }
  345.                                 }
  346.                         }
  347.                 }
  348.                 foreach ($duplicates as $k) {
  349.                         unset($associations["$k"]);
  350.                 }
  351.         }
  352. }
  353. ?>

Submit a correction or amendment below (click here to make a fresh posting)
After submitting an amendment, you'll be able to view the differences between the old and new posts easily.

Syntax highlighting:

To highlight particular lines, prefix each line with @@


Remember me so that I can delete my post