Skip to content

Commit 123dca3

Browse files
Refactors BubblePresenter for better separation
Renames BubblePresenter to BubbleMapper and creates a new BubblePresenter. This change improves separation of concerns by extracting the data transformation logic into a dedicated mapper class. The BubblePresenter now depends on the BubbleMapper for transforming metrics.
1 parent 493f92b commit 123dca3

File tree

4 files changed

+116
-99
lines changed

4 files changed

+116
-99
lines changed
Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
11
<?php
22

3-
namespace App\Commands\Analyze\Class\Graph;
3+
namespace App\Commands\Analyze\Class\Bubble;
44

55
use LaravelZero\Framework\Commands\Command;
66
use App\Presenter\Analyze\Class\Bubble\BubblePresenter;
7+
use App\Presenter\Analyze\Class\Bubble\BubbleMapper;
78

89
class BubblePresenterFactory
910
{
1011
public function __construct(
12+
private readonly BubbleMapper $mapper,
1113
) {}
1214

1315
public function make(Command $command): BubblePresenter
1416
{
15-
return new BubblePresenter();
17+
return new BubblePresenter(
18+
mapper: $this->mapper,
19+
);
1620
}
1721
}

app/Commands/Analyze/Class/PresenterFactory.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
use Illuminate\Console\Command;
66
use App\Application\Analyze\AnalyzePresenter;
77
use App\Commands\Analyze\Class\Graph\GraphPresenterFactory;
8-
use App\Commands\Analyze\Class\Graph\BubblePresenterFactory;
8+
use App\Commands\Analyze\Class\Bubble\BubblePresenterFactory;
99
use App\Commands\Analyze\Class\Summary\SummaryPresenterFactory;
1010

1111
class PresenterFactory
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Presenter\Analyze\Class\Bubble;
6+
7+
use App\Application\Analyze\AnalyzeMetric;
8+
9+
class BubbleMapper
10+
{
11+
/**
12+
* @param array<AnalyzeMetric> $metrics
13+
* @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}}>
14+
*/
15+
public function from(array $metrics): array
16+
{
17+
$foldersData = [];
18+
19+
foreach ($metrics as $metric) {
20+
$folderPath = $this->fqcnToFolderPath($metric->name());
21+
$dependencies = $metric->dependencies();
22+
23+
if (!isset($foldersData[$folderPath])) {
24+
$foldersData[$folderPath] = [
25+
'classes' => 0,
26+
'interfaces' => 0,
27+
'abstracts' => 0,
28+
'total' => 0,
29+
'relations' => [],
30+
'metrics' => [
31+
'efferent_coupling' => 0.0,
32+
'afferent_coupling' => 0.0,
33+
'instability' => 0.0,
34+
'loc_total' => 0,
35+
'ccn_total' => 0,
36+
],
37+
];
38+
}
39+
40+
// Compter le type de classe
41+
if ($metric->isInterface()) {
42+
$foldersData[$folderPath]['interfaces']++;
43+
} elseif ($metric->abstract()) {
44+
$foldersData[$folderPath]['abstracts']++;
45+
} else {
46+
$foldersData[$folderPath]['classes']++;
47+
}
48+
49+
$foldersData[$folderPath]['total']++;
50+
51+
// Ajouter les métriques de couplage
52+
$foldersData[$folderPath]['metrics']['efferent_coupling'] += $metric->efferentCoupling();
53+
$foldersData[$folderPath]['metrics']['afferent_coupling'] += $metric->afferentCoupling();
54+
$foldersData[$folderPath]['metrics']['instability'] += $metric->instability();
55+
56+
// Convertir les dépendances en chemins de dossiers et les ajouter aux relations
57+
foreach ($dependencies as $dependency) {
58+
$dependencyFolderPath = $this->fqcnToFolderPath($dependency);
59+
60+
// Ne pas ajouter de relation vers le même dossier
61+
if ($dependencyFolderPath !== $folderPath && !in_array($dependencyFolderPath, $foldersData[$folderPath]['relations'], true)) {
62+
$foldersData[$folderPath]['relations'][] = $dependencyFolderPath;
63+
}
64+
}
65+
}
66+
67+
// Calculer les moyennes d'instabilité par dossier
68+
foreach ($foldersData as $folderPath => &$data) {
69+
$count = $data['total'];
70+
if ($count > 0) {
71+
$data['metrics']['instability'] = number_format($data['metrics']['instability'] / $count, 2);
72+
}
73+
}
74+
75+
return $foldersData;
76+
}
77+
78+
private function fqcnToFolderPath(string $fqcn): string
79+
{
80+
// Séparer le namespace et le nom de classe
81+
$parts = explode('\\', $fqcn);
82+
83+
// Retirer le nom de classe (dernier élément)
84+
array_pop($parts);
85+
86+
if (empty($parts)) {
87+
return '';
88+
}
89+
90+
// Convertir en chemin de dossier
91+
$path = implode('/', $parts);
92+
93+
// Mettre en minuscule la première partie (ex: App -> app)
94+
$firstSlash = strpos($path, '/');
95+
if ($firstSlash !== false) {
96+
$firstPart = substr($path, 0, $firstSlash);
97+
$rest = substr($path, $firstSlash);
98+
return strtolower($firstPart) . $rest;
99+
}
100+
101+
return strtolower($path);
102+
}
103+
}
104+

app/Presenter/Analyze/Class/Bubble/BubblePresenter.php

Lines changed: 5 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -4,116 +4,25 @@
44

55
namespace App\Presenter\Analyze\Class\Bubble;
66

7-
use Exception;
87
use Throwable;
98
use App\Application\Analyze\AnalyzeResponse;
109
use App\Application\Analyze\AnalyzePresenter;
11-
use App\Application\Analyze\AnalyzeMetric;
1210

1311
class BubblePresenter implements AnalyzePresenter
1412
{
13+
public function __construct(
14+
private readonly BubbleMapper $mapper,
15+
) {}
16+
1517
public function present(AnalyzeResponse $response): void
1618
{
1719
$metrics = $response->metrics;
1820

19-
$foldersData = $this->transformMetricsToFoldersData($metrics);
21+
$foldersData = $this->mapper->from($metrics);
2022

2123
echo json_encode($foldersData, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
2224
}
2325

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-
}
113-
114-
return strtolower($path);
115-
}
116-
11726
public function hello(): void
11827
{
11928
}

0 commit comments

Comments
 (0)