Skip to content

Commit b2681f9

Browse files
Amoifrclaude
andcommitted
Fix DataCollector not appearing in Symfony Profiler
- Mark DataCollector service as public - Mark FileAnalyzer service as public for DI resolution - Add priority to data_collector tag Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent fadddd0 commit b2681f9

15 files changed

Lines changed: 13337 additions & 1 deletion

File tree

src/DependencyInjection/PhpQualityExtension.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,11 @@ private function registerDataCollector(ContainerBuilder $container, array $profi
6666
$profilerConfig['exclude_paths'],
6767
]);
6868

69+
$definition->setPublic(true);
6970
$definition->addTag('data_collector', [
7071
'template' => '@PhpQuality/data_collector/phpquality.html.twig',
7172
'id' => 'phpquality',
73+
'priority' => 300,
7274
]);
7375

7476
$container->setDefinition(PhpQualityDataCollector::class, $definition);

src/Resources/config/services.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ services:
1616
resource: '../../Config/'
1717

1818
PhpQuality\Analyzer\Ast\AstParser: ~
19-
PhpQuality\Analyzer\FileAnalyzer: ~
19+
PhpQuality\Analyzer\FileAnalyzer:
20+
public: true
2021
PhpQuality\Analyzer\ProjectAnalyzer: ~
2122

2223
PhpQuality\Analyzer\ProjectType\ProjectTypeDetector:

test-report/analysis.html

Lines changed: 927 additions & 0 deletions
Large diffs are not rendered by default.

test-report/architecture.html

Lines changed: 658 additions & 0 deletions
Large diffs are not rendered by default.

test-report/ccn.html

Lines changed: 2990 additions & 0 deletions
Large diffs are not rendered by default.

test-report/coverage.html

Lines changed: 271 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,271 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6+
<title>Test Coverage - PhpQuality</title>
7+
<link rel="stylesheet" href="report.css">
8+
<script src="https://cdn.jsdelivr.net/npm/chart.js@4"></script>
9+
<style>
10+
<style>
11+
.coverage-progress {
12+
margin: 1rem 0;
13+
}
14+
.progress-bar {
15+
height: 24px;
16+
background: var(--bg-secondary);
17+
border-radius: 12px;
18+
overflow: hidden;
19+
}
20+
.progress-fill {
21+
height: 100%;
22+
transition: width 0.3s ease;
23+
}
24+
.progress-labels {
25+
display: flex;
26+
justify-content: space-between;
27+
margin-top: 0.5rem;
28+
font-size: 0.85rem;
29+
color: var(--text-muted);
30+
}
31+
.mini-progress {
32+
display: flex;
33+
align-items: center;
34+
gap: 0.5rem;
35+
}
36+
.mini-progress .mini-progress-fill {
37+
height: 8px;
38+
border-radius: 4px;
39+
min-width: 60px;
40+
background: var(--bg-secondary);
41+
position: relative;
42+
}
43+
.rating-bg-A { background: #22c55e; }
44+
.rating-bg-B { background: #84cc16; }
45+
.rating-bg-C { background: #eab308; }
46+
.rating-bg-D { background: #f97316; }
47+
.rating-bg-F { background: #ef4444; }
48+
</style>
49+
</style>
50+
</head>
51+
<body>
52+
<nav class="navbar">
53+
<div class="navbar-content">
54+
<a href="index.html" class="navbar-brand">
55+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
56+
<path d="M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5"/>
57+
</svg>
58+
<span class="navbar-title">PhpQuality</span>
59+
<span class="navbar-author">by <a href="https://moi.ruedesjasses.fr" target="_blank" rel="noopener">Pascal CESCON</a></span>
60+
</a>
61+
62+
<ul class="nav-links">
63+
<li><a href="index.html" class="nav-link ">Dashboard</a></li>
64+
<li><a href="metrics.html" class="nav-link ">Documentation</a></li>
65+
66+
<!-- Metrics Dropdown -->
67+
<li class="nav-dropdown">
68+
<button class="nav-link nav-dropdown-toggle ">
69+
Metrics
70+
<svg class="dropdown-arrow" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="12" height="12">
71+
<polyline points="6 9 12 15 18 9"></polyline>
72+
</svg>
73+
</button>
74+
<ul class="nav-dropdown-menu">
75+
<li><a href="ccn.html" class="nav-link ">CCN - Complexity</a></li>
76+
<li><a href="mi.html" class="nav-link ">MI - Maintainability</a></li>
77+
<li><a href="lcom.html" class="nav-link ">LCOM - Cohesion</a></li>
78+
<li><a href="loc.html" class="nav-link ">LOC - Lines of Code</a></li>
79+
</ul>
80+
</li>
81+
82+
<!-- Analysis Dropdown -->
83+
<li class="nav-dropdown">
84+
<button class="nav-link nav-dropdown-toggle ">
85+
Analysis
86+
<svg class="dropdown-arrow" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="12" height="12">
87+
<polyline points="6 9 12 15 18 9"></polyline>
88+
</svg>
89+
</button>
90+
<ul class="nav-dropdown-menu">
91+
<li><a href="halstead.html" class="nav-link ">Halstead Metrics</a></li>
92+
<li><a href="analysis.html" class="nav-link ">Multi-dimensional</a></li>
93+
<li><a href="recommendations.html" class="nav-link ">Recommendations</a></li>
94+
</ul>
95+
</li>
96+
97+
<!-- Architecture Dropdown -->
98+
<li class="nav-dropdown">
99+
<button class="nav-link nav-dropdown-toggle ">
100+
Architecture
101+
<svg class="dropdown-arrow" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="12" height="12">
102+
<polyline points="6 9 12 15 18 9"></polyline>
103+
</svg>
104+
</button>
105+
<ul class="nav-dropdown-menu">
106+
<li><a href="architecture.html" class="nav-link ">Layers &amp; SOLID</a></li>
107+
<li><a href="coverage.html" class="nav-link active">Test Coverage</a></li>
108+
<li><a href="dependencies.html" class="nav-link ">Dependencies</a></li>
109+
</ul>
110+
</li>
111+
</ul>
112+
113+
<button class="btn-icon" onclick="toggleTheme()" title="Toggle light/dark theme">
114+
<svg class="icon-sun" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
115+
<circle cx="12" cy="12" r="5"/>
116+
<line x1="12" y1="1" x2="12" y2="3"/>
117+
<line x1="12" y1="21" x2="12" y2="23"/>
118+
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/>
119+
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/>
120+
<line x1="1" y1="12" x2="3" y2="12"/>
121+
<line x1="21" y1="12" x2="23" y2="12"/>
122+
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/>
123+
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/>
124+
</svg>
125+
<svg class="icon-moon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
126+
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/>
127+
</svg>
128+
</button>
129+
</div>
130+
</nav>
131+
132+
<div class="container">
133+
<div class="page-header">
134+
<h1>Test Coverage</h1>
135+
<p>Code coverage analysis from PHPUnit test suite</p>
136+
</div>
137+
138+
<!-- No Coverage Data -->
139+
<section class="section">
140+
<div class="card text-center" style="padding: 3rem;">
141+
<div style="font-size: 4rem; margin-bottom: 1rem; opacity: 0.5;">&#128202;</div>
142+
<h2>No Coverage Data</h2>
143+
<p class="text-muted" style="margin-bottom: 2rem;">No coverage file was provided. Use --coverage option to include test coverage analysis.</p>
144+
145+
<div class="card" style="text-align: left; max-width: 700px; margin: 0 auto;">
146+
<h3>How to Generate Coverage</h3>
147+
<p>Use PHPUnit with the --coverage-clover option to generate a coverage report in Clover XML format:</p>
148+
<pre><code># PHPUnit (Clover format)
149+
./vendor/bin/phpunit --coverage-clover coverage.xml
150+
151+
# Then run PhpQuality with coverage
152+
docker run --rm \
153+
-v $(pwd):/project \
154+
amoifr13/phpquality \
155+
analyze --source=/project/src --coverage=/project/coverage.xml</code></pre>
156+
</div>
157+
</div>
158+
</section>
159+
160+
<footer>
161+
<p>Generated by <a href="https://github.com/amoifr/PhpQuality">PhpQuality</a> on 2026-03-26 06:49:34</p>
162+
<p style="margin-top: 0.5rem;">Developed by <a href="https://moi.ruedesjasses.fr">Pascal CESCON</a></p>
163+
</footer>
164+
</div>
165+
166+
<script>
167+
// Theme toggle
168+
function initTheme() {
169+
const savedTheme = localStorage.getItem('phpquality-theme');
170+
if (savedTheme) {
171+
document.documentElement.setAttribute('data-theme', savedTheme);
172+
}
173+
}
174+
175+
function toggleTheme() {
176+
const currentTheme = document.documentElement.getAttribute('data-theme');
177+
const newTheme = currentTheme === 'light' ? 'dark' : 'light';
178+
179+
if (newTheme === 'dark') {
180+
document.documentElement.removeAttribute('data-theme');
181+
} else {
182+
document.documentElement.setAttribute('data-theme', newTheme);
183+
}
184+
185+
localStorage.setItem('phpquality-theme', newTheme);
186+
}
187+
188+
// Initialize theme on page load
189+
initTheme();
190+
</script>
191+
192+
<script>
193+
const coverageData = null;
194+
195+
// Coverage Distribution Chart
196+
new Chart(document.getElementById('coverageDistChart').getContext('2d'), {
197+
type: 'doughnut',
198+
data: {
199+
labels: coverageData.distribution.labels,
200+
datasets: [{
201+
data: coverageData.distribution.values,
202+
backgroundColor: coverageData.distribution.colors,
203+
borderWidth: 0
204+
}]
205+
},
206+
options: {
207+
responsive: true,
208+
maintainAspectRatio: false,
209+
plugins: {
210+
legend: {
211+
position: 'right',
212+
labels: { color: '#94a3b8', font: { size: 11 } }
213+
}
214+
}
215+
}
216+
});
217+
218+
// Filter functionality
219+
const searchInput = document.getElementById('searchInput');
220+
const ratingFilter = document.getElementById('ratingFilter');
221+
const tbody = document.querySelector('#filesTable tbody');
222+
223+
function filterTable() {
224+
const search = searchInput.value.toLowerCase();
225+
const rating = ratingFilter.value;
226+
const rows = tbody.querySelectorAll('tr');
227+
228+
rows.forEach(row => {
229+
const text = row.textContent.toLowerCase();
230+
const rowRating = row.dataset.rating;
231+
const matchesSearch = text.includes(search);
232+
const matchesRating = !rating || rowRating === rating;
233+
row.style.display = matchesSearch && matchesRating ? '' : 'none';
234+
});
235+
}
236+
237+
searchInput.addEventListener('input', filterTable);
238+
ratingFilter.addEventListener('change', filterTable);
239+
240+
// Sort functionality
241+
let currentSort = { col: 1, asc: true };
242+
243+
function sortTable(col) {
244+
const rows = Array.from(tbody.querySelectorAll('tr'));
245+
const isAsc = currentSort.col === col ? !currentSort.asc : true;
246+
currentSort = { col, asc: isAsc };
247+
248+
rows.sort((a, b) => {
249+
const aVal = a.cells[col].dataset.sort || a.cells[col].textContent;
250+
const bVal = b.cells[col].dataset.sort || b.cells[col].textContent;
251+
const aNum = parseFloat(aVal);
252+
const bNum = parseFloat(bVal);
253+
254+
if (!isNaN(aNum) && !isNaN(bNum)) {
255+
return isAsc ? aNum - bNum : bNum - aNum;
256+
}
257+
return isAsc ? aVal.localeCompare(bVal) : bVal.localeCompare(aVal);
258+
});
259+
260+
rows.forEach(row => tbody.appendChild(row));
261+
262+
// Update sort indicators
263+
document.querySelectorAll('#filesTable th').forEach((th, i) => {
264+
th.classList.toggle('sorted', i === col);
265+
const icon = th.querySelector('.sort-icon');
266+
if (icon) icon.innerHTML = i === col ? (isAsc ? '&#9650;' : '&#9660;') : '&#9650;';
267+
});
268+
}
269+
</script>
270+
</body>
271+
</html>

0 commit comments

Comments
 (0)