Permalink
Browse files

! Fix for Bug #15019 addCluster using attributes twice

 ! Fix for Bug #15943 Nested subgraphs
 ! Fix for Bug #16872 Rectangles around cluster (BC break fix)


git-svn-id: http://svn.php.net/repository/pear/packages/Image_GraphViz/trunk@291929 c90b9560-bf6c-de11-be94-00142212c4b1
  • Loading branch information...
1 parent 05b74fa commit 08e77964e5afe861cc0e6ae85de5a81e148fa508 Philippe Jausions committed Dec 9, 2009
Showing with 465 additions and 81 deletions.
  1. +200 −46 GraphViz.php
  2. +4 −0 package.xml
  3. +29 −0 tests/bug_15019.phpt
  4. +61 −0 tests/bug_15943.phpt
  5. +62 −0 tests/bug_16872.phpt
  6. +4 −4 tests/test17.phpt
  7. +74 −0 tests/test20b.phpt
  8. +2 −2 tests/test4.phpt
  9. +3 −3 tests/test6.phpt
  10. +26 −26 tests/test9.phpt
View
@@ -142,6 +142,7 @@ class Image_GraphViz
'attributes' => array(),
'directed' => true,
'clusters' => array(),
+ 'subgraphs' => array(),
'name' => 'G',
'strict' => true,
);
@@ -383,17 +384,40 @@ function renderDotFile($dotfile, $outputfile, $format = 'svg',
/**
* Adds a cluster to the graph.
*
+ * A cluster is a subgraph with a rectangle around it.
+ *
* @param string $id ID.
* @param array $title Title.
* @param array $attributes Attributes of the cluster.
+ * @param string $group ID of group to nest cluster into
*
* @return void
* @access public
+ * @see addSubgraph()
*/
- function addCluster($id, $title, $attributes = array())
+ function addCluster($id, $title, $attributes = array(), $group = 'default')
{
$this->graph['clusters'][$id]['title'] = $title;
$this->graph['clusters'][$id]['attributes'] = $attributes;
+ $this->graph['clusters'][$id]['embedIn'] = $group;
+ }
+
+ /**
+ * Adds a subgraph to the graph.
+ *
+ * @param string $id ID.
+ * @param array $title Title.
+ * @param array $attributes Attributes of the cluster.
+ * @param string $group ID of group to nest subgraph into
+ *
+ * @return void
+ * @access public
+ */
+ function addSubgraph($id, $title, $attributes = array(), $group = 'default')
+ {
+ $this->graph['subgraphs'][$id]['title'] = $title;
+ $this->graph['subgraphs'][$id]['attributes'] = $attributes;
+ $this->graph['subgraphs'][$id]['embedIn'] = $group;
}
/**
@@ -665,6 +689,7 @@ function load($file)
'attributes' => array(),
'directed' => true,
'clusters' => array(),
+ 'subgraphs' => array(),
'name' => 'G',
'strict' => true,
);
@@ -721,6 +746,72 @@ function save($file = '')
}
/**
+ * Returns a list of sub-groups for a given parent group
+ *
+ * @param string $parent Group ID
+ *
+ * @return array list of group IDs
+ * @access protected
+ */
+ function _getSubgraphs($parent)
+ {
+ $subgraphs = array();
+ foreach ($this->graph['clusters'] as $id => $info) {
+ if ($info['embedIn'] === $parent) {
+ $subgraphs[] = $id;
+ }
+ }
+ foreach ($this->graph['subgraphs'] as $id => $info) {
+ if ($info['embedIn'] === $parent) {
+ $subgraphs[] = $id;
+ }
+ }
+ return $subgraphs;
+ }
+
+ /**
+ * Returns a list of cluster/subgraph IDs
+ *
+ * @return array
+ * @access protected
+ */
+ function _getGroups()
+ {
+ $groups = array_merge(array_keys($this->graph['clusters']),
+ array_keys($this->graph['subgraphs']));
+ return array_unique($groups);
+ }
+
+ /**
+ * Returns a list of top groups
+ *
+ * @return array
+ * @access protected
+ */
+ function _getTopGraphs()
+ {
+ $top = array();
+ $groups = $this->_getGroups();
+
+ foreach ($groups as $id) {
+ $isTop = ($id === 'default');
+ if (isset($this->graph['clusters'][$id])
+ && $this->graph['clusters'][$id]['embedIn'] === 'default') {
+ $isTop = true;
+ }
+ if (isset($this->graph['subgraphs'][$id])
+ && $this->graph['subgraphs'][$id]['embedIn'] === 'default') {
+ $isTop = true;
+ }
+ if ($isTop) {
+ $top[] = $id;
+ }
+ }
+
+ return array_unique($top);
+ }
+
+ /**
* Parses the graph into GraphViz markup.
*
* @return string GraphViz markup
@@ -740,54 +831,16 @@ function parse()
$parsedGraph .= $indent.$key.'='.$value.";\n";
}
+ $groups = $this->_getGroups();
foreach ($this->graph['nodes'] as $group => $nodes) {
- if ($group != 'default') {
- $parsedGraph .= $indent.'subgraph '.$this->_escape($group)." {\n";
-
- $indent .= ' ';
-
- if (isset($this->graph['clusters'][$group])) {
- $cluster = $this->graph['clusters'][$group];
- $attr = $this->_escapeArray($cluster['attributes']);
-
- foreach ($attr as $key => $value) {
- $attr[] = $key.'='.$value;
- }
-
- if (strlen($cluster['title'])) {
- $attr[] = 'label='
- .$this->_escape($cluster['title'], true);
- }
-
- if ($attr) {
- $parsedGraph .= $indent.'graph [ '.implode(',', $attr)
- ." ];\n";
- }
- }
- }
-
- foreach ($nodes as $node => $attributes) {
- $parsedGraph .= $indent.$this->_escape($node);
-
- $attributeList = array();
-
- foreach ($this->_escapeArray($attributes) as $key => $value) {
- $attributeList[] = $key.'='.$value;
- }
-
- if (!empty($attributeList)) {
- $parsedGraph .= ' [ '.implode(',', $attributeList).' ]';
- }
-
- $parsedGraph .= ";\n";
- }
-
- if ($group != 'default') {
- $indent = substr($indent, 0, -4);
-
- $parsedGraph .= $indent."}\n";
+ if (!in_array($group, $groups)) {
+ $parsedGraph .= $this->_nodes($nodes, $indent);
}
}
+ $tops = $this->_getTopGraphs();
+ foreach ($tops as $group) {
+ $parsedGraph .= $this->_subgraph($group, $indent);
+ }
if (!empty($this->graph['directed'])) {
$separator = ' -> ';
@@ -819,6 +872,14 @@ function parse()
$attributeList = array();
foreach ($this->_escapeArray($info['attributes']) as $key => $value) {
+ switch ($key) {
+ case 'lhead':
+ case 'ltail':
+ if (strncasecmp($value, 'cluster', 7)) {
+ $value = 'cluster_'.$value;
+ }
+ break;
+ }
$attributeList[] = $key.'='.$value;
}
@@ -834,6 +895,99 @@ function parse()
}
/**
+ * Output nodes
+ *
+ * @param array $nodes nodes list
+ * @param string $indent space indentation
+ *
+ * @return string output
+ * @access protected
+ */
+ function _nodes($nodes, $indent)
+ {
+ $parsedGraph = '';
+ foreach ($nodes as $node => $attributes) {
+ $parsedGraph .= $indent.$this->_escape($node);
+
+ $attributeList = array();
+
+ foreach ($this->_escapeArray($attributes) as $key => $value) {
+ $attributeList[] = $key.'='.$value;
+ }
+
+ if (!empty($attributeList)) {
+ $parsedGraph .= ' [ '.implode(',', $attributeList).' ]';
+ }
+
+ $parsedGraph .= ";\n";
+ }
+ return $parsedGraph;
+ }
+
+ /**
+ * Generates output for a group
+ *
+ * @return string output
+ * @access protected
+ */
+ function _subgraph($group, &$indent)
+ {
+ $parsedGraph = '';
+ $nodes = $this->graph['nodes'][$group];
+
+ if ($group !== 'default') {
+ $type = null;
+ $_group = $this->_escape($group);
+
+ if (isset($this->graph['clusters'][$group])) {
+ $type = 'clusters';
+ if (strncasecmp($group, 'cluster', 7)) {
+ $_group = $this->_escape('cluster_'.$group);
+ }
+ } elseif (isset($this->graph['subgraphs'][$group])) {
+ $type = 'subgraphs';
+ }
+ $parsedGraph .= $indent.'subgraph '.$_group." {\n";
+
+ $indent .= ' ';
+
+ if ($type !== null && isset($this->graph[$type][$group])) {
+ $cluster = $this->graph[$type][$group];
+ $_attr = $this->_escapeArray($cluster['attributes']);
+
+ $attr = array();
+ foreach ($_attr as $key => $value) {
+ $attr[] = $key.'='.$value;
+ }
+
+ if (strlen($cluster['title'])) {
+ $attr[] = 'label='
+ .$this->_escape($cluster['title'], true);
+ }
+
+ if ($attr) {
+ $parsedGraph .= $indent.'graph [ '.implode(',', $attr)
+ ." ];\n";
+ }
+ }
+ }
+
+ $parsedGraph .= $this->_nodes($nodes, $indent);
+
+ foreach ($this->_getSubgraphs($group) as $_group) {
+ $parsedGraph .= $this->_subgraph($_group, $indent);
+ }
+
+ if ($group !== 'default') {
+ $indent = substr($indent, 0, -4);
+
+ $parsedGraph .= $indent."}\n";
+ }
+
+ return $parsedGraph;
+ }
+
+ /**
* Saves GraphViz markup to file (in DOT language)
*
* @param string $file File to write the GraphViz markup to.
View
@@ -59,7 +59,11 @@ http://pear.php.net/dtd/package-2.0.xsd">
<file name="test17.phpt" role="test" />
<file name="test19.phpt" role="test" />
<file name="test20.phpt" role="test" />
+ <file name="test20b.phpt" role="test" />
<file name="req_12913.phpt" role="test" />
+ <file name="bug_15019.phpt" role="test" />
+ <file name="bug_15943.phpt" role="test" />
+ <file name="bug_16872.phpt" role="test" />
</dir> <!-- /tests -->
</dir> <!-- / -->
</contents>
View
@@ -0,0 +1,29 @@
+--TEST--
+Bug #15019: addCluster using attributes twice
+--FILE--
+<?php
+
+/**
+ * Bug 15019: "addCluster using attributes twice"
+ *
+ * @category Image
+ * @package Image_GraphViz
+ * @author Philippe Jausions <jausions@php.net>
+ * @link http://pear.php.net/bugs/bug.php?id=15019
+ */
+require_once 'Image/GraphViz.php';
+
+$graph = new Image_GraphViz(true, '', 'Bug', true);
+$graph->addCluster('cluster_0', 'Cluster',
+ array('fontcolor' => 'black', 'style' => 'filled' ));
+$graph->addNode( 'Node', '', 'cluster_0');
+echo $graph->parse();
+
+?>
+--EXPECT--
+strict digraph Bug {
+ subgraph cluster_0 {
+ graph [ fontcolor=black,style=filled,label=Cluster ];
+ "Node" [ 0="" ];
+ }
+}
Oops, something went wrong.

0 comments on commit 08e7796

Please sign in to comment.