Skip to content

Commit ff4f2c5

Browse files
Support for custom Reporters (#61)
1 parent 28d0dea commit ff4f2c5

File tree

131 files changed

+5424
-905
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

131 files changed

+5424
-905
lines changed

config.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,12 @@ cognitive:
4040
threshold: 1
4141
scale: 1.0
4242
enabled: true
43+
# Example of custom reporters:
44+
# customReporters:
45+
# cognitive:
46+
# pdf:
47+
# class: 'My\Custom\PdfReporter'
48+
# file: '/path/to/PdfReporter.php'
49+
# churn:
50+
# class: 'My\Custom\ChurnReporter'
51+
# file: '/path/to/ChurnReporter.php'

docs/Creating-Custom-Reporters.md

Lines changed: 286 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,286 @@
1+
# Creating Custom Reporters
2+
3+
This guide explains how to create custom reporters for the Cognitive Code Checker to output metrics in your preferred format.
4+
5+
## Overview
6+
7+
The Cognitive Code Checker supports two types of reports:
8+
9+
- **Cognitive reporter**: Export cognitive complexity metrics
10+
- **Churn reporter**: Export code churn metrics
11+
12+
Both types follow similar patterns but have different interfaces and data structures.
13+
14+
## Reporter Types
15+
16+
### Cognitive reporter
17+
18+
Cognitive reporter handle cognitive complexity metrics data and implement the `ReportGeneratorInterface` from the `Phauthentic\CognitiveCodeAnalysis\Business\Cognitive\Report` namespace.
19+
20+
**Interface:**
21+
22+
```php
23+
interface ReportGeneratorInterface
24+
{
25+
public function export(CognitiveMetricsCollection $metrics, string $filename): void;
26+
}
27+
```
28+
29+
**Data Structure:** `CognitiveMetricsCollection` contains individual `CognitiveMetrics` objects with methods like:
30+
31+
- `getClass()` - Class name
32+
- `getMethod()` - Method name
33+
- `getLineCount()` - Number of lines
34+
- `getScore()` - Combined cognitive complexity score
35+
- `getLineCountWeight()`, `getArgCountWeight()`, etc. - Individual metric weights
36+
- `getLineCountWeightDelta()`, etc. - Delta values for comparison
37+
38+
### Churn reporter
39+
40+
Churn reporter handle code churn metrics data and implement the `ReportGeneratorInterface` from the `Phauthentic\CognitiveCodeAnalysis\Business\Churn\Report` namespace.
41+
42+
**Interface:**
43+
44+
```php
45+
interface ReportGeneratorInterface
46+
{
47+
/**
48+
* @param array<string, array<string, mixed>> $classes
49+
*/
50+
public function export(array $classes, string $filename): void;
51+
}
52+
```
53+
54+
**Data Structure:** Array with class names as keys and arrays containing:
55+
- `file` - File path
56+
- `score` - Churn score
57+
- `churn` - Churn value
58+
- `timesChanged` - Number of times changed
59+
- `coverage` - Test coverage (optional)
60+
- `riskLevel` - Risk level (optional)
61+
62+
## Configuration
63+
64+
Add your custom reporter to the `config.yml` file under the `customReporters` section:
65+
66+
```yaml
67+
cognitive:
68+
# ... other cognitive settings ...
69+
customReporters:
70+
cognitive:
71+
pdf: # Custom reporter name
72+
class: 'My\Custom\PdfReporter'
73+
file: '/path/to/PdfReporter.php'
74+
churn:
75+
churn: # Custom reporter name
76+
class: 'My\Custom\ChurnReporter'
77+
file: '/path/to/ChurnReporter.php'
78+
```
79+
80+
### Configuration Parameters
81+
82+
- **`class`** (required): Fully qualified class name of your reporter
83+
- **`file`** (optional): Path to the PHP file containing your reporter class. Set to `null` if using autoloading
84+
85+
## Constructor Patterns
86+
87+
The system automatically detects whether your reporter needs the `CognitiveConfig` object:
88+
89+
### Reporter with Config Access
90+
91+
```php
92+
class PdfReporter implements ReportGeneratorInterface
93+
{
94+
private CognitiveConfig $config;
95+
96+
public function __construct(CognitiveConfig $config)
97+
{
98+
$this->config = $config;
99+
}
100+
// ... rest of implementation
101+
}
102+
```
103+
104+
### Reporter without Config
105+
106+
```php
107+
class SimpleReporter implements ReportGeneratorInterface
108+
{
109+
public function __construct()
110+
{
111+
// No config needed
112+
}
113+
// ... rest of implementation
114+
}
115+
```
116+
117+
The system will automatically try to pass the config to your constructor. If your constructor doesn't accept it, the system will fall back to calling the constructor without arguments.
118+
119+
Here's a complete example of a custom PDF reporter for cognitive metrics:
120+
121+
```php
122+
<?php
123+
124+
declare(strict_types=1);
125+
126+
namespace My\Custom;
127+
128+
use Phauthentic\CognitiveCodeAnalysis\Business\Cognitive\Report\ReportGeneratorInterface;
129+
use Phauthentic\CognitiveCodeAnalysis\Business\Cognitive\CognitiveMetricsCollection;
130+
use Phauthentic\CognitiveCodeAnalysis\Config\CognitiveConfig;
131+
use Phauthentic\CognitiveCodeAnalysis\CognitiveAnalysisException;
132+
133+
class PdfReporter implements ReportGeneratorInterface
134+
{
135+
private CognitiveConfig $config;
136+
137+
public function __construct(CognitiveConfig $config)
138+
{
139+
$this->config = $config;
140+
}
141+
142+
public function export(CognitiveMetricsCollection $metrics, string $filename): void
143+
{
144+
// Ensure directory exists
145+
$directory = dirname($filename);
146+
if (!is_dir($directory)) {
147+
throw new CognitiveAnalysisException("Directory {$directory} does not exist");
148+
}
149+
150+
// Create PDF content
151+
$pdfContent = $this->generatePdfContent($metrics);
152+
153+
// Write to file
154+
if (file_put_contents($filename, $pdfContent) === false) {
155+
throw new CognitiveAnalysisException("Could not write to file: {$filename}");
156+
}
157+
}
158+
159+
private function generatePdfContent(CognitiveMetricsCollection $metrics): string
160+
{
161+
$content = "%PDF-1.4\n";
162+
$content .= "1 0 obj\n";
163+
$content .= "<< /Type /Catalog /Pages 2 0 R >>\n";
164+
$content .= "endobj\n";
165+
166+
// Add your PDF generation logic here
167+
$groupedByClass = $metrics->groupBy('class');
168+
169+
foreach ($groupedByClass as $class => $methods) {
170+
$content .= "% Class: {$class}\n";
171+
foreach ($methods as $metric) {
172+
$content .= "Method: {$metric->getMethod()}, Score: {$metric->getScore()}\n";
173+
}
174+
}
175+
176+
return $content;
177+
}
178+
}
179+
```
180+
181+
## Creating a Custom Churn Reporter
182+
183+
Here's an example of a custom churn reporter for churn metrics:
184+
185+
```php
186+
<?php
187+
188+
declare(strict_types=1);
189+
190+
namespace My\Custom;
191+
192+
use Phauthentic\CognitiveCodeAnalysis\Business\Churn\Report\ReportGeneratorInterface;
193+
use Phauthentic\CognitiveCodeAnalysis\CognitiveAnalysisException;
194+
195+
class ChurnReporter implements ReportGeneratorInterface
196+
{
197+
public function export(array $classes, string $filename): void
198+
{
199+
// Ensure directory exists
200+
$directory = dirname($filename);
201+
if (!is_dir($directory)) {
202+
throw new CognitiveAnalysisException("Directory {$directory} does not exist");
203+
}
204+
205+
// Generate churn content
206+
$churnContent = $this->generateChurnContent($classes);
207+
208+
// Write to file
209+
if (file_put_contents($filename, $churnContent) === false) {
210+
throw new CognitiveAnalysisException("Could not write to file: {$filename}");
211+
}
212+
}
213+
214+
private function generateChurnContent(array $classes): string
215+
{
216+
$content = "Churn Report\n";
217+
$content .= "============\n\n";
218+
219+
foreach ($classes as $className => $data) {
220+
$content .= "Class: {$className}\n";
221+
$content .= "File: {$data['file']}\n";
222+
$content .= "Score: {$data['score']}\n";
223+
$content .= "Churn: {$data['churn']}\n";
224+
$content .= "Times Changed: {$data['timesChanged']}\n";
225+
$content .= "---\n";
226+
}
227+
228+
return $content;
229+
}
230+
}
231+
```
232+
233+
## Using Your Custom Reporter
234+
235+
Once configured, you can use your custom reporter by specifying its name when generating reports:
236+
237+
```bash
238+
# For cognitive metrics
239+
php bin/cognitive-report --format=pdf --output=report.pdf
240+
241+
# For churn metrics
242+
php bin/churn-report --format=churn --output=churn.txt
243+
```
244+
245+
## Best Practices
246+
247+
1. **Error Handling**: Always throw `CognitiveAnalysisException` for errors
248+
2. **File Validation**: Check that directories exist and files are writable
249+
3. **Data Access**: Use the provided methods to access metric data
250+
4. **Configuration**: Use `CognitiveConfig` if you need access to settings
251+
5. **Testing**: Test your reporter with real data to ensure proper formatting
252+
253+
## Built-in reporter Reference
254+
255+
For inspiration, examine the built-in reporter:
256+
257+
**Cognitive reporter:**
258+
-
259+
- `JsonReport` - JSON format
260+
- `CsvReport` - CSV format
261+
- `HtmlReport` - HTML with Bootstrap styling
262+
- `MarkdownReport` - Markdown tables
263+
264+
**Churn reporter:**
265+
266+
- `JsonReport` - JSON format
267+
- `CsvReport` - CSV format
268+
- `HtmlReport` - HTML with Bootstrap styling
269+
- `MarkdownReport` - Markdown tables
270+
- `SvgTreemapReport` - SVG treemap visualization
271+
272+
## Troubleshooting
273+
274+
**Common Issues:**
275+
276+
1. **Class not found**: Ensure the `class` parameter uses the full namespace
277+
2. **File not found**: Check the `file` path is correct and accessible
278+
3. **Interface not implemented**: Ensure your class implements the correct `ReportGeneratorInterface`
279+
4. **Constructor issues**: Your reporter can optionally accept `CognitiveConfig` in its constructor - the system will automatically detect this
280+
281+
**Debug Tips:**
282+
283+
- Check the configuration syntax in `config.yml`
284+
- Verify file paths are absolute or relative to the project root
285+
- Test with simple reporter first before complex implementations
286+
- Use the built-in reporter as templates for your custom ones

phpmd.xml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@
1111
</description>
1212

1313
<!-- Import the entire unused code rule set -->
14-
<rule ref="rulesets/cleancode.xml" />
14+
<rule ref="rulesets/cleancode.xml">
15+
<exclude name="StaticAccess" />
16+
</rule>
1517
<rule ref="rulesets/unusedcode.xml" />
1618
<rule ref="rulesets/naming.xml">
1719
<exclude name="LongVariable" />

0 commit comments

Comments
 (0)