Skip to content

Commit 493f92b

Browse files
Adds bubble chart presenter
Implements a new presenter to transform analyze metrics into a format suitable for a bubble chart visualization. This includes calculating folder-level metrics like coupling and instability, and generating relations between folders based on class dependencies. The presenter outputs data in JSON format.
1 parent ccc25ce commit 493f92b

File tree

3 files changed

+104
-4
lines changed

3 files changed

+104
-4
lines changed

app/Application/Analyze/AnalyzeMetric.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,9 @@ public function abstractnessRatio(): float
4747
{
4848
return $this->metric['abstractness']['ratio'];
4949
}
50+
51+
public function isInterface(): bool
52+
{
53+
return $this->metric['isInterface'] ?? false;
54+
}
5055
}

app/Domain/Entities/ClassDependencies.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ public function toArray(): array
7474
'name' => $this->getName(),
7575
'dependencies' => $this->getDependencies(),
7676
'abstract' => $this->isAbstract(),
77+
'isInterface' => $this->isInterface->isTrue(),
7778
'coupling' => $this->coupling->toArray(),
7879
'abstractness' => $this->abstractness->toArray(),
7980
];
Lines changed: 98 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,124 @@
11
<?php
22

3+
declare(strict_types=1);
4+
35
namespace App\Presenter\Analyze\Class\Bubble;
46

57
use Exception;
68
use Throwable;
79
use App\Application\Analyze\AnalyzeResponse;
810
use App\Application\Analyze\AnalyzePresenter;
11+
use App\Application\Analyze\AnalyzeMetric;
912

1013
class BubblePresenter implements AnalyzePresenter
1114
{
1215
public function present(AnalyzeResponse $response): void
1316
{
1417
$metrics = $response->metrics;
1518

16-
dd($metrics);
19+
$foldersData = $this->transformMetricsToFoldersData($metrics);
20+
21+
echo json_encode($foldersData, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
22+
}
23+
24+
/**
25+
* @param array<AnalyzeMetric> $metrics
26+
* @return array<string, array{classes: int, interfaces: int, abstracts: int, total: int, relations: array<string>, metrics: array{efferent_coupling: float, afferent_coupling: float, instability: float, loc_total: int, ccn_total: int}}>
27+
*/
28+
private function transformMetricsToFoldersData(array $metrics): array
29+
{
30+
$foldersData = [];
31+
32+
foreach ($metrics as $metric) {
33+
$folderPath = $this->fqcnToFolderPath($metric->name());
34+
$dependencies = $metric->dependencies();
35+
36+
if (!isset($foldersData[$folderPath])) {
37+
$foldersData[$folderPath] = [
38+
'classes' => 0,
39+
'interfaces' => 0,
40+
'abstracts' => 0,
41+
'total' => 0,
42+
'relations' => [],
43+
'metrics' => [
44+
'efferent_coupling' => 0.0,
45+
'afferent_coupling' => 0.0,
46+
'instability' => 0.0,
47+
'loc_total' => 0,
48+
'ccn_total' => 0,
49+
],
50+
];
51+
}
52+
53+
// Compter le type de classe
54+
if ($metric->isInterface()) {
55+
$foldersData[$folderPath]['interfaces']++;
56+
} elseif ($metric->abstract()) {
57+
$foldersData[$folderPath]['abstracts']++;
58+
} else {
59+
$foldersData[$folderPath]['classes']++;
60+
}
61+
62+
$foldersData[$folderPath]['total']++;
63+
64+
// Ajouter les métriques de couplage
65+
$foldersData[$folderPath]['metrics']['efferent_coupling'] += $metric->efferentCoupling();
66+
$foldersData[$folderPath]['metrics']['afferent_coupling'] += $metric->afferentCoupling();
67+
$foldersData[$folderPath]['metrics']['instability'] += $metric->instability();
68+
69+
// Convertir les dépendances en chemins de dossiers et les ajouter aux relations
70+
foreach ($dependencies as $dependency) {
71+
$dependencyFolderPath = $this->fqcnToFolderPath($dependency);
72+
73+
// Ne pas ajouter de relation vers le même dossier
74+
if ($dependencyFolderPath !== $folderPath && !in_array($dependencyFolderPath, $foldersData[$folderPath]['relations'], true)) {
75+
$foldersData[$folderPath]['relations'][] = $dependencyFolderPath;
76+
}
77+
}
78+
}
79+
80+
// Calculer les moyennes d'instabilité par dossier
81+
foreach ($foldersData as $folderPath => &$data) {
82+
$count = $data['total'];
83+
if ($count > 0) {
84+
$data['metrics']['instability'] = number_format($data['metrics']['instability'] / $count, 2);
85+
}
86+
}
87+
88+
return $foldersData;
89+
}
90+
91+
private function fqcnToFolderPath(string $fqcn): string
92+
{
93+
// Séparer le namespace et le nom de classe
94+
$parts = explode('\\', $fqcn);
95+
96+
// Retirer le nom de classe (dernier élément)
97+
array_pop($parts);
98+
99+
if (empty($parts)) {
100+
return '';
101+
}
102+
103+
// Convertir en chemin de dossier
104+
$path = implode('/', $parts);
105+
106+
// Mettre en minuscule la première partie (ex: App -> app)
107+
$firstSlash = strpos($path, '/');
108+
if ($firstSlash !== false) {
109+
$firstPart = substr($path, 0, $firstSlash);
110+
$rest = substr($path, $firstSlash);
111+
return strtolower($firstPart) . $rest;
112+
}
17113

18-
//
114+
return strtolower($path);
19115
}
20116

21117
public function hello(): void
22118
{
23-
throw new Exception('Not implemented');
24119
}
25120

26121
public function error(Throwable $e): void
27122
{
28-
throw new \Exception('Not implemented');
29123
}
30124
}

0 commit comments

Comments
 (0)