Skip to content

Commit 1dd4d3c

Browse files
authored
Merge pull request #428 from phpmetrics/config_group
Way to analyze by layer
2 parents a59c49a + dc29e2b commit 1dd4d3c

File tree

17 files changed

+519
-96
lines changed

17 files changed

+519
-96
lines changed

README.md

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,55 @@ PhpMetrics provides metrics about PHP project and classes, with beautiful and re
2323
## Quick start
2424

2525
composer require phpmetrics/phpmetrics --dev
26-
php ./vendor/bin/phpmetrics --report-html=myreport .
26+
php ./vendor/bin/phpmetrics --report-html=myreport <folder-to-analyze>
2727

2828
Then open the generated `./myreport/index.html` file in your browser.
2929

30+
## Configuration file
31+
32+
Use the `--config=<file>.json` option. For example:
33+
34+
```json
35+
{
36+
"includes": [ // directory and files to analyze, relative to config file directory
37+
"src"
38+
],
39+
"exclude": [ // regex of files (or directory) to exclude from analyze
40+
"tests"
41+
],
42+
"report": { // list of reports to generate (html, json, csv or violation)
43+
"html": "/tmp/report/", // destination directory of HTML report
44+
"csv": "/tmp/report.csv", // destination file for CSV report
45+
"json": "/tmp/report.json", // destination file for JSON report
46+
"violations": "/tmp/violations.xml" // destination file for XML violations report
47+
},
48+
"groups": [ // "layers" of code. You can group your classes and packages by regex, to visualise specific HTML report for each of them
49+
{
50+
"name": "Component", // name of the layer
51+
"match": "!component!i" // regular expression used to match the group (based on the name of the fully qualified class name)
52+
// remember to double escape (for json, then for regex): set "!\\\\MyPackage\\\\!" if you want to capture expression "\MyPackage\"
53+
},
54+
{
55+
"name": "Example",
56+
"match": "!example!"
57+
}
58+
],
59+
"plugins": {
60+
"git": {
61+
"binary": "git" // if defined, runs git analyze
62+
},
63+
"junit": {
64+
"file": "/tmp/junit.xml" // if defined, JUnit report file will be analyzed
65+
}
66+
}
67+
"extensions": [ "php", "php8" ], // default: ["php", "inc"]
68+
}
69+
```
70+
3071
## More
3172

32-
If want, you can [install](https://github.com/phpmetrics/PhpMetrics/blob/master/doc/installation.md) PhpMetrics globally with your favorite package manager. You can also visit our [documentation](http://www.phpmetrics.org/documentation/index.html).
73+
If want, you can [install](doc/installation.md) PhpMetrics globally with your favorite package manager (APT, Brew...). You can also visit our [documentation](http://www.phpmetrics.org/documentation/index.html).
74+
3375

3476
## Metrics list
3577

config-example.json

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"includes": [
3+
"Controller"
4+
],
5+
"excludes": [
6+
"tests"
7+
],
8+
"report": {
9+
"html": "/tmp/report/",
10+
"csv": "/tmp/report.csv",
11+
"json": "/tmp/report.json",
12+
"violations": "/tmp/violations.xml"
13+
},
14+
"groups": [
15+
{
16+
"name": "Component",
17+
"match": "!component!i"
18+
},
19+
{
20+
"name": "Reporters",
21+
"match": "!Report!"
22+
}
23+
]
24+
}

config.json

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
{
2+
"includes": [
3+
"src/Hal/Component"
4+
],
5+
"excludes": [
6+
"tests"
7+
],
8+
"extensions": [
9+
"php",
10+
"php8"
11+
],
12+
"report": {
13+
"html": "/tmp/report/",
14+
"csv": "/tmp/report.csv",
15+
"json": "/tmp/report.json",
16+
"violations": "/tmp/violations.xml"
17+
},
18+
"groups": [
19+
{
20+
"name": "Component",
21+
"match": "!component!i"
22+
},
23+
{
24+
"name": "App",
25+
"match": "!app!i"
26+
}
27+
],
28+
"plugins": {
29+
"git": {
30+
"binary": "git"
31+
},
32+
"junit": {
33+
"file": "/tmp/junit.xml"
34+
}
35+
}
36+
}

doc/installation.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ Please note that the `~/.composer/vendor/bin` directory must be in your `$PATH`.
1313
export PATH=~/.composer/vendor/bin:$PATH
1414
```
1515

16-
## Phar
16+
## Phar
1717

1818
```bash
1919
curl https://github.com/phpmetrics/PhpMetrics/releases/download/v2.6.2/phpmetrics.phar
@@ -40,7 +40,7 @@ brew install phpmetrics
4040
yaourt install phpmetrics
4141
```
4242

43-
## Docker
43+
## Docker
4444

4545
```bash
4646
docker run --rm \

src/Hal/Application/Config/File/ConfigFileReaderJson.php

Lines changed: 47 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -36,36 +36,64 @@ public function read(Config $config)
3636

3737
$jsonData = json_decode($jsonText, true);
3838

39-
if (false === $jsonData) {
39+
if (false === $jsonData || null === $jsonData) {
4040
throw new \InvalidArgumentException("Bad json file '{$this->filename}'");
4141
}
4242

43-
$jsonDataImploded = $this->collapseArray($jsonData);
43+
if (isset($jsonData['includes'])) {
44+
$includes = $jsonData['includes'];
45+
$files = [];
46+
// with config file, includes are relative to config file
47+
foreach ($includes as $include) {
48+
$include = $this->resolvePath($include);
49+
$files[] = $include;
50+
}
51+
$config->set('files', $files);
52+
}
53+
54+
if (isset($jsonData['groups'])) {
55+
$config->set('groups', $jsonData['groups']);
56+
}
57+
58+
if (isset($jsonData['extensions'])) {
59+
$config->set('extensions', implode(',', $jsonData['extensions']));
60+
}
61+
62+
if (isset($jsonData['excludes'])) {
63+
// retro-compatibility
64+
// "exclude" is a string
65+
// excludes is an array
66+
$config->set('exclude', implode(',', $jsonData['excludes']));
67+
} else if (isset($jsonData['exclude'])) {
68+
$config->set('exclude', $jsonData['exclude']);
69+
}
4470

45-
foreach ($jsonDataImploded as $key => $value) {
46-
$config->set($key, $value);
71+
if (isset($jsonData['plugins'], $jsonData['plugins']['git'], $jsonData['plugins']['git']['binary'])) {
72+
$config->set('git', $jsonData['plugins']['git']['binary']);
73+
}
74+
75+
if (isset($jsonData['plugins'], $jsonData['plugins']['junit'], $jsonData['plugins']['junit']["report"])) {
76+
$config->set('junit', $jsonData['plugins']['junit']["report"]);
77+
}
78+
79+
// reports
80+
if (isset($jsonData['report']) && is_array($jsonData['report'])) {
81+
foreach ($jsonData['report'] as $reportType => $path) {
82+
$path = $this->resolvePath($path);
83+
$config->set('report-' . $reportType, $path);
84+
}
4785
}
4886
}
4987

5088
/**
51-
* Collapses array into a one-dimensional one by imploding nested keys with '-'
52-
*
53-
* @param array $arr
54-
*
55-
* @return array
89+
* @return string
5690
*/
57-
private function collapseArray(array $arr)
91+
private function resolvePath($path)
5892
{
59-
$iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($arr));
60-
$result = [];
61-
foreach ($iterator as $leafValue) {
62-
$keys = [];
63-
foreach (range(0, $iterator->getDepth()) as $depth) {
64-
$keys[] = $iterator->getSubIterator($depth)->key();
65-
}
66-
$result[implode('-', $keys)] = $leafValue;
93+
if (DIRECTORY_SEPARATOR !== $path[0]) {
94+
$path = dirname($this->filename) . DIRECTORY_SEPARATOR . $path;
6795
}
6896

69-
return $result;
97+
return $path;
7098
}
7199
}

src/Hal/Application/Config/Validator.php

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
<?php
2+
23
namespace Hal\Application\Config;
34

5+
use Hal\Metric\Group\Group;
6+
47
/**
58
* @package Hal\Application\Config
69
*/
@@ -32,10 +35,26 @@ public function validate(Config $config)
3235
if (!$config->has('exclude')) {
3336
$config->set('exclude', 'vendor,test,Test,tests,Tests,testing,Testing,bower_components,node_modules,cache,spec');
3437
}
38+
39+
// retro-compatibility with excludes as string in config files
40+
if (is_array($config->get('exclude'))) {
41+
$config->set('exclude', implode(',', $config->get('exclude')));
42+
}
3543
$config->set('exclude', array_filter(explode(',', $config->get('exclude'))));
3644

45+
// groups by regex
46+
if (!$config->has('groups')) {
47+
$config->set('groups', []);
48+
}
49+
$groupsRaw = $config->get('groups');
50+
51+
$groups = array_map(static function (array $groupRaw): Group {
52+
return new Group($groupRaw['name'], $groupRaw['match']);
53+
}, $groupsRaw);
54+
$config->set('groups', $groups);
55+
3756
// parameters with values
38-
$keys = ['report-html', 'report-csv', 'report-violation', '--report-json', 'extensions'];
57+
$keys = ['report-html', 'report-csv', 'report-violation', 'report-json', 'extensions', 'config'];
3958
foreach ($keys as $key) {
4059
$value = $config->get($key);
4160
if ($config->has($key) && empty($value) || true === $value) {
@@ -60,6 +79,7 @@ public function help()
6079
6180
Optional:
6281
82+
--config=<file> Use a file for configuration
6383
--exclude=<directory> List of directories to exclude, separated by a comma (,)
6484
--extensions=<php,inc> List of extensions to parse, separated by a comma (,)
6585
--report-html=<directory> Folder where report HTML will be generated

src/Hal/Metric/Group/Group.php

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
<?php
2+
3+
namespace Hal\Metric\Group;
4+
5+
use Hal\Metric\Metrics;
6+
7+
/**
8+
* Class Group
9+
* Allows to group metrics by regex, given them a name
10+
* @package Hal\Metric\Group
11+
*/
12+
class Group
13+
{
14+
/**
15+
* @var string
16+
*/
17+
private $name;
18+
19+
/**
20+
* @var string
21+
*/
22+
private $regex;
23+
24+
/**
25+
* Group constructor.
26+
* @param string $name
27+
* @param string $regex
28+
*/
29+
public function __construct($name, $regex)
30+
{
31+
$this->name = $name;
32+
$this->regex = $regex;
33+
}
34+
35+
/**
36+
* @return string
37+
*/
38+
public function getName()
39+
{
40+
return $this->name;
41+
}
42+
43+
/**
44+
* @return string
45+
*/
46+
public function getRegex()
47+
{
48+
return $this->regex;
49+
}
50+
51+
/**
52+
* @param Metrics $metrics
53+
* @return Metrics
54+
*/
55+
public function reduceMetrics(Metrics $metrics)
56+
{
57+
$all = $metrics->all();
58+
$matched = new Metrics();
59+
60+
foreach ($all as $metric) {
61+
if (!preg_match($this->regex, $metric->getName())) {
62+
continue;
63+
}
64+
65+
$matched->attach($metric);
66+
}
67+
68+
return $matched;
69+
}
70+
}

0 commit comments

Comments
 (0)