Skip to content

Commit 0727216

Browse files
committed
Add GraphViz renderer.
1 parent fd67e47 commit 0727216

File tree

4 files changed

+179
-0
lines changed

4 files changed

+179
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
3+
declare(strict_types = 1);
4+
5+
namespace spec\drupol\phptree\tests;
6+
7+
use drupol\phptree\Node\ValueNode;
8+
use drupol\phptree\tests\TestGraphViz;
9+
use drupol\phptree\Visitor\BreadthFirstVisitor;
10+
use PhpSpec\ObjectBehavior;
11+
12+
class TestGraphVizSpec extends ObjectBehavior
13+
{
14+
public function it_is_initializable()
15+
{
16+
$visitor = new BreadthFirstVisitor();
17+
18+
$this->beConstructedWith($visitor);
19+
20+
$this->shouldHaveType(TestGraphViz::class);
21+
}
22+
23+
public function it_can_create_a_graph()
24+
{
25+
$this->beConstructedWith(new BreadthFirstVisitor());
26+
27+
$tree = new ValueNode('root', 2);
28+
29+
$nodes = [];
30+
foreach (\range('A', 'F') as $letter) {
31+
$nodes[] = new ValueNode($letter, 2);
32+
}
33+
34+
$tree->add(...$nodes);
35+
36+
$result = <<< EOF
37+
digraph G {
38+
"root" -> "A"
39+
"root" -> "B"
40+
"A" -> "C"
41+
"A" -> "D"
42+
"B" -> "E"
43+
"B" -> "F"
44+
}
45+
EOF;
46+
47+
$this
48+
->render($tree)
49+
->shouldReturn($result . PHP_EOL);
50+
}
51+
}

spec/src/TestGraphViz.php

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
declare(strict_types = 1);
4+
5+
namespace drupol\phptree\tests;
6+
7+
use drupol\phptree\Node\NodeInterface;
8+
use drupol\phptree\Render\GraphViz;
9+
10+
/**
11+
* Class TestGraphViz
12+
*/
13+
class TestGraphViz extends GraphViz
14+
{
15+
/**
16+
* {@inheritdoc}
17+
*/
18+
protected function hash(NodeInterface $node)
19+
{
20+
return $node->getValue();
21+
}
22+
}

src/Render/GraphViz.php

+88
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
<?php
2+
3+
declare(strict_types = 1);
4+
5+
namespace drupol\phptree\Render;
6+
7+
use drupol\phptree\Node\NodeInterface;
8+
use drupol\phptree\Visitor\VisitorInterface;
9+
use Fhaculty\Graph\Graph;
10+
11+
/**
12+
* Class GraphViz
13+
*/
14+
class GraphViz implements RendererInterface
15+
{
16+
/**
17+
* @var \drupol\phptree\Visitor\VisitorInterface
18+
*/
19+
private $visitor;
20+
21+
/**
22+
* @var \Fhaculty\Graph\Graph
23+
*/
24+
private $graph;
25+
26+
/**
27+
* @var array
28+
*/
29+
private $nodes;
30+
31+
/**
32+
* @var \Graphp\GraphViz\GraphViz
33+
*/
34+
private $graphviz;
35+
36+
/**
37+
* GraphViz constructor.
38+
*
39+
* @param \drupol\phptree\Visitor\VisitorInterface $visitor
40+
*/
41+
public function __construct(VisitorInterface $visitor)
42+
{
43+
$this->visitor = $visitor;
44+
$this->graph = new Graph();
45+
$this->graphviz = new \Graphp\GraphViz\GraphViz();
46+
$this->nodes = [];
47+
}
48+
49+
/**
50+
* @param \drupol\phptree\Node\NodeInterface $node
51+
*
52+
* @return string
53+
*/
54+
public function render(NodeInterface $node): string
55+
{
56+
foreach ($this->visitor->traverse($node) as $child) {
57+
$hash_parent = $this->hash($child);
58+
59+
if (!isset($this->nodes[$hash_parent])) {
60+
$this->nodes[$hash_parent] = $this->graph->createVertex($hash_parent);
61+
}
62+
63+
if (null === $parent = $child->getParent()) {
64+
continue;
65+
}
66+
67+
$hash = $this->hash($parent);
68+
69+
if (!isset($this->nodes[$hash])) {
70+
$this->nodes[$hash] = $this->graph->createVertex($hash);
71+
}
72+
73+
$this->nodes[$hash]->createEdgeTo($this->nodes[$hash_parent]);
74+
}
75+
76+
return $this->graphviz->createScript($this->graph);
77+
}
78+
79+
/**
80+
* @param \drupol\phptree\Node\NodeInterface $node
81+
*
82+
* @return int
83+
*/
84+
protected function hash(NodeInterface $node)
85+
{
86+
return (int) \spl_object_hash($node);
87+
}
88+
}

src/Render/RendererInterface.php

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
declare(strict_types = 1);
4+
5+
namespace drupol\phptree\Render;
6+
7+
use drupol\phptree\Node\NodeInterface;
8+
9+
/**
10+
* Interface RendererInterface
11+
*/
12+
interface RendererInterface
13+
{
14+
/**
15+
* @param \drupol\phptree\Node\NodeInterface $node
16+
*/
17+
public function render(NodeInterface $node);
18+
}

0 commit comments

Comments
 (0)