Skip to content

Commit

Permalink
Merge pull request #82 from clue/add-extend
Browse files Browse the repository at this point in the history
Support extending Graph, Vertex and Edge
  • Loading branch information
clue committed Jan 1, 2014
2 parents 3ce5097 + 658e92b commit 0fc72f8
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 39 deletions.
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ you spot any mistakes.

## 0.8.0 (2013-xx-xx)

* Feature: The base `Graph`, `Vertex` and `EdgeBase` classes can now be
extended in order to implement a custom behavior. As such, one can now also
instantiate them using the normal `new` operator instead of having to use
`Graph::createVertex()` family of methods.
([#82](https://github.com/clue/graph/issues/82))

* BC break: Rename `Algorithm\Directed::isDirected()` to remove its ambiguity
in regards to mixed and/or empty graphs
([#80](https://github.com/clue/graph/issues/80))
Expand All @@ -14,7 +20,7 @@ you spot any mistakes.
|---|---|
| `Algorithm\Directed::isDirected()` | `Algorithm\Directed::hasDirected()` |

* Feature:: Add new `Algorithm\Directed::hasUndirected()` and
* Feature: Add new `Algorithm\Directed::hasUndirected()` and
`Algorithm\Directed::isMixed()` in order to complement the renamed
`Algorithm\Directed::hasDirected()`
([#80](https://github.com/clue/graph/issues/80))
Expand Down
10 changes: 9 additions & 1 deletion lib/Fhaculty/Graph/Edge/Directed.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class Directed extends Base
private $to;

/**
* creats a new Edge (MUST NOT BE CALLED MANUALLY!)
* create a new directed Edge from Vertex $from to Vertex $to
*
* @param Vertex $from start/source Vertex
* @param Vertex $to end/target Vertex
Expand All @@ -34,8 +34,16 @@ class Directed extends Base
*/
public function __construct(Vertex $from, Vertex $to)
{
if ($from->getGraph() !== $to->getGraph()) {
throw new InvalidArgumentException('Vertices have to be within the same graph');
}

$this->from = $from;
$this->to = $to;

$from->getGraph()->addEdge($this);
$from->addEdge($this);
$to->addEdge($this);
}

public function getVerticesTarget()
Expand Down
10 changes: 9 additions & 1 deletion lib/Fhaculty/Graph/Edge/Undirected.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,24 @@ class Undirected extends Base
private $b;

/**
* create new undirected edge between given vertices (MUST NOT BE CALLED MANUALLY!)
* create a new undirected edge between given vertices
*
* @param Vertex $a
* @param Vertex $b
* @see Vertex::createEdge() instead
*/
public function __construct(Vertex $a, Vertex $b)
{
if ($a->getGraph() !== $b->getGraph()) {
throw new InvalidArgumentException('Vertices have to be within the same graph');
}

$this->a = $a;
$this->b = $b;

$a->getGraph()->addEdge($this);
$a->addEdge($this);
$b->addEdge($this);
}

public function getVerticesTarget()
Expand Down
36 changes: 22 additions & 14 deletions lib/Fhaculty/Graph/Graph.php
Original file line number Diff line number Diff line change
Expand Up @@ -77,19 +77,12 @@ public function createVertex($id = NULL, $returnDuplicate = false)
// no ID given
if ($id === NULL) {
$id = $this->getNextId();
} elseif (!is_int($id) && !is_string($id)) {
throw new InvalidArgumentException('Vertex ID has to be of type integer or string');
}
if ($this->vertices->hasVertexId($id)) {
if ($returnDuplicate) {
return $this->vertices->getVertexId($id);
}
throw new OverflowException('ID must be unique');
if ($returnDuplicate && $this->vertices->hasVertexId($id)) {
return $this->vertices->getVertexId($id);
}
$vertex = new Vertex($id, $this);
$this->verticesStorage[$id] = $vertex;

return $vertex;
return new Vertex($this, $id);
}

/**
Expand All @@ -105,12 +98,11 @@ public function createVertexClone(Vertex $originalVertex)
if ($this->vertices->hasVertexId($id)) {
throw new RuntimeException('Id of cloned vertex already exists');
}
$newVertex = new Vertex($id, $this);
$newVertex = new Vertex($this, $id);
// TODO: properly set attributes of vertex
$newVertex->setLayout($originalVertex->getLayout());
$newVertex->setBalance($originalVertex->getBalance());
$newVertex->setGroup($originalVertex->getGroup());
$this->verticesStorage[$id] = $newVertex;

return $newVertex;
}
Expand Down Expand Up @@ -264,7 +256,7 @@ public function createVertices($n)
$vertices = array();
if (is_int($n) && $n >= 0) {
for ($id = $this->getNextId(), $n += $id; $id < $n; ++$id) {
$vertices[$id] = $this->verticesStorage[$id] = new Vertex($id, $this);
$vertices[$id] = new Vertex($this, $id);
}
} elseif (is_array($n)) {
// array given => check to make sure all given IDs are available (atomic operation)
Expand All @@ -283,7 +275,7 @@ public function createVertices($n)

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

/**
* adds a new Vertex to the Graph (MUST NOT be called manually!)
*
* @param Vertex $vertex instance of the new Vertex
* @return void
* @private
* @see self::createVertex() instead!
*/
public function addVertex(Vertex $vertex)
{
if (isset($this->verticesStorage[$vertex->getId()])) {
throw new OverflowException('ID must be unique');
}
$this->verticesStorage[$vertex->getId()] = $vertex;
}

/**
* adds a new Edge to the Graph (MUST NOT be called manually!)
*
Expand Down
45 changes: 23 additions & 22 deletions lib/Fhaculty/Graph/Vertex.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,16 +43,22 @@ class Vertex extends Layoutable implements EdgesAggregate
private $group = 0;

/**
* Creates a Vertex (MUST NOT BE CALLED MANUALLY!)
* Create a new Vertex
*
* @param string|int $id identifier used to uniquely identify this vertex in the graph
* @param Graph $graph graph to be added to
* @param string|int $id identifier used to uniquely identify this vertex in the graph
* @see Graph::createVertex() to create new vertices
*/
public function __construct($id, Graph $graph)
public function __construct(Graph $graph, $id)
{
if (!is_int($id) && !is_string($id)) {
throw new InvalidArgumentException('Vertex ID has to be of type integer or string');
}

$this->id = $id;
$this->graph = $graph;

$graph->addVertex($this);
}

/**
Expand Down Expand Up @@ -127,16 +133,7 @@ public function getId()
*/
public function createEdgeTo(Vertex $vertex)
{
if ($vertex->getGraph() !== $this->graph) {
throw new InvalidArgumentException('Target vertex has to be within the same graph');
}

$edge = new EdgeDirected($this, $vertex);
$this->edges []= $edge;
$vertex->edges []= $edge;
$this->graph->addEdge($edge);

return $edge;
return new EdgeDirected($this, $vertex);
}

/**
Expand All @@ -149,16 +146,20 @@ public function createEdgeTo(Vertex $vertex)
*/
public function createEdge(Vertex $vertex)
{
if ($vertex->getGraph() !== $this->graph) {
throw new InvalidArgumentException('Target vertex has to be within the same graph');
}

$edge = new EdgeUndirected($this, $vertex);
$this->edges []= $edge;
$vertex->edges []= $edge;
$this->graph->addEdge($edge);
return new EdgeUndirected($this, $vertex);
}

return $edge;
/**
* add the given edge to list of connected edges (MUST NOT be called manually)
*
* @param Edge $edge
* @return void
* @private
* @see self::createEdge() instead!
*/
public function addEdge(Edge $edge)
{
$this->edges[] = $edge;
}

/**
Expand Down
27 changes: 27 additions & 0 deletions tests/Fhaculty/Graph/VertexTest.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?php

use Fhaculty\Graph\Graph;
use Fhaculty\Graph\Vertex;

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

public function testPrecondition()
{
$this->assertCount(1, $this->graph->getVertices());
$this->assertTrue($this->graph->hasVertex(1));
$this->assertFalse($this->graph->hasVertex(2));
$this->assertSame($this->vertex, $this->graph->getVertex(1));
}

public function testConstructor()
{
$v2 = new Vertex($this->graph, 2);

$this->assertCount(2, $this->graph->getVertices());
$this->assertTrue($this->graph->hasVertex(2));

$this->assertSame($v2, $this->graph->getVertex(2));
}

/**
* @expectedException OverflowException
*/
public function testCanNotConstructDuplicateVertex()
{
$v2 = new Vertex($this->graph, 1);
}

public function testEdges()
{
// v1 -> v2, v1 -- v3, v1 <- v4
Expand Down

0 comments on commit 0fc72f8

Please sign in to comment.