DependencyGraph   A
last analyzed

Complexity

Total Complexity 9

Size/Duplication

Total Lines 88
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 9
lcom 1
cbo 1
dl 0
loc 88
ccs 26
cts 26
cp 1
rs 10
c 0
b 0
f 0

3 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A sort() 0 17 4
A visit() 0 21 4
1
<?php
2
namespace PSB\Core\Util\DependencyGraph;
3
4
5
use PSB\Core\Exception\DependencyGraphCycleException;
6
7
class DependencyGraph
8
{
9
    /**
10
     * @var array
11
     */
12
    private $idToNode;
13
14
    /**
15
     * The actual graph maintained as an array of arrays (node id to successor ids).
16
     *
17
     * @var [][]
18
     */
19
    private $idDirectedGraph;
20
21
    /**
22
     * @var array
23
     */
24
    private $nodeMarks = [];
25
26
    /**
27
     * @var array
28
     */
29
    private $nodeTemporaryMarks = [];
30
31
    /**
32
     * @var array
33
     */
34
    private $sortedIdList = [];
35
36
    /**
37
     * @param array $idToNode        The nodes indexed by id.
38
     * @param array $idDirectedGraph The actual graph maintained as an array of arrays (node id to successor ids).
39
     */
40 19
    public function __construct(array $idToNode, array $idDirectedGraph)
41
    {
42 19
        $this->idToNode = $idToNode;
43 19
        $this->idDirectedGraph = $idDirectedGraph;
44 19
    }
45
46
    /**
47
     * It uses Tarjan's algorithm for topological sorting.
48
     * {@see https://en.wikipedia.org/wiki/Topological_sorting#Tarjan.27s_algorithm}
49
     *
50
     * @return array The sorted id to node list.
51
     */
52 14
    public function sort()
53
    {
54 14
        foreach ($this->idDirectedGraph as $nodeId => $successorIds) {
55 14
            if (!isset($this->nodeMarks[$nodeId])) {
56 14
                $this->visit($nodeId);
57
            }
58
        }
59
60 13
        $sortedIdList = array_reverse($this->sortedIdList);
61
62 13
        $sortedNodeList = [];
63 13
        foreach ($sortedIdList as $nodeId) {
64 13
            $sortedNodeList[] = $this->idToNode[$nodeId];
65
        }
66
67 13
        return $sortedNodeList;
68
    }
69
70
    /**
71
     * @param string $nodeId
72
     */
73 14
    private function visit($nodeId)
74
    {
75 14
        if (isset($this->nodeTemporaryMarks[$nodeId])) {
76 1
            throw new DependencyGraphCycleException(
77 1
                "Cyclic dependency detected in graph containing node with id '$nodeId'."
78
            );
79
        }
80
81 14
        if (isset($this->nodeMarks[$nodeId])) {
82 3
            return;
83
        }
84
85 14
        $this->nodeTemporaryMarks[$nodeId] = true;
86 14
        foreach ($this->idDirectedGraph[$nodeId] as $successorId) {
87 5
            $this->visit($successorId);
88
        }
89
90 13
        $this->nodeMarks[$nodeId] = true;
91 13
        unset($this->nodeTemporaryMarks[$nodeId]);
92 13
        $this->sortedIdList[] = $nodeId;
93 13
    }
94
}
95