| [ Index ] |
PHP Cross Reference of MantisBT |
[Summary view] [Print] [Text view]
1 <?php 2 # MantisBT - A PHP based bugtracking system 3 4 # MantisBT is free software: you can redistribute it and/or modify 5 # it under the terms of the GNU General Public License as published by 6 # the Free Software Foundation, either version 2 of the License, or 7 # (at your option) any later version. 8 # 9 # MantisBT is distributed in the hope that it will be useful, 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 # GNU General Public License for more details. 13 # 14 # You should have received a copy of the GNU General Public License 15 # along with MantisBT. If not, see <http://www.gnu.org/licenses/>. 16 17 /** 18 * GraphViz API 19 * 20 * Wrapper classes around GraphViz utilities (dot and neato) for 21 * directed and undirected graph generation. These wrappers are enhanced 22 * enough just to support relationship_graph_api.php. They don't 23 * support subgraphs yet. 24 * 25 * The original Graphviz package is available at: 26 * - http://www.graphviz.org/ 27 * Additional documentation can be found at: 28 * - http://www.graphviz.org/Documentation.html 29 * 30 * @package CoreAPI 31 * @subpackage GraphVizAPI 32 * @author Juliano Ravasi Ferraz <jferraz at users sourceforge net> 33 * @copyright Copyright (C) 2002 - 2011 MantisBT Team - mantisbt-dev@lists.sourceforge.net 34 * @link http://www.mantisbt.org 35 * 36 * @uses constant_inc.php 37 * @uses utility_api.php 38 */ 39 40 require_api( 'constant_inc.php' ); 41 require_api( 'utility_api.php' ); 42 43 /** 44 * constant(s) defining the output formats supported by dot and neato. 45 */ 46 define( 'GRAPHVIZ_ATTRIBUTED_DOT', 0 ); 47 define( 'GRAPHVIZ_PS', 1 ); 48 define( 'GRAPHVIZ_HPGL', 2 ); 49 define( 'GRAPHVIZ_PCL', 3 ); 50 define( 'GRAPHVIZ_MIF', 4 ); 51 define( 'GRAPHVIZ_PLAIN', 6 ); 52 define( 'GRAPHVIZ_PLAIN_EXT', 7 ); 53 define( 'GRAPHVIZ_GIF', 11 ); 54 define( 'GRAPHVIZ_JPEG', 12 ); 55 define( 'GRAPHVIZ_PNG', 13 ); 56 define( 'GRAPHVIZ_WBMP', 14 ); 57 define( 'GRAPHVIZ_XBM', 15 ); 58 define( 'GRAPHVIZ_ISMAP', 16 ); 59 define( 'GRAPHVIZ_IMAP', 17 ); 60 define( 'GRAPHVIZ_CMAP', 18 ); 61 define( 'GRAPHVIZ_CMAPX', 19 ); 62 define( 'GRAPHVIZ_VRML', 20 ); 63 define( 'GRAPHVIZ_SVG', 25 ); 64 define( 'GRAPHVIZ_SVGZ', 26 ); 65 define( 'GRAPHVIZ_CANONICAL_DOT', 27 ); 66 define( 'GRAPHVIZ_PDF', 28 ); 67 68 /** 69 * Base class for graph creation and manipulation. By default, 70 * undirected graphs are generated. For directed graphs, use Digraph 71 * class. 72 * @package MantisBT 73 * @subpackage classes 74 */ 75 class Graph { 76 var $name = 'G'; 77 var $attributes = array(); 78 var $default_node = null; 79 var $default_edge = null; 80 var $nodes = array(); 81 var $edges = array(); 82 83 var $graphviz_tool; 84 var $graphviz_com_module; 85 86 var $formats = array( 87 'dot' => array( 88 'binary' => false, 89 'type' => GRAPHVIZ_ATTRIBUTED_DOT, 90 'mime' => 'text/x-graphviz', 91 ), 92 'ps' => array( 93 'binary' => false, 94 'type' => GRAPHVIZ_PS, 95 'mime' => 'application/postscript', 96 ), 97 'hpgl' => array( 98 'binary' => true, 99 'type' => GRAPHVIZ_HPGL, 100 'mime' => 'application/vnd.hp-HPGL', 101 ), 102 'pcl' => array( 103 'binary' => true, 104 'type' => GRAPHVIZ_PCL, 105 'mime' => 'application/vnd.hp-PCL', 106 ), 107 'mif' => array( 108 'binary' => true, 109 'type' => GRAPHVIZ_MIF, 110 'mime' => 'application/vnd.mif', 111 ), 112 'gif' => array( 113 'binary' => true, 114 'type' => GRAPHVIZ_GIF, 115 'mime' => 'image/gif', 116 ), 117 'jpg' => array( 118 'binary' => false, 119 'type' => GRAPHVIZ_JPEG, 120 'mime' => 'image/jpeg', 121 ), 122 'jpeg' => array( 123 'binary' => true, 124 'type' => GRAPHVIZ_JPEG, 125 'mime' => 'image/jpeg', 126 ), 127 'png' => array( 128 'binary' => true, 129 'type' => GRAPHVIZ_PNG, 130 'mime' => 'image/png', 131 ), 132 'wbmp' => array( 133 'binary' => true, 134 'type' => GRAPHVIZ_WBMP, 135 'mime' => 'image/vnd.wap.wbmp', 136 ), 137 'xbm' => array( 138 'binary' => false, 139 'type' => GRAPHVIZ_XBM, 140 'mime' => 'image/x-xbitmap', 141 ), 142 'ismap' => array( 143 'binary' => false, 144 'type' => GRAPHVIZ_ISMAP, 145 'mime' => 'text/plain', 146 ), 147 'imap' => array( 148 'binary' => false, 149 'type' => GRAPHVIZ_IMAP, 150 'mime' => 'application/x-httpd-imap', 151 ), 152 'cmap' => array( 153 'binary' => false, 154 'type' => GRAPHVIZ_CMAP, 155 'mime' => 'text/html', 156 ), 157 'cmapx' => array( 158 'binary' => false, 159 'type' => GRAPHVIZ_CMAPX, 160 'mime' => 'application/xhtml+xml', 161 ), 162 'vrml' => array( 163 'binary' => true, 164 'type' => GRAPHVIZ_VRML, 165 'mime' => 'x-world/x-vrml', 166 ), 167 'svg' => array( 168 'binary' => false, 169 'type' => GRAPHVIZ_SVG, 170 'mime' => 'image/svg+xml', 171 ), 172 'svgz' => array( 173 'binary' => true, 174 'type' => GRAPHVIZ_SVGZ, 175 'mime' => 'image/svg+xml', 176 ), 177 'pdf' => array( 178 'binary' => true, 179 'type' => GRAPHVIZ_PDF, 180 'mime' => 'application/pdf', 181 ), 182 ); 183 184 /** 185 * Constructor for Graph objects. 186 * @param string $p_name 187 * @param array $p_attributes 188 * @param string $p_tool 189 * @param string $p_com_module 190 * @return null 191 */ 192 function Graph( $p_name = 'G', $p_attributes = array(), $p_tool = 'neato', $p_com_module = 'WinGraphviz.NEATO' ) { 193 if( is_string( $p_name ) ) { 194 $this->name = $p_name; 195 } 196 197 $this->set_attributes( $p_attributes ); 198 199 $this->graphviz_tool = $p_tool; 200 $this->graphviz_com_module = $p_com_module; 201 } 202 203 /** 204 * Sets graph attributes. 205 * @param array $p_attributes 206 * @return null 207 */ 208 function set_attributes( $p_attributes ) { 209 if( is_array( $p_attributes ) ) { 210 $this->attributes = $p_attributes; 211 } 212 } 213 214 /** 215 * Sets default attributes for all nodes of the graph. 216 * @param array $p_attributes 217 * @return null 218 */ 219 function set_default_node_attr( $p_attributes ) { 220 if( is_array( $p_attributes ) ) { 221 $this->default_node = $p_attributes; 222 } 223 } 224 225 /** 226 * Sets default attributes for all edges of the graph. 227 * @param array $p_attributes 228 * @return null 229 */ 230 function set_default_edge_attr( $p_attributes ) { 231 if( is_array( $p_attributes ) ) { 232 $this->default_edge = $p_attributes; 233 } 234 } 235 236 /** 237 * Adds a node to the graph. 238 * @param string $p_name 239 * @param array $p_attributes 240 * @return null 241 */ 242 function add_node( $p_name, $p_attributes = array() ) { 243 if( is_array( $p_attributes ) ) { 244 $this->nodes[$p_name] = $p_attributes; 245 } 246 } 247 248 /** 249 * Adds an edge to the graph. 250 * @param string $p_src 251 * @param string $p_dst 252 * @param array $p_attributes 253 * @return null 254 */ 255 function add_edge( $p_src, $p_dst, $p_attributes = array() ) { 256 if( is_array( $p_attributes ) ) { 257 $this->edges[] = array( 258 'src' => $p_src, 259 'dst' => $p_dst, 260 'attributes' => $p_attributes, 261 ); 262 } 263 } 264 265 /** 266 * Check if an edge is already present. 267 * @param string $p_src 268 * @param string $p_dst 269 * @return bool 270 */ 271 function is_edge_present( $p_src, $p_dst ) { 272 foreach( $this->edges as $t_edge ) { 273 if( $t_edge['src'] == $p_src && $t_edge['dst'] == $p_dst ) { 274 return true; 275 } 276 } 277 return false; 278 } 279 280 /** 281 * Generates an undirected graph representation (suitable for neato). 282 * @return null 283 */ 284 function generate() { 285 echo 'graph ' . $this->name . ' {' . "\n"; 286 287 $this->_print_graph_defaults(); 288 289 foreach( $this->nodes as $t_name => $t_attr ) { 290 $t_name = '"' . addcslashes( $t_name, "\0..\37\"\\" ) . '"'; 291 $t_attr = $this->_build_attribute_list( $t_attr ); 292 echo "\t" . $t_name . ' ' . $t_attr . ";\n"; 293 } 294 295 foreach( $this->edges as $t_edge ) { 296 $t_src = '"' . addcslashes( $t_edge['src'], "\0..\37\"\\" ) . '"'; 297 $t_dst = '"' . addcslashes( $t_edge['dst'], "\0..\37\"\\" ) . '"'; 298 $t_attr = $t_edge['attributes']; 299 $t_attr = $this->_build_attribute_list( $t_attr ); 300 echo "\t" . $t_src . ' -- ' . $t_dst . ' ' . $t_attr . ";\n"; 301 } 302 303 echo "};\n"; 304 } 305 306 /** 307 * Outputs a graph image or map in the specified format. 308 * @param string $p_format 309 * @param bool $p_headers 310 * @return null 311 */ 312 function output( $p_format = 'dot', $p_headers = false ) { 313 # Check if it is a recognized format. 314 if( !isset( $this->formats[$p_format] ) ) { 315 trigger_error( ERROR_GENERIC, ERROR ); 316 } 317 318 $t_binary = $this->formats[$p_format]['binary']; 319 $t_type = $this->formats[$p_format]['type']; 320 $t_mime = $this->formats[$p_format]['mime']; 321 322 # Send Content-Type header, if requested. 323 if( $p_headers ) { 324 header( 'Content-Type: ' . $t_mime ); 325 } 326 # Retrieve the source dot document into a buffer 327 ob_start(); 328 $this->generate(); 329 $t_dot_source = ob_get_contents(); 330 ob_end_clean(); 331 332 # Start dot process 333 334 $t_command = $this->graphviz_tool . ' -T' . $p_format; 335 $t_descriptors = array( 336 0 => array( 'pipe', 'r', ), 337 1 => array( 'pipe', 'w', ), 338 2 => array( 'file', 'php://stderr', 'w', ), 339 ); 340 341 $t_pipes = array(); 342 $t_proccess = proc_open( $t_command, $t_descriptors, $t_pipes ); 343 344 if( is_resource( $t_proccess ) ) { 345 # Filter generated output through dot 346 fwrite( $t_pipes[0], $t_dot_source ); 347 fclose( $t_pipes[0] ); 348 349 if( $p_headers ) { 350 # Headers were requested, use another output buffer to 351 # retrieve the size for Content-Length. 352 ob_start(); 353 while( !feof( $t_pipes[1] ) ) { 354 echo fgets( $t_pipes[1], 1024 ); 355 } 356 header( 'Content-Length: ' . ob_get_length() ); 357 ob_end_flush(); 358 } else { 359 # No need for headers, send output directly. 360 while( !feof( $t_pipes[1] ) ) { 361 print( fgets( $t_pipes[1], 1024 ) ); 362 } 363 } 364 365 fclose( $t_pipes[1] ); 366 proc_close( $t_proccess ); 367 } 368 } 369 370 /** 371 * PROTECTED function to build a node or edge attribute list. 372 * @param array $p_attributes 373 * @return string 374 */ 375 function _build_attribute_list( $p_attributes ) { 376 if( empty( $p_attributes ) ) { 377 return ''; 378 } 379 380 $t_result = array(); 381 382 foreach( $p_attributes as $t_name => $t_value ) { 383 if( !preg_match( "/[a-zA-Z]+/", $t_name ) ) { 384 continue; 385 } 386 387 if( is_string( $t_value ) ) { 388 $t_value = '"' . addcslashes( $t_value, "\0..\37\"\\" ) . '"'; 389 } 390 else if( is_integer( $t_value ) or is_float( $t_value ) ) { 391 $t_value = (string) $t_value; 392 } else { 393 continue; 394 } 395 396 $t_result[] = $t_name . '=' . $t_value; 397 } 398 399 return '[ ' . join( ', ', $t_result ) . ' ]'; 400 } 401 402 /** 403 * PROTECTED function to print graph attributes and defaults. 404 * @return null 405 */ 406 function _print_graph_defaults() { 407 foreach( $this->attributes as $t_name => $t_value ) { 408 if( !preg_match( "/[a-zA-Z]+/", $t_name ) ) { 409 continue; 410 } 411 412 if( is_string( $t_value ) ) { 413 $t_value = '"' . addcslashes( $t_value, "\0..\37\"\\" ) . '"'; 414 } 415 else if( is_integer( $t_value ) or is_float( $t_value ) ) { 416 $t_value = (string) $t_value; 417 } else { 418 continue; 419 } 420 421 echo "\t" . $t_name . '=' . $t_value . ";\n"; 422 } 423 424 if( null !== $this->default_node ) { 425 $t_attr = $this->_build_attribute_list( $this->default_node ); 426 echo "\t" . 'node ' . $t_attr . ";\n"; 427 } 428 429 if( null !== $this->default_edge ) { 430 $t_attr = $this->_build_attribute_list( $this->default_edge ); 431 echo "\t" . 'edge ' . $t_attr . ";\n"; 432 } 433 } 434 } 435 436 /** 437 * Directed graph creation and manipulation. 438 * @package MantisBT 439 * @subpackage classes 440 */ 441 class Digraph extends Graph { 442 /** 443 * Constructor for Digraph objects. 444 * @param string $p_name 445 * @param array $p_attributes 446 * @param string $p_tool 447 * @param string $p_com_module 448 * @return null 449 */ 450 function Digraph( $p_name = 'G', $p_attributes = array(), $p_tool = 'dot', $p_com_module = 'WinGraphviz.DOT' ) { 451 parent::Graph( $p_name, $p_attributes, $p_tool, $p_com_module ); 452 } 453 454 /** 455 * Generates a directed graph representation (suitable for dot). 456 */ 457 function generate() { 458 echo 'digraph ' . $this->name . ' {' . "\n"; 459 460 $this->_print_graph_defaults(); 461 462 foreach( $this->nodes as $t_name => $t_attr ) { 463 $t_name = '"' . addcslashes( $t_name, "\0..\37\"\\" ) . '"'; 464 $t_attr = $this->_build_attribute_list( $t_attr ); 465 echo "\t" . $t_name . ' ' . $t_attr . ";\n"; 466 } 467 468 foreach( $this->edges as $t_edge ) { 469 $t_src = '"' . addcslashes( $t_edge['src'], "\0..\37\"\\" ) . '"'; 470 $t_dst = '"' . addcslashes( $t_edge['dst'], "\0..\37\"\\" ) . '"'; 471 $t_attr = $t_edge['attributes']; 472 $t_attr = $this->_build_attribute_list( $t_attr ); 473 echo "\t" . $t_src . ' -> ' . $t_dst . ' ' . $t_attr . ";\n"; 474 } 475 476 echo "};\n"; 477 } 478 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Thu Jul 28 15:48:31 2011 | Cross-referenced by PHPXref 0.7 |