1 | <?php |
||||||
2 | |||||||
3 | namespace Graphp\Graph; |
||||||
4 | |||||||
5 | use InvalidArgumentException; |
||||||
6 | use Graphp\GraphInterface; |
||||||
7 | use Graphp\Graph\Specifics\SpecificsInterface; |
||||||
8 | use Graphp\Graph\Specifics\UndirectedSpecifics; |
||||||
9 | use Graphp\Graph\Specifics\DirectedSpecifics; |
||||||
10 | use Graphp\Edge\EdgeInterface; |
||||||
11 | use Graphp\Edge\EdgeSet; |
||||||
12 | use Graphp\Edge\Specifics\EdgeSpecificsInterface; |
||||||
13 | use Graphp\Edge\Specifics\UniformEdgeSpecifics; |
||||||
14 | use Graphp\Edge\Specifics\WeightedEdgeSpecifics; |
||||||
15 | use Graphp\Vertex\VertexInterface; |
||||||
16 | use Graphp\Vertex\VertexSet; |
||||||
17 | use Graphp\Util\SupplierInterface; |
||||||
18 | |||||||
19 | /** |
||||||
20 | * Class AbstractGraph |
||||||
21 | * |
||||||
22 | * @package Graphp\Graph |
||||||
23 | */ |
||||||
24 | class AbstractGraph implements GraphInterface |
||||||
25 | { |
||||||
26 | /** |
||||||
27 | * The vertex supplier |
||||||
28 | * |
||||||
29 | * @var SupplierInterface |
||||||
30 | */ |
||||||
31 | private $vertexSupplier; |
||||||
32 | |||||||
33 | /** |
||||||
34 | * The edge supplier |
||||||
35 | * |
||||||
36 | * @var SupplierInterface |
||||||
37 | */ |
||||||
38 | private $edgeSupplier; |
||||||
39 | |||||||
40 | /** |
||||||
41 | * The graph type |
||||||
42 | * |
||||||
43 | * @var GraphTypeInterface |
||||||
44 | */ |
||||||
45 | private $type; |
||||||
46 | |||||||
47 | /** |
||||||
48 | * The graph specifics |
||||||
49 | * |
||||||
50 | * @var SpecificsInterface |
||||||
51 | */ |
||||||
52 | private $specifics; |
||||||
53 | |||||||
54 | /** |
||||||
55 | * The edge specifics |
||||||
56 | * |
||||||
57 | * @var EdgeSpecificsInterface |
||||||
58 | */ |
||||||
59 | private $edgeSpecifics; |
||||||
60 | |||||||
61 | /** |
||||||
62 | * Construct a new graph |
||||||
63 | * |
||||||
64 | * @param SupplierInterface $vertexSupplier - the vertex supplier |
||||||
65 | * @param SupplierInterface $edgeSupplier - the edge supplier |
||||||
66 | * @param GraphTypeInterface $type - the graph type |
||||||
67 | */ |
||||||
68 | 41 | protected function __construct( |
|||||
69 | ?SupplierInterface $vertexSupplier = null, |
||||||
70 | ?SupplierInterface $edgeSupplier = null, |
||||||
71 | ?GraphTypeInterface $type = null |
||||||
72 | ) { |
||||||
73 | 41 | $this->vertexSupplier = $vertexSupplier; |
|||||
74 | 41 | $this->edgeSupplier = $edgeSupplier; |
|||||
75 | 41 | $this->type = $type; |
|||||
76 | 41 | $this->specifics = $this->createSpecifics($type->isDirected()); |
|||||
0 ignored issues
–
show
|
|||||||
77 | 41 | $this->edgeSpecifics = $this->createEdgeSpecifics($type->isWeighted()); |
|||||
78 | 41 | } |
|||||
79 | |||||||
80 | /** |
||||||
81 | * Get the graph specifics |
||||||
82 | * |
||||||
83 | * @param bool $isDirected - is directed graph? |
||||||
84 | * |
||||||
85 | * @return SpecificsInterface |
||||||
86 | */ |
||||||
87 | 41 | public function createSpecifics(bool $isDirected): SpecificsInterface |
|||||
88 | { |
||||||
89 | 41 | return $isDirected ? new DirectedSpecifics($this) : new UndirectedSpecifics($this); |
|||||
90 | } |
||||||
91 | |||||||
92 | /** |
||||||
93 | * Get the edge specifics |
||||||
94 | * |
||||||
95 | * @param bool $isWeighted - is weighted? |
||||||
96 | * |
||||||
97 | * @return EdgeSpecificsInterface |
||||||
98 | */ |
||||||
99 | 41 | public function createEdgeSpecifics(bool $isWeighted): EdgeSpecificsInterface |
|||||
100 | { |
||||||
101 | 41 | return $isWeighted ? new WeightedEdgeSpecifics($this) : new UniformEdgeSpecifics($this); |
|||||
0 ignored issues
–
show
The call to
Graphp\Edge\Specifics\We...pecifics::__construct() has too many arguments starting with $this .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above. ![]() The call to
Graphp\Edge\Specifics\Un...pecifics::__construct() has too many arguments starting with $this .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above. ![]() |
|||||||
102 | } |
||||||
103 | |||||||
104 | /** |
||||||
105 | * Get all edges connecting the source vertext to the target vertex |
||||||
106 | * |
||||||
107 | * @return EdgeSet |
||||||
108 | */ |
||||||
109 | 1 | public function getAllEdges(VertexInterface $sourceVertex, VertexInterface $targetVertex): EdgeSet |
|||||
110 | { |
||||||
111 | 1 | return $this->specifics->getAllEdges($sourceVertex, $targetVertex); |
|||||
112 | } |
||||||
113 | |||||||
114 | /** |
||||||
115 | * Get an edge connecting the source vertext to the target vertex |
||||||
116 | * |
||||||
117 | * @return null|EdgeInterface |
||||||
118 | */ |
||||||
119 | 24 | public function getEdge(VertexInterface $sourceVertex, VertexInterface $targetVertex): ?EdgeInterface |
|||||
120 | { |
||||||
121 | 24 | return $this->specifics->getEdge($sourceVertex, $targetVertex); |
|||||
122 | } |
||||||
123 | |||||||
124 | /** |
||||||
125 | * Get the vertex supplier that the graph uses whenever it needs to create new vertices |
||||||
126 | * |
||||||
127 | * @return null|SupplierInterface |
||||||
128 | */ |
||||||
129 | 2 | public function getVertexSupplier(): ?SupplierInterface |
|||||
130 | { |
||||||
131 | 2 | return $this->vertexSupplier; |
|||||
132 | } |
||||||
133 | |||||||
134 | /** |
||||||
135 | * Get the edge supplier that the graph uses whenever it needs to create new edges |
||||||
136 | * |
||||||
137 | * @return SupplierInterface |
||||||
138 | */ |
||||||
139 | 10 | public function getEdgeSupplier(): SupplierInterface |
|||||
140 | { |
||||||
141 | 10 | return $this->edgeSupplier; |
|||||
142 | } |
||||||
143 | |||||||
144 | /** |
||||||
145 | * Get the graph type |
||||||
146 | * |
||||||
147 | * @return GraphTypeInterface |
||||||
148 | */ |
||||||
149 | 32 | public function getType(): GraphTypeInterface |
|||||
150 | { |
||||||
151 | 32 | return $this->type; |
|||||
152 | } |
||||||
153 | |||||||
154 | /** |
||||||
155 | * Create a new edge in the graph. Return the newly created edge if added to the graph. |
||||||
156 | * |
||||||
157 | * @return EdgeInterface |
||||||
158 | * |
||||||
159 | * @throws InvalidArgumentException |
||||||
160 | */ |
||||||
161 | 29 | public function addEdge( |
|||||
162 | VertexInterface $sourceVertex, |
||||||
163 | VertexInterface $targetVertex, |
||||||
164 | ?EdgeInterface $edge = null |
||||||
165 | ): ?EdgeInterface { |
||||||
166 | 29 | $this->assertVertexExists($sourceVertex); |
|||||
167 | 29 | $this->assertVertexExists($targetVertex); |
|||||
168 | |||||||
169 | 29 | if (!$this->getType()->isAllowingMultipleEdges() && $this->containsEdge($sourceVertex, $targetVertex)) { |
|||||
170 | 2 | return null; |
|||||
171 | } |
||||||
172 | |||||||
173 | 29 | if (!$this->getType()->isAllowingSelfLoops() && $sourceVertex->equals($targetVertex)) { |
|||||
174 | throw new InvalidArgumentException("loops are not allowed"); |
||||||
175 | } |
||||||
176 | |||||||
177 | 29 | $targetEdge = $edge ?? $this->edgeSupplier->get(); |
|||||
178 | |||||||
179 | 29 | if ($this->edgeSpecifics->add($targetEdge, $sourceVertex, $targetVertex)) { |
|||||
180 | 29 | $this->specifics->addEdgeToTouchingVertices($targetEdge); |
|||||
181 | 29 | return $targetEdge; |
|||||
182 | } |
||||||
183 | |||||||
184 | return null; |
||||||
185 | } |
||||||
186 | |||||||
187 | /** |
||||||
188 | * Create and return a new vertex in the graph. |
||||||
189 | * |
||||||
190 | * @return null|VertexInterface |
||||||
191 | */ |
||||||
192 | 36 | public function addVertex(VertexInterface $vertex): ?VertexInterface |
|||||
193 | { |
||||||
194 | 36 | if (!$this->containsVertex($vertex)) { |
|||||
195 | 36 | $this->specifics->addVertex($vertex); |
|||||
196 | 36 | return $vertex; |
|||||
197 | } |
||||||
198 | |||||||
199 | 5 | return null; |
|||||
200 | } |
||||||
201 | |||||||
202 | /** |
||||||
203 | * Check if the graph contains the given edge, specified either by two vertices or by the edge itself |
||||||
204 | * |
||||||
205 | * @param VertexInterface $sourceVertex - the source vertex |
||||||
206 | * @param VertexInterface $targetVertex - the target vertex |
||||||
207 | * @param EdgeInterface $edge - the edge |
||||||
208 | * |
||||||
209 | * @return bool |
||||||
210 | */ |
||||||
211 | 23 | public function containsEdge( |
|||||
212 | ?VertexInterface $sourceVertex = null, |
||||||
213 | ?VertexInterface $targetVertex = null, |
||||||
214 | ?EdgeInterface $edge = null |
||||||
215 | ): bool { |
||||||
216 | 23 | if (!is_null($sourceVertex) && !is_null($targetVertex)) { |
|||||
217 | 23 | return !is_null($this->getEdge($sourceVertex, $targetVertex)); |
|||||
218 | } |
||||||
219 | 2 | return !is_null($edge) ? $this->edgeSpecifics->containsEdge($edge) : false; |
|||||
220 | } |
||||||
221 | |||||||
222 | /** |
||||||
223 | * Check if the graph contains the given vertex |
||||||
224 | * |
||||||
225 | * @return bool |
||||||
226 | */ |
||||||
227 | 36 | public function containsVertex(VertexInterface $vertex): bool |
|||||
228 | { |
||||||
229 | 36 | return $this->specifics->getVertexSet()->contains($vertex); |
|||||
230 | } |
||||||
231 | |||||||
232 | /** |
||||||
233 | * Get a set of all edges touching the specified vertex |
||||||
234 | * |
||||||
235 | * @param VertexInterface - the vertex |
||||||
0 ignored issues
–
show
|
|||||||
236 | * |
||||||
237 | * @return EdgeSet |
||||||
238 | */ |
||||||
239 | 7 | public function edgesOf(VertexInterface $vertex): EdgeSet |
|||||
240 | { |
||||||
241 | 7 | $this->assertVertexExists($vertex); |
|||||
242 | 7 | return $this->specifics->edgesOf($vertex); |
|||||
243 | } |
||||||
244 | |||||||
245 | /** |
||||||
246 | * Get a set of all edges incoming into the specified vertex |
||||||
247 | * |
||||||
248 | * @param VertexInterface $vertex - the vertex |
||||||
249 | * |
||||||
250 | * @return EdgeSet |
||||||
251 | */ |
||||||
252 | 3 | public function incomingEdgesOf(VertexInterface $vertex): EdgeSet |
|||||
253 | { |
||||||
254 | 3 | $this->assertVertexExists($vertex); |
|||||
255 | 3 | return $this->specifics->incomingEdgesOf($vertex); |
|||||
256 | } |
||||||
257 | |||||||
258 | /** |
||||||
259 | * Get a set of all edges outgoing from the specified vertex |
||||||
260 | * |
||||||
261 | * @param VertexInterface $vertex - the vertex |
||||||
262 | * |
||||||
263 | * @return EdgeSet |
||||||
264 | */ |
||||||
265 | 9 | public function outgoingEdgesOf(VertexInterface $vertex): EdgeSet |
|||||
266 | { |
||||||
267 | 9 | $this->assertVertexExists($vertex); |
|||||
268 | 9 | return $this->specifics->outgoingEdgesOf($vertex); |
|||||
269 | } |
||||||
270 | |||||||
271 | /** |
||||||
272 | * Remove all edges specified by two vertices or the the list of edges themselves. |
||||||
273 | * Return true, if graph was changed |
||||||
274 | * |
||||||
275 | * @param VertexInterface $vertex - the source vertex |
||||||
276 | * @param VertexInterface $vertex - the target vertex |
||||||
277 | * @param EdgeSet $edges - the edges |
||||||
278 | * |
||||||
279 | * @return bool |
||||||
280 | */ |
||||||
281 | 4 | public function removeAllEdges( |
|||||
282 | ?VertexInterface $sourceVertex = null, |
||||||
283 | ?VertexInterface $targetVertex = null, |
||||||
284 | ?EdgeSet $edges = null |
||||||
285 | ): bool { |
||||||
286 | 4 | $changed = false; |
|||||
287 | 4 | if (!is_null($sourceVertex) && !is_null($targetVertex)) { |
|||||
288 | 1 | $edge = $this->getEdge($sourceVertex, $targetVertex); |
|||||
289 | 1 | if (!is_null($edge)) { |
|||||
290 | 1 | $this->specifics->removeEdgeFromTouchingVertices($edge); |
|||||
291 | 1 | $this->edgeSpecifics->remove($edge); |
|||||
292 | 1 | return true; |
|||||
293 | } |
||||||
294 | } else { |
||||||
295 | 3 | foreach ($edges as $edge) { |
|||||
296 | 1 | if ($this->containsEdge(null, null, $edge)) { |
|||||
297 | 1 | $this->specifics->removeEdgeFromTouchingVertices($edge); |
|||||
298 | 1 | $this->edgeSpecifics->remove($edge); |
|||||
299 | 1 | $changed = true; |
|||||
300 | } |
||||||
301 | } |
||||||
302 | } |
||||||
303 | 3 | return $changed; |
|||||
304 | } |
||||||
305 | |||||||
306 | /** |
||||||
307 | * Remove all specified vertices contained in the graph. |
||||||
308 | * Return true, if graph was changed |
||||||
309 | * |
||||||
310 | * @param VertexSet $vertices - the vertices |
||||||
311 | * |
||||||
312 | * @return bool |
||||||
313 | */ |
||||||
314 | 1 | public function removeAllVertices(VertexSet $vertices): bool |
|||||
315 | { |
||||||
316 | 1 | $changed = false; |
|||||
317 | 1 | foreach ($vertices as $vertex) { |
|||||
318 | 1 | $changed = $this->removeVertex($vertex); |
|||||
319 | } |
||||||
320 | 1 | return $changed; |
|||||
321 | } |
||||||
322 | |||||||
323 | /** |
||||||
324 | * Remove the specifeid edge from the graph. |
||||||
325 | * Return the edge, if it was removed |
||||||
326 | * |
||||||
327 | * @param VertexInterface $sourceVertex - the source vertex |
||||||
328 | * @param VertexInterface $targetVertex - the target vertex |
||||||
329 | * @param EdgeInterface $edge - the edge |
||||||
330 | * |
||||||
331 | * @return null|EdgeInterface |
||||||
332 | */ |
||||||
333 | 2 | public function removeEdge( |
|||||
334 | ?VertexInterface $sourceVertex = null, |
||||||
335 | ?VertexInterface $targetVertex = null, |
||||||
336 | ?EdgeInterface $edge = null |
||||||
337 | ): ?EdgeInterface { |
||||||
338 | 2 | if (!is_null($sourceVertex) && !is_null($targetVertex)) { |
|||||
339 | 2 | $edge = $this->getEdge($sourceVertex, $targetVertex); |
|||||
340 | 2 | if (!is_null($edge)) { |
|||||
341 | 2 | $this->specifics->removeEdgeFromTouchingVertices($edge); |
|||||
342 | 2 | $this->edgeSpecifics->remove($edge); |
|||||
343 | 2 | return $edge; |
|||||
344 | } |
||||||
345 | 1 | } elseif (!is_null($edge)) { |
|||||
346 | 1 | $this->specifics->removeEdgeFromTouchingVertices($edge); |
|||||
347 | 1 | $this->edgeSpecifics->remove($edge); |
|||||
348 | 1 | return $edge; |
|||||
349 | } |
||||||
350 | return null; |
||||||
351 | } |
||||||
352 | |||||||
353 | /** |
||||||
354 | * Remove the specifeid vertex from the graph. |
||||||
355 | * Return the true, if it was removed |
||||||
356 | * |
||||||
357 | * @param VertexInterface $vertex - the vertex |
||||||
358 | * |
||||||
359 | * @return bool |
||||||
360 | */ |
||||||
361 | 3 | public function removeVertex(VertexInterface $vertex): bool |
|||||
362 | { |
||||||
363 | 3 | if ($this->containsVertex($vertex)) { |
|||||
364 | 3 | $edges = $this->edgesOf($vertex); |
|||||
365 | 3 | $this->removeAllEdges(null, null, $edges); |
|||||
366 | 3 | $this->specifics->removeVertex($vertex); |
|||||
367 | 3 | return true; |
|||||
368 | } |
||||||
369 | 1 | return false; |
|||||
370 | } |
||||||
371 | |||||||
372 | /** |
||||||
373 | * Get the set of edges contained in the graph |
||||||
374 | * |
||||||
375 | * @return EdgeSet |
||||||
376 | */ |
||||||
377 | 11 | public function edgeSet(): EdgeSet |
|||||
378 | { |
||||||
379 | 11 | return $this->edgeSpecifics->getEdgeSet(); |
|||||
380 | } |
||||||
381 | |||||||
382 | /** |
||||||
383 | * Get the set of vertices contained in the graph |
||||||
384 | * |
||||||
385 | * @return VertexSet |
||||||
386 | */ |
||||||
387 | 14 | public function vertexSet(): VertexSet |
|||||
388 | { |
||||||
389 | 14 | return $this->specifics->getVertexSet(); |
|||||
390 | } |
||||||
391 | |||||||
392 | /** |
||||||
393 | * Get the edge source vertex |
||||||
394 | * |
||||||
395 | * @param EdgeInterface $edge - the edge |
||||||
396 | * |
||||||
397 | * @return VertexInterface |
||||||
398 | */ |
||||||
399 | 29 | public function getEdgeSource(EdgeInterface $edge): VertexInterface |
|||||
400 | { |
||||||
401 | 29 | return $this->edgeSpecifics->getEdgeSource($edge); |
|||||
402 | } |
||||||
403 | |||||||
404 | /** |
||||||
405 | * Get the edge target vertex |
||||||
406 | * |
||||||
407 | * @param EdgeInterface $edge - the edge |
||||||
408 | * |
||||||
409 | * @return VertexInterface |
||||||
410 | */ |
||||||
411 | 29 | public function getEdgeTarget(EdgeInterface $edge): VertexInterface |
|||||
412 | { |
||||||
413 | 29 | return $this->edgeSpecifics->getEdgeTarget($edge); |
|||||
414 | } |
||||||
415 | |||||||
416 | /** |
||||||
417 | * Get the edge weight |
||||||
418 | * |
||||||
419 | * @param EdgeInterface $edge - the edge |
||||||
420 | * |
||||||
421 | * @return null|float |
||||||
422 | */ |
||||||
423 | 8 | public function getEdgeWeight(EdgeInterface $edge): ?float |
|||||
424 | { |
||||||
425 | 8 | return $this->edgeSpecifics->getEdgeWeight($edge); |
|||||
426 | } |
||||||
427 | |||||||
428 | /** |
||||||
429 | * Set the edge weight |
||||||
430 | * |
||||||
431 | * @param EdgeInterface $edge - the edge |
||||||
432 | * @param float $weight - the edge weight |
||||||
433 | */ |
||||||
434 | 9 | public function setEdgeWeight(EdgeInterface $edge, ?float $weight = null): void |
|||||
435 | { |
||||||
436 | 9 | $this->edgeSpecifics->setEdgeWeight($edge, $weight); |
|||||
437 | 9 | } |
|||||
438 | |||||||
439 | /** |
||||||
440 | * Assert the the vertex exists |
||||||
441 | * |
||||||
442 | * @param VertexInterface - the vertex |
||||||
0 ignored issues
–
show
|
|||||||
443 | * |
||||||
444 | * @return bool |
||||||
445 | * |
||||||
446 | * @throws InvalidArgumentException |
||||||
447 | */ |
||||||
448 | 31 | private function assertVertexExists(VertexInterface $vertex): bool |
|||||
449 | { |
||||||
450 | 31 | if ($this->containsVertex($vertex)) { |
|||||
451 | 31 | return true; |
|||||
452 | } else { |
||||||
453 | throw new InvalidArgumentException("no such vertex in graph"); |
||||||
454 | } |
||||||
455 | } |
||||||
456 | } |
||||||
457 |
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.
This is most likely a typographical error or the method has been renamed.