source: branches/1.2/workflow/inc/engine/src/ProcessManager/GraphViz.php @ 1349

Revision 1349, 14.3 KB checked in by niltonneto, 15 years ago (diff)

Ticket #561 - Inclusão do módulo Workflow faltante nessa versão.

  • Property svn:executable set to *
Line 
1<?php
2//
3// +----------------------------------------------------------------------+
4// | PEAR :: Image :: GraphViz                                            |
5// +----------------------------------------------------------------------+
6// | Copyright (c) 2002 Sebastian Bergmann <sb@sebastian-bergmann.de> and |
7// |                    Dr. Volker Göbbels <vmg@arachnion.de>.            |
8// +----------------------------------------------------------------------+
9// | This source file is subject to version 3.00 of the PHP License,      |
10// | that is available at http://www.php.net/license/3_0.txt.             |
11// | If you did not receive a copy of the PHP license and are unable to   |
12// | obtain it through the world-wide-web, please send a note to          |
13// | license@php.net so we can mail you a copy immediately.               |
14// +----------------------------------------------------------------------+
15//
16//
17
18/**
19* PEAR::Image_GraphViz
20*
21* Purpose
22*
23*     Allows for the creation of and the work with directed
24*     and undirected graphs and their visualization with
25*     AT&T's GraphViz tools. These can be found at
26*     http://www.research.att.com/sw/tools/graphviz/
27*
28* Example
29*
30*     require_once 'Image/GraphViz.php';
31*     $graph = new Image_GraphViz();
32*
33*     $graph->addNode('Node1', array('URL'      => 'http://link1',
34*                                    'label'    => 'This is a label',
35*                                    'shape'    => 'box'
36*                                    )
37*                     );
38*     $graph->addNode('Node2', array('URL'      => 'http://link2',
39*                                    'fontsize' => '14'
40*                                    )
41*                     );
42*     $graph->addNode('Node3', array('URL'      => 'http://link3',
43*                                    'fontsize' => '20'
44*                                    )
45*                     );
46*
47*     $graph->addEdge(array('Node1' => 'Node2'), array('label' => 'Edge Label'));
48*     $graph->addEdge(array('Node1' => 'Node2'), array('color' => 'red'));
49*
50*     $graph->image();
51*
52* @author  Sebastian Bergmann <sb@sebastian-bergmann.de>
53*          Dr. Volker Göbbels <vmg@arachnion.de>
54* @package Galaxia
55*/
56class Process_GraphViz {
57    /**
58    * @var string $dotCommand Path to GraphViz/dot command
59    * @access public
60    */
61    var $dotCommand = 'dot';
62   
63    /**
64    * @var string $pid
65    * @access public
66    */
67    var $pid;
68
69    /**
70    * @var string $neatoCommand Path to GraphViz/dot command
71    * @access public
72    */
73    var $neatoCommand = 'neato';
74
75    /**
76    * @var  array $graph Path to GraphViz/dot command
77    * @access public
78    */
79    var $graph;
80
81    /**
82    * Constructor
83    *
84    * @param  boolean $directed Directed (true) or undirected (false) graph.
85    * @param  array  $attributes Attributes of the graph
86    * @access public
87    */
88    function Process_GraphViz($directed = true, $attributes = array()) {
89        $this->setDirected($directed);
90        $this->setAttributes($attributes);
91        if (defined('GRAPHVIZ_BIN_DIR') && GRAPHVIZ_BIN_DIR) {
92            $this->dotCommand = GRAPHVIZ_BIN_DIR.'/'.$this->dotCommand;
93            $this->neatoCommand = GRAPHVIZ_BIN_DIR.'/'.$this->neatoCommand;
94        }
95    }
96   
97    /**
98    * Set pid
99    *
100    * @param  string $pid pid
101    * @access public
102    * @return void
103    */
104    function set_pid($pid)
105    {
106      $this->pid = $pid;
107    }
108
109    /**
110    * Output image of the graph in a given format.
111    *
112    * @param  string $format Format of the output image. This may be one of the formats supported by GraphViz.
113    * @param  string $file Name of the output file.
114    * @access public
115    * @return string
116    */
117    function image($format = 'png', $file = '') {
118        if ($file = $this->saveParsedGraph($file)) {
119            $outputfile = $file . '.' . $format;
120            $outputfile2 = $file . '.' . 'map';
121            $command  = $this->graph['directed'] ? $this->dotCommand : $this->neatoCommand;
122            $command .= " -T$format -Gcharset=latin1 -o$outputfile $file";
123
124            @`$command`;
125            $command = $this->dotCommand;
126            $command.= " -Tcmap -Gcharset=latin1 -o$outputfile2 $file";
127            @`$command`;
128            $fr = fopen($outputfile2,"r");
129            $map = fread($fr,filesize($outputfile2));
130            fclose($fr);
131            @unlink($file);
132
133            switch ($format) {
134                case 'gif':
135                case 'jpg':
136                case 'png':
137                case 'svg':
138                case 'wbmp': {
139                    header('Content-Type: image/' . $format);
140                }
141                break;
142
143                case 'pdf': {
144                    header('Content-Type: application/pdf');
145                }
146                break;
147            }
148
149            header('Content-Length: ' . filesize($outputfile));
150
151            $fp = fopen($outputfile, 'rb');
152
153            if ($fp) {
154                echo fread($fp, filesize($outputfile));
155                fclose($fp);
156                @unlink($outputfile);
157            }
158            @unlink($outputfile2);
159            return $map;
160        }
161    }
162   
163    /**
164    * Output image of the graph in a given format.
165    *
166    * @param  string $format Format of the output image. This may be one of the formats supported by GraphViz.
167    * @access public
168    * return boolean
169    */
170    function image_and_map($format = 'png') {
171        if ($file = $this->saveParsedGraph()) {
172            $outputfile = $file . '.' . $format;
173            $outputfile2 = $file . '.' . 'map';
174            if(!isset($this->graph['directed'])) $this->graph['directed']=true;
175            $command  = $this->graph['directed'] ? $this->dotCommand : $this->neatoCommand;
176            $command .= " -T$format -Gcharset=latin1 -o $outputfile $file";
177            @`$command`;
178
179            $command = $this->dotCommand;
180            $command.= " -Tcmap -Gcharset=latin1 -o $outputfile2 $file";
181            @`$command`;
182            @unlink($file);
183            return true;
184        }
185    }
186
187    /**
188    * Map the current image
189    *
190    * @access public
191    * return boolean
192    */
193    function map() {
194        if ($file = $this->saveParsedGraph()) {
195           
196            $outputfile2 = $file . '.' . 'map';
197           
198            $command = $this->dotCommand;
199            $command.= " -Tcmap -Gcharset=latin1 -o$outputfile2 $file";
200            @`$command`;
201            $fr = fopen($outputfile2,"r");
202            $map = fread($fr,filesize($outputfile2));
203            fclose($fr);
204           
205            @unlink($outputfile2);
206            @unlink($file);
207            return $map;
208        }
209    }
210
211    /**
212    * Add a cluster to the graph.
213    *
214    * @param  string $id ID.
215    * @param  array  $title Title.
216    * @access public
217    * @return void
218    */
219    function addCluster($id, $title) {
220        $this->graph['clusters'][$id] = $title;
221    }
222
223    /**
224    * Add a node to the graph.
225    *
226    * @param  string $name Name of the node.
227    * @param  array $attributes  Attributes of the node.
228    * @param  string $group Group of the node.
229    * @access public
230    * @return void
231    */
232    function addNode($name, $attributes = array(), $group = 'default') {
233        $this->graph['nodes'][$group][$name] = $attributes;
234    }
235
236    /**
237    * Remove a node from the graph.
238    *
239    * @param  string $name Name of the node to be removed.
240    * @param  string $group Name of the node group to be removed.
241    * @access public
242    * @return void
243    */
244    function removeNode($name, $group = 'default') {
245        if (isset($this->graph['nodes'][$group][$name])) {
246            unset($this->graph['nodes'][$group][$name]);
247        }
248    }
249
250    /**
251    * Add an edge to the graph.
252    *
253    * @param  array $edge Start and End node of the edge.
254    * @param  array $attributes Attributes of the edge.
255    * @access public
256    * @return void
257    */
258    function addEdge($edge, $attributes = array()) {
259        if (is_array($edge)) {
260            $from = key($edge);
261            $to   = $edge[$from];
262            $id   = $from . '_' . $to;
263
264            if (!isset($this->graph['edges'][$id])) {
265                $this->graph['edges'][$id] = $edge;
266            } else {
267                $this->graph['edges'][$id] = array_merge(
268                  $this->graph['edges'][$id],
269                  $edge
270                );
271            }
272
273            if (is_array($attributes)) {
274                if (!isset($this->graph['edgeAttributes'][$id])) {
275                    $this->graph['edgeAttributes'][$id] = $attributes;
276                } else {
277                    $this->graph['edgeAttributes'][$id] = array_merge(
278                      $this->graph['edgeAttributes'][$id],
279                      $attributes
280                    );
281                }
282            }
283        }
284    }
285
286    /**
287    * Remove an edge from the graph.
288    *
289    * @param  array $edge Start and End node of the edge to be removed.
290    * @access public
291    * return void
292    */
293    function removeEdge($edge) {
294        if (is_array($edge)) {
295              $from = key($edge);
296              $to   = $edge[$from];
297              $id   = $from . '_' . $to;
298
299            if (isset($this->graph['edges'][$id])) {
300                unset($this->graph['edges'][$id]);
301            }
302
303            if (isset($this->graph['edgeAttributes'][$id])) {
304                unset($this->graph['edgeAttributes'][$id]);
305            }
306        }
307    }
308
309    /**
310    * Add attributes to the graph.
311    *
312    * @param  array Attributes to be added to the graph.
313    * @access public
314    * @return void
315    *
316    */
317    function addAttributes($attributes) {
318        if (is_array($attributes)) {
319            $this->graph['attributes'] = array_merge(
320              $this->graph['attributes'],
321              $attributes
322            );
323        }
324    }
325
326    /**
327    * Set attributes of the graph.
328    *
329    * @param  array Attributes to be set for the graph.
330    * @access public
331    * @return void
332    */
333    function setAttributes($attributes) {
334        if (is_array($attributes)) {
335            $this->graph['attributes'] = $attributes;
336        }
337    }
338
339    /**
340    * Set directed/undirected flag for the graph.
341    *
342    * @param  boolean Directed (true) or undirected (false) graph.
343    * @access public
344    * @return void
345    */
346    function setDirected($directed) {
347        if (is_bool($directed)) {
348            $this->graph['directed'] = $directed;
349        }
350    }
351
352    /**
353    * Load graph from file.
354    *
355    * @param  string $file File to load graph from.
356    * @access public
357    * @return void
358    */
359    function load($file) {
360        if ($serialized_graph = implode('', @file($file))) {
361            $this->graph = unserialize($serialized_graph);
362        }
363    }
364
365    /**
366    * Save graph to file.
367    *
368    * @param  string  $file File to save the graph to.
369    * @return mixed  File the graph was saved to, false on failure.
370    * @access public
371    */
372    function save($file = '') {
373        $serialized_graph = serialize($this->graph);
374
375        if (empty($file)) {
376            $file = tempnam('temp', 'graph_');
377        }
378
379        if ($fp = @fopen($file, 'w')) {
380            @fputs($fp, $serialized_graph);
381            @fclose($fp);
382
383            return $file;
384        }
385
386        return false;
387    }
388
389    /**
390    * Parse the graph into GraphViz markup.
391    *
392    * @return string  GraphViz markup
393    * @access public
394    */
395    function parse() {
396        $parsedGraph = "digraph G {\n";
397
398        if (isset($this->graph['attributes'])) {
399            foreach ($this->graph['attributes'] as $key => $value) {
400                $attributeList[] = $key . '="' . $value . '"';
401            }
402
403            if (!empty($attributeList)) {
404              $parsedGraph .= implode(',', $attributeList) . ";\n";
405            }
406        }
407
408        if (isset($this->graph['nodes'])) {
409            foreach($this->graph['nodes'] as $group => $nodes) {
410                if ($group != 'default') {
411                  $parsedGraph .= sprintf(
412                    "subgraph \"cluster_%s\" {\nlabel=\"%s\";\n",
413
414                    $group,
415                    isset($this->graph['clusters'][$group]) ? $this->graph['clusters'][$group] : ''
416                  );
417                }
418
419                foreach($nodes as $node => $attributes) {
420                    unset($attributeList);
421
422                    foreach($attributes as $key => $value) {
423                        $attributeList[] = $key . '="' . $value . '"';
424                    }
425
426                    if (!empty($attributeList)) {
427                        $parsedGraph .= sprintf(
428                          "\"%s\" [ %s ];\n",
429                          addslashes(stripslashes($node)),
430                          implode(',', $attributeList)
431                        );
432                    }
433                }
434
435                if ($group != 'default') {
436                  $parsedGraph .= "}\n";
437                }
438            }
439        }
440
441        if (isset($this->graph['edges'])) {
442            foreach($this->graph['edges'] as $label => $node) {
443                unset($attributeList);
444
445                $from = key($node);
446                $to   = $node[$from];
447
448                foreach($this->graph['edgeAttributes'][$label] as $key => $value) {
449                    $attributeList[] = $key . '="' . $value . '"';
450                }
451
452                $parsedGraph .= sprintf(
453                  '"%s" -> "%s"',
454                  addslashes(stripslashes($from)),
455                  addslashes(stripslashes($to))
456                );
457               
458                if (!empty($attributeList)) {
459                    $parsedGraph .= sprintf(
460                      ' [ %s ]',
461                      implode(',', $attributeList)
462                    );
463                }
464
465                $parsedGraph .= ";\n";
466            }
467        }
468
469        return $parsedGraph . "}\n";
470    }
471
472    /**
473    * Save GraphViz markup to file.
474    *
475    * @param  string $file File to write the GraphViz markup to.
476    * @return mixed   File to which the GraphViz markup was
477    *                 written, false on failure.
478    * @access public
479    */
480    function saveParsedGraph($file = '') {
481        $parsedGraph = $this->parse();
482        if (!empty($parsedGraph)) {
483                        if (empty($file))
484                $file = GALAXIA_PROCESSES.'/'.$this->pid.'/graph/'.$this->pid;
485            if ($fp = @fopen($file, 'w')) {
486                @fputs($fp, $parsedGraph);
487                @fclose($fp);
488
489                return $file;
490            }
491        }
492
493        return false;
494    }
495}
496?>
Note: See TracBrowser for help on using the repository browser.