From 482e95f16823adcc3d3200eedd62d5544dff4d4d Mon Sep 17 00:00:00 2001 From: Gummibeer Date: Wed, 28 Aug 2019 15:38:04 +0200 Subject: [PATCH 1/9] add HTML formatter --- composer.json | 3 +- .../Console/Definitions/AnalyseDefinition.php | 2 +- .../Console/Formatters/FormatResolver.php | 1 + src/Application/Console/Formatters/Html.php | 70 +++++++++++++++++++ src/Domain/Insights/InsightCollection.php | 8 +++ views/dashboard.html.twig | 46 ++++++++++++ views/partials/insights_per_metric.html.twig | 35 ++++++++++ views/partials/stats_per_metric.html.twig | 5 ++ 8 files changed, 168 insertions(+), 2 deletions(-) create mode 100644 src/Application/Console/Formatters/Html.php create mode 100644 views/dashboard.html.twig create mode 100644 views/partials/insights_per_metric.html.twig create mode 100644 views/partials/stats_per_metric.html.twig diff --git a/composer.json b/composer.json index f32ecffa..7fd41c75 100644 --- a/composer.json +++ b/composer.json @@ -24,7 +24,8 @@ "slevomat/coding-standard": "^5.0", "squizlabs/php_codesniffer": "^3.4", "symfony/console": "^4.2", - "symfony/finder": "^4.2" + "symfony/finder": "^4.2", + "twig/twig": "^2.0" }, "require-dev": { "illuminate/console": "^5.8", diff --git a/src/Application/Console/Definitions/AnalyseDefinition.php b/src/Application/Console/Definitions/AnalyseDefinition.php index 90cd9763..386549d1 100644 --- a/src/Application/Console/Definitions/AnalyseDefinition.php +++ b/src/Application/Console/Definitions/AnalyseDefinition.php @@ -67,7 +67,7 @@ public static function get(): array 'format', null, InputOption::VALUE_REQUIRED, - 'Format to output the result in [console, json]', + 'Format to output the result in [console, json, html].', "console" ), ]; diff --git a/src/Application/Console/Formatters/FormatResolver.php b/src/Application/Console/Formatters/FormatResolver.php index 31dba11c..8f0d8afc 100644 --- a/src/Application/Console/Formatters/FormatResolver.php +++ b/src/Application/Console/Formatters/FormatResolver.php @@ -20,6 +20,7 @@ final class FormatResolver private static $formatters = [ 'console' => Console::class, 'json' => Json::class, + 'html' => Html::class, ]; public static function resolve( diff --git a/src/Application/Console/Formatters/Html.php b/src/Application/Console/Formatters/Html.php new file mode 100644 index 00000000..738f2783 --- /dev/null +++ b/src/Application/Console/Formatters/Html.php @@ -0,0 +1,70 @@ +output = $output; + } + + /** + * Format the result to the desired format. + * + * @param InsightCollection $insightCollection + * @param string $dir + * @param array $metrics + * + * @throws Exception + */ + public function format( + InsightCollection $insightCollection, + string $dir, + array $metrics + ): void + { + $loader = new FilesystemLoader(__DIR__.'/../../../../views'); + $twig = new Environment($loader, [ + 'cache' => false, + 'debug' => true, + ]); + $twig->addExtension(new DebugExtension()); + $twig->addTest(new TwigTest('instanceof', function($var, $instance) { + $reflexionClass = new \ReflectionClass($instance); + return $reflexionClass->isInstance($var); + })); + $twig->addFilter(new TwigFilter('sluggify', function ($slug) { + $slug = preg_replace('/<(.*?)>/u', '', $slug); + $slug = preg_replace('/[\'"‘’“”]/u', '', $slug); + $slug = mb_strtolower($slug, 'UTF-8'); + preg_match_all('/[\p{L}\p{N}\.]+/u', $slug, $words); + return implode('-', array_filter($words[0])); + })); + + $this->output->write($twig->render('dashboard.html.twig', [ + 'dir' => $dir, + 'results' => $insightCollection->results(), + 'insights' => $insightCollection, + ]), false, OutputInterface::OUTPUT_RAW); + } +} diff --git a/src/Domain/Insights/InsightCollection.php b/src/Domain/Insights/InsightCollection.php index 94c20e9e..eb3e0b05 100644 --- a/src/Domain/Insights/InsightCollection.php +++ b/src/Domain/Insights/InsightCollection.php @@ -43,6 +43,14 @@ public function getCollector(): Collector return $this->collector; } + /** + * @return array> + */ + public function getInsightsPerMetric(): array + { + return $this->insightsPerMetric; + } + /** * Gets all insights. * diff --git a/views/dashboard.html.twig b/views/dashboard.html.twig new file mode 100644 index 00000000..b30edd7b --- /dev/null +++ b/views/dashboard.html.twig @@ -0,0 +1,46 @@ + + + + + + + + + + PHP Insights + + +
+ +

PHP Insights

+ +

+ + {{ dir }} +

+ +
+
{% include 'partials/stats_per_metric.html.twig' with {'id': 'quality', 'title': 'code quality', 'score': results.codeQuality} %}
+
{% include 'partials/stats_per_metric.html.twig' with {'id': 'complexity', 'title': 'complexity', 'score': results.complexity} %}
+
{% include 'partials/stats_per_metric.html.twig' with {'id': 'structure', 'title': 'structure', 'score': results.structure} %}
+
{% include 'partials/stats_per_metric.html.twig' with {'id': 'style', 'title': 'style', 'score': results.style} %}
+
+ +
+ score scale: + 1 - 49 + 50 - 79 + 80 - 100 +
+ + {% include 'partials/insights_per_metric.html.twig' with {'id': 'quality', 'title': 'code quality', 'metricNamespacePart': '\\Code\\'} %} + {% include 'partials/insights_per_metric.html.twig' with {'id': 'complexity', 'title': 'complexity', 'metricNamespacePart': '\\Complexity\\'} %} + {% include 'partials/insights_per_metric.html.twig' with {'id': 'structure', 'title': 'structure', 'metricNamespacePart': '\\Architecture\\'} %} + {% include 'partials/insights_per_metric.html.twig' with {'id': 'style', 'title': 'style', 'metricNamespacePart': '\\Style\\'} %} + +
+ + + + + diff --git a/views/partials/insights_per_metric.html.twig b/views/partials/insights_per_metric.html.twig new file mode 100644 index 00000000..2c1fc6b4 --- /dev/null +++ b/views/partials/insights_per_metric.html.twig @@ -0,0 +1,35 @@ +

{{ title }}

+
+ {% for metric, insightsPerMetric in insights.insightsPerMetric %} + {% if metricNamespacePart in metric %} + {% for insight in insightsPerMetric %} + {% if insight.hasIssue() %} +
+
+ + {{ insight.title }} + ({{ insight.details|length }}) + {{ insight.insightClass }} +
+
+
    + {% for detail in insight.details %} +
  • + {% if detail.hasFile() %} + + {{ detail.file }}{% if detail.hasLine() %}:{{ detail.line }}{% endif %}{% if detail.hasFunction() %}:{{ detail.function }}{% endif %} + + {% endif %} + {% if detail.hasMessage() %} + {{ detail.message }} + {% endif %} +
  • + {% endfor %} +
+
+
+ {% endif %} + {% endfor %} + {% endif %} + {% endfor %} +
diff --git a/views/partials/stats_per_metric.html.twig b/views/partials/stats_per_metric.html.twig new file mode 100644 index 00000000..af4a8b58 --- /dev/null +++ b/views/partials/stats_per_metric.html.twig @@ -0,0 +1,5 @@ +
+ {{ title }} + +
{{ score|number_format(1, '.') }} %
+
From 7dd734824cf13849b2e119825984edbf5bbef8fb Mon Sep 17 00:00:00 2001 From: Gummibeer Date: Wed, 28 Aug 2019 15:41:56 +0200 Subject: [PATCH 2/9] update docs --- docs/get-started.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/get-started.md b/docs/get-started.md index 390cf35e..379015ac 100644 --- a/docs/get-started.md +++ b/docs/get-started.md @@ -81,6 +81,7 @@ For changing the output format you can add the `format` flag. The following form - console - json +- html ```bash ./vendor/bin/phpinsights analyse --format=json @@ -89,10 +90,11 @@ For changing the output format you can add the `format` flag. The following form ## Saving output to file You can pipe the result to a file or to anywhere you like. -A common use case is parsing the output formatted as json to a json file. +A common use case is parsing the output formatted as json or html to a file. ```bash ./vendor/bin/phpinsights analyse --format=json > test.json +./vendor/bin/phpinsights analyse --format=html > test.html ``` When piping the result remember to add the no interaction flag `-n`, as the part where you need to interact is also getting piped. (the json format does not have any interaction) From 2e4a4b1d34e5e361bcfd5fcfe535912087ab1fe5 Mon Sep 17 00:00:00 2001 From: Gummibeer Date: Thu, 19 Sep 2019 15:37:15 +0200 Subject: [PATCH 3/9] make twig optional/suggested --- composer.json | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index 7fd41c75..d1830f63 100644 --- a/composer.json +++ b/composer.json @@ -24,8 +24,7 @@ "slevomat/coding-standard": "^5.0", "squizlabs/php_codesniffer": "^3.4", "symfony/console": "^4.2", - "symfony/finder": "^4.2", - "twig/twig": "^2.0" + "symfony/finder": "^4.2" }, "require-dev": { "illuminate/console": "^5.8", @@ -37,7 +36,11 @@ "roave/no-floaters": "^1.1", "symfony/var-dumper": "^4.2", "symplify/easy-coding-standard": "^6.0", - "thecodingmachine/phpstan-strict-rules": "^0.11.0" + "thecodingmachine/phpstan-strict-rules": "^0.11.0", + "twig/twig": "^2.0" + }, + "suggest": { + "twig/twig": "Twig:^2.0 is needed to support the HTML formattter" }, "autoload-dev": { "psr-4": { From 06f6310301452dfa7e653b8862590c3ef09e242f Mon Sep 17 00:00:00 2001 From: Gummibeer Date: Thu, 19 Sep 2019 15:37:30 +0200 Subject: [PATCH 4/9] optimize twig --- src/Application/Console/Formatters/Html.php | 31 +++++++++++---------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/src/Application/Console/Formatters/Html.php b/src/Application/Console/Formatters/Html.php index 738f2783..a9ebb305 100644 --- a/src/Application/Console/Formatters/Html.php +++ b/src/Application/Console/Formatters/Html.php @@ -9,11 +9,9 @@ use NunoMaduro\PhpInsights\Domain\Insights\InsightCollection; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; -use Twig\Environment; -use Twig\Extension\DebugExtension; +use Twig\Environment as Twig; use Twig\Loader\FilesystemLoader; use Twig\TwigFilter; -use Twig\TwigTest; /** * @internal @@ -42,29 +40,32 @@ public function format( string $dir, array $metrics ): void + { + $this->output->write($this->getTwig()->render('dashboard.html.twig', [ + 'dir' => $dir, + 'results' => $insightCollection->results(), + 'insights' => $insightCollection, + ]), false, OutputInterface::OUTPUT_RAW); + } + + protected function getTwig(): Twig { $loader = new FilesystemLoader(__DIR__.'/../../../../views'); - $twig = new Environment($loader, [ + $twig = new Twig($loader, [ 'cache' => false, 'debug' => true, ]); - $twig->addExtension(new DebugExtension()); - $twig->addTest(new TwigTest('instanceof', function($var, $instance) { - $reflexionClass = new \ReflectionClass($instance); - return $reflexionClass->isInstance($var); - })); - $twig->addFilter(new TwigFilter('sluggify', function ($slug) { + + $twig->addFilter(new TwigFilter('sluggify', function (string $slug) { $slug = preg_replace('/<(.*?)>/u', '', $slug); $slug = preg_replace('/[\'"‘’“”]/u', '', $slug); $slug = mb_strtolower($slug, 'UTF-8'); + preg_match_all('/[\p{L}\p{N}\.]+/u', $slug, $words); + return implode('-', array_filter($words[0])); })); - $this->output->write($twig->render('dashboard.html.twig', [ - 'dir' => $dir, - 'results' => $insightCollection->results(), - 'insights' => $insightCollection, - ]), false, OutputInterface::OUTPUT_RAW); + return $twig; } } From c054759cf0898cafefbdb20cd421f60462751cb1 Mon Sep 17 00:00:00 2001 From: Gummibeer Date: Thu, 19 Sep 2019 15:43:29 +0200 Subject: [PATCH 5/9] add hint to docs --- docs/get-started.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/get-started.md b/docs/get-started.md index 379015ac..64c76dcc 100644 --- a/docs/get-started.md +++ b/docs/get-started.md @@ -87,6 +87,12 @@ For changing the output format you can add the `format` flag. The following form ./vendor/bin/phpinsights analyse --format=json ``` +::: Twig for HTML +The HTML formatter requires Twig to render. +So you have to add it do your dependencies if you want to use it. +`composer require --dev twig/twig: ^2.0` +::: + ## Saving output to file You can pipe the result to a file or to anywhere you like. From e90765158075c37d6d0eff225324a4748bab583c Mon Sep 17 00:00:00 2001 From: Gummibeer Date: Thu, 19 Sep 2019 15:52:36 +0200 Subject: [PATCH 6/9] fix protected->private --- src/Application/Console/Formatters/Html.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Application/Console/Formatters/Html.php b/src/Application/Console/Formatters/Html.php index a9ebb305..f8fdaa18 100644 --- a/src/Application/Console/Formatters/Html.php +++ b/src/Application/Console/Formatters/Html.php @@ -48,7 +48,7 @@ public function format( ]), false, OutputInterface::OUTPUT_RAW); } - protected function getTwig(): Twig + private function getTwig(): Twig { $loader = new FilesystemLoader(__DIR__.'/../../../../views'); $twig = new Twig($loader, [ From e9f24f0930432247fe841d1ec88b8b983c403252 Mon Sep 17 00:00:00 2001 From: Gummibeer Date: Thu, 19 Sep 2019 16:33:42 +0200 Subject: [PATCH 7/9] ignore phpstan error --- phpstan.neon.dist | 1 + 1 file changed, 1 insertion(+) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 876b4771..925e1caa 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -24,6 +24,7 @@ parameters: - '#Access to an undefined property PHP_CodeSniffer\\Config::\$standards.#' - '#Access to an undefined property PHP_CodeSniffer\\Sniffs\\Sniff::\$#' - '#NunoMaduro\\PhpInsights\\Application\\Console\\Formatters\\Json has an unused parameter \$input#' + - '#NunoMaduro\\PhpInsights\\Application\\Console\\Formatters\\Html has an unused parameter \$input#' - '#In method "NunoMaduro\\PhpInsights\\Domain\\File::process", caught "Throwable" must be rethrown#' - '#Casting to string something that#' - '#Instanceof between Illuminate\\Contracts\\Foundation\\Application and#' From 9ac17e8eda15ecd782a2ad378f573f6ac90f50ce Mon Sep 17 00:00:00 2001 From: Gummibeer Date: Thu, 19 Sep 2019 16:34:00 +0200 Subject: [PATCH 8/9] make phpinsights happy --- src/Application/Console/Formatters/Html.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Application/Console/Formatters/Html.php b/src/Application/Console/Formatters/Html.php index f8fdaa18..11d2f83c 100644 --- a/src/Application/Console/Formatters/Html.php +++ b/src/Application/Console/Formatters/Html.php @@ -56,12 +56,12 @@ private function getTwig(): Twig 'debug' => true, ]); - $twig->addFilter(new TwigFilter('sluggify', function (string $slug) { - $slug = preg_replace('/<(.*?)>/u', '', $slug); - $slug = preg_replace('/[\'"‘’“”]/u', '', $slug); - $slug = mb_strtolower($slug, 'UTF-8'); + $twig->addFilter(new TwigFilter('sluggify', static function (string $slug): string { + $slug = preg_replace('/<(.*?)>/u', '', (string) $slug); + $slug = preg_replace('/[\'"‘’“”]/u', '', (string) $slug); + $slug = mb_strtolower((string) $slug, 'UTF-8'); - preg_match_all('/[\p{L}\p{N}\.]+/u', $slug, $words); + preg_match_all('/[\p{L}\p{N}\.]+/u', (string) $slug, $words); return implode('-', array_filter($words[0])); })); From c93989fd9205d1b242ae0bcc9f6515084088d602 Mon Sep 17 00:00:00 2001 From: Gummibeer Date: Wed, 25 Sep 2019 11:48:58 +0200 Subject: [PATCH 9/9] fix php cs --- src/Application/Console/Formatters/Html.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Application/Console/Formatters/Html.php b/src/Application/Console/Formatters/Html.php index 11d2f83c..a2eadfc4 100644 --- a/src/Application/Console/Formatters/Html.php +++ b/src/Application/Console/Formatters/Html.php @@ -39,8 +39,7 @@ public function format( InsightCollection $insightCollection, string $dir, array $metrics - ): void - { + ): void { $this->output->write($this->getTwig()->render('dashboard.html.twig', [ 'dir' => $dir, 'results' => $insightCollection->results(),