Skip to content

Commit 0fc72f8

Browse files
committed
Merge pull request #82 from clue/add-extend
Support extending Graph, Vertex and Edge
2 parents 3ce5097 + 658e92b commit 0fc72f8

6 files changed

Lines changed: 97 additions & 39 deletions

File tree

CHANGELOG.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ you spot any mistakes.
66

77
## 0.8.0 (2013-xx-xx)
88

9+
* Feature: The base `Graph`, `Vertex` and `EdgeBase` classes can now be
10+
extended in order to implement a custom behavior. As such, one can now also
11+
instantiate them using the normal `new` operator instead of having to use
12+
`Graph::createVertex()` family of methods.
13+
([#82](https://github.com/clue/graph/issues/82))
14+
915
* BC break: Rename `Algorithm\Directed::isDirected()` to remove its ambiguity
1016
in regards to mixed and/or empty graphs
1117
([#80](https://github.com/clue/graph/issues/80))
@@ -14,7 +20,7 @@ you spot any mistakes.
1420
|---|---|
1521
| `Algorithm\Directed::isDirected()` | `Algorithm\Directed::hasDirected()` |
1622

17-
* Feature:: Add new `Algorithm\Directed::hasUndirected()` and
23+
* Feature: Add new `Algorithm\Directed::hasUndirected()` and
1824
`Algorithm\Directed::isMixed()` in order to complement the renamed
1925
`Algorithm\Directed::hasDirected()`
2026
([#80](https://github.com/clue/graph/issues/80))

lib/Fhaculty/Graph/Edge/Directed.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class Directed extends Base
2525
private $to;
2626

2727
/**
28-
* creats a new Edge (MUST NOT BE CALLED MANUALLY!)
28+
* create a new directed Edge from Vertex $from to Vertex $to
2929
*
3030
* @param Vertex $from start/source Vertex
3131
* @param Vertex $to end/target Vertex
@@ -34,8 +34,16 @@ class Directed extends Base
3434
*/
3535
public function __construct(Vertex $from, Vertex $to)
3636
{
37+
if ($from->getGraph() !== $to->getGraph()) {
38+
throw new InvalidArgumentException('Vertices have to be within the same graph');
39+
}
40+
3741
$this->from = $from;
3842
$this->to = $to;
43+
44+
$from->getGraph()->addEdge($this);
45+
$from->addEdge($this);
46+
$to->addEdge($this);
3947
}
4048

4149
public function getVerticesTarget()

lib/Fhaculty/Graph/Edge/Undirected.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,24 @@ class Undirected extends Base
2323
private $b;
2424

2525
/**
26-
* create new undirected edge between given vertices (MUST NOT BE CALLED MANUALLY!)
26+
* create a new undirected edge between given vertices
2727
*
2828
* @param Vertex $a
2929
* @param Vertex $b
3030
* @see Vertex::createEdge() instead
3131
*/
3232
public function __construct(Vertex $a, Vertex $b)
3333
{
34+
if ($a->getGraph() !== $b->getGraph()) {
35+
throw new InvalidArgumentException('Vertices have to be within the same graph');
36+
}
37+
3438
$this->a = $a;
3539
$this->b = $b;
40+
41+
$a->getGraph()->addEdge($this);
42+
$a->addEdge($this);
43+
$b->addEdge($this);
3644
}
3745

3846
public function getVerticesTarget()

lib/Fhaculty/Graph/Graph.php

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -77,19 +77,12 @@ public function createVertex($id = NULL, $returnDuplicate = false)
7777
// no ID given
7878
if ($id === NULL) {
7979
$id = $this->getNextId();
80-
} elseif (!is_int($id) && !is_string($id)) {
81-
throw new InvalidArgumentException('Vertex ID has to be of type integer or string');
8280
}
83-
if ($this->vertices->hasVertexId($id)) {
84-
if ($returnDuplicate) {
85-
return $this->vertices->getVertexId($id);
86-
}
87-
throw new OverflowException('ID must be unique');
81+
if ($returnDuplicate && $this->vertices->hasVertexId($id)) {
82+
return $this->vertices->getVertexId($id);
8883
}
89-
$vertex = new Vertex($id, $this);
90-
$this->verticesStorage[$id] = $vertex;
9184

92-
return $vertex;
85+
return new Vertex($this, $id);
9386
}
9487

9588
/**
@@ -105,12 +98,11 @@ public function createVertexClone(Vertex $originalVertex)
10598
if ($this->vertices->hasVertexId($id)) {
10699
throw new RuntimeException('Id of cloned vertex already exists');
107100
}
108-
$newVertex = new Vertex($id, $this);
101+
$newVertex = new Vertex($this, $id);
109102
// TODO: properly set attributes of vertex
110103
$newVertex->setLayout($originalVertex->getLayout());
111104
$newVertex->setBalance($originalVertex->getBalance());
112105
$newVertex->setGroup($originalVertex->getGroup());
113-
$this->verticesStorage[$id] = $newVertex;
114106

115107
return $newVertex;
116108
}
@@ -264,7 +256,7 @@ public function createVertices($n)
264256
$vertices = array();
265257
if (is_int($n) && $n >= 0) {
266258
for ($id = $this->getNextId(), $n += $id; $id < $n; ++$id) {
267-
$vertices[$id] = $this->verticesStorage[$id] = new Vertex($id, $this);
259+
$vertices[$id] = new Vertex($this, $id);
268260
}
269261
} elseif (is_array($n)) {
270262
// array given => check to make sure all given IDs are available (atomic operation)
@@ -283,7 +275,7 @@ public function createVertices($n)
283275

284276
// actually create all requested vertices
285277
foreach ($n as $id) {
286-
$vertices[$id] = $this->verticesStorage[$id] = new Vertex($id, $this);
278+
$vertices[$id] = new Vertex($this, $id);
287279
}
288280
} else {
289281
throw new InvalidArgumentException('Invalid number of vertices given. Must be non-negative integer or an array of Vertex IDs');
@@ -332,6 +324,22 @@ public function hasVertex($id)
332324
return $this->vertices->hasVertexId($id);
333325
}
334326

327+
/**
328+
* adds a new Vertex to the Graph (MUST NOT be called manually!)
329+
*
330+
* @param Vertex $vertex instance of the new Vertex
331+
* @return void
332+
* @private
333+
* @see self::createVertex() instead!
334+
*/
335+
public function addVertex(Vertex $vertex)
336+
{
337+
if (isset($this->verticesStorage[$vertex->getId()])) {
338+
throw new OverflowException('ID must be unique');
339+
}
340+
$this->verticesStorage[$vertex->getId()] = $vertex;
341+
}
342+
335343
/**
336344
* adds a new Edge to the Graph (MUST NOT be called manually!)
337345
*

lib/Fhaculty/Graph/Vertex.php

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -43,16 +43,22 @@ class Vertex extends Layoutable implements EdgesAggregate
4343
private $group = 0;
4444

4545
/**
46-
* Creates a Vertex (MUST NOT BE CALLED MANUALLY!)
46+
* Create a new Vertex
4747
*
48-
* @param string|int $id identifier used to uniquely identify this vertex in the graph
4948
* @param Graph $graph graph to be added to
49+
* @param string|int $id identifier used to uniquely identify this vertex in the graph
5050
* @see Graph::createVertex() to create new vertices
5151
*/
52-
public function __construct($id, Graph $graph)
52+
public function __construct(Graph $graph, $id)
5353
{
54+
if (!is_int($id) && !is_string($id)) {
55+
throw new InvalidArgumentException('Vertex ID has to be of type integer or string');
56+
}
57+
5458
$this->id = $id;
5559
$this->graph = $graph;
60+
61+
$graph->addVertex($this);
5662
}
5763

5864
/**
@@ -127,16 +133,7 @@ public function getId()
127133
*/
128134
public function createEdgeTo(Vertex $vertex)
129135
{
130-
if ($vertex->getGraph() !== $this->graph) {
131-
throw new InvalidArgumentException('Target vertex has to be within the same graph');
132-
}
133-
134-
$edge = new EdgeDirected($this, $vertex);
135-
$this->edges []= $edge;
136-
$vertex->edges []= $edge;
137-
$this->graph->addEdge($edge);
138-
139-
return $edge;
136+
return new EdgeDirected($this, $vertex);
140137
}
141138

142139
/**
@@ -149,16 +146,20 @@ public function createEdgeTo(Vertex $vertex)
149146
*/
150147
public function createEdge(Vertex $vertex)
151148
{
152-
if ($vertex->getGraph() !== $this->graph) {
153-
throw new InvalidArgumentException('Target vertex has to be within the same graph');
154-
}
155-
156-
$edge = new EdgeUndirected($this, $vertex);
157-
$this->edges []= $edge;
158-
$vertex->edges []= $edge;
159-
$this->graph->addEdge($edge);
149+
return new EdgeUndirected($this, $vertex);
150+
}
160151

161-
return $edge;
152+
/**
153+
* add the given edge to list of connected edges (MUST NOT be called manually)
154+
*
155+
* @param Edge $edge
156+
* @return void
157+
* @private
158+
* @see self::createEdge() instead!
159+
*/
160+
public function addEdge(Edge $edge)
161+
{
162+
$this->edges[] = $edge;
162163
}
163164

164165
/**

tests/Fhaculty/Graph/VertexTest.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<?php
22

33
use Fhaculty\Graph\Graph;
4+
use Fhaculty\Graph\Vertex;
45

56
class VertexTest extends TestCase
67
{
@@ -10,6 +11,32 @@ public function setUp()
1011
$this->vertex = $this->graph->createVertex(1);
1112
}
1213

14+
public function testPrecondition()
15+
{
16+
$this->assertCount(1, $this->graph->getVertices());
17+
$this->assertTrue($this->graph->hasVertex(1));
18+
$this->assertFalse($this->graph->hasVertex(2));
19+
$this->assertSame($this->vertex, $this->graph->getVertex(1));
20+
}
21+
22+
public function testConstructor()
23+
{
24+
$v2 = new Vertex($this->graph, 2);
25+
26+
$this->assertCount(2, $this->graph->getVertices());
27+
$this->assertTrue($this->graph->hasVertex(2));
28+
29+
$this->assertSame($v2, $this->graph->getVertex(2));
30+
}
31+
32+
/**
33+
* @expectedException OverflowException
34+
*/
35+
public function testCanNotConstructDuplicateVertex()
36+
{
37+
$v2 = new Vertex($this->graph, 1);
38+
}
39+
1340
public function testEdges()
1441
{
1542
// v1 -> v2, v1 -- v3, v1 <- v4

0 commit comments

Comments
 (0)