Skip to content

Commit 2be92fc

Browse files
authored
Merge pull request #182 from olivernybroe/sniffwrapper
[feat] Adds support for ignoring a file on a specific sniff
2 parents c41477d + cf9096d commit 2be92fc

File tree

12 files changed

+330
-71
lines changed

12 files changed

+330
-71
lines changed

phpstan.neon.dist

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,11 @@ parameters:
2222
- '#is not allowed to extend#'
2323
- '#Language construct isset\(\) should not be used#'
2424
- '#Access to an undefined property PHP_CodeSniffer\\Config::\$standards.#'
25+
- '#Access to an undefined property PHP_CodeSniffer\\Sniffs\\Sniff::\$#'
2526
autoload_files:
2627
- %rootDir%/../../squizlabs/php_codesniffer/autoload.php
2728
reportUnmatchedIgnoredErrors: false
2829

2930
excludes_analyse:
3031
- %rootDir%/../../../tests/*/Fixtures/*
32+
- %rootDir%/../../../tests/Fixtures/*

src/Domain/EcsContainer.php

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
namespace NunoMaduro\PhpInsights\Domain;
66

7-
use Symfony\Component\DependencyInjection\ContainerInterface;
7+
use Symfony\Component\DependencyInjection\Container;
88
use Symplify\EasyCodingStandard\HttpKernel\EasyCodingStandardKernel;
99
use Symplify\PackageBuilder\Console\Input\InputDetector;
1010

@@ -14,14 +14,14 @@
1414
final class EcsContainer
1515
{
1616
/**
17-
* @var \Symfony\Component\DependencyInjection\ContainerInterface
17+
* @var \Symfony\Component\DependencyInjection\Container
1818
*/
1919
private static $container;
2020

2121
/**
22-
* @return \Symfony\Component\DependencyInjection\ContainerInterface
22+
* @return \Symfony\Component\DependencyInjection\Container
2323
*/
24-
public static function make(): ContainerInterface
24+
public static function make(): Container
2525
{
2626
if (self::$container === null) {
2727
$environment = str_replace('.', '_', sprintf(
@@ -31,11 +31,13 @@ public static function make(): ContainerInterface
3131
$easyCodingStandardKernel = new EasyCodingStandardKernel($environment, InputDetector::isDebug());
3232
$easyCodingStandardKernel->boot();
3333

34-
if ($easyCodingStandardKernel->getContainer() === null) {
34+
$container = $easyCodingStandardKernel->getContainer();
35+
36+
if ($container === null || ! ($container instanceof Container)) {
3537
throw new \RuntimeException('Unable to get EcsContainer.');
3638
}
3739

38-
self::$container = $easyCodingStandardKernel->getContainer();
40+
self::$container = $container;
3941
}
4042

4143
return self::$container;

src/Domain/File.php

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,16 @@
44

55
namespace NunoMaduro\PhpInsights\Domain;
66

7+
use NunoMaduro\PhpInsights\Domain\Sniffs\SniffWrapper;
78
use PHP_CodeSniffer\Config;
89
use PHP_CodeSniffer\Files\File as BaseFile;
910
use PHP_CodeSniffer\Fixer;
10-
use PHP_CodeSniffer\Sniffs\Sniff;
1111
use PHP_CodeSniffer\Util\Common;
1212
use Symplify\EasyCodingStandard\Application\AppliedCheckersCollector;
1313
use Symplify\EasyCodingStandard\Console\Style\EasyCodingStandardStyle;
1414
use Symplify\EasyCodingStandard\Error\ErrorAndDiffCollector;
1515
use Symplify\EasyCodingStandard\Skipper;
16+
use Symplify\EasyCodingStandard\SniffRunner\Exception\File\NotImplementedException;
1617
use Symplify\PackageBuilder\FileSystem\SmartFileInfo;
1718

1819
final class File extends BaseFile
@@ -28,7 +29,7 @@ final class File extends BaseFile
2829
private $previousActiveSniffClass;
2930

3031
/**
31-
* @var array<array<\PHP_CodeSniffer\Sniffs\Sniff>>
32+
* @var array<array<\NunoMaduro\PhpInsights\Domain\Sniffs\SniffWrapper>>
3233
*/
3334
private $tokenListeners = [];
3435

@@ -120,15 +121,15 @@ public function process(): void
120121

121122
public function getErrorCount(): int
122123
{
123-
throw new \Symplify\EasyCodingStandard\SniffRunner\Exception\File\NotImplementedException();
124+
throw new NotImplementedException();
124125
}
125126

126127
/**
127128
* {@inheritdoc}
128129
*/
129130
public function getErrors(): array
130131
{
131-
throw new \Symplify\EasyCodingStandard\SniffRunner\Exception\File\NotImplementedException();
132+
throw new NotImplementedException();
132133
}
133134

134135
/**
@@ -145,7 +146,7 @@ public function addFixableError($error, $stackPtr, $code, $data = [], $severity
145146
}
146147

147148
/**
148-
* @param array<array<Sniff>> $tokenListeners
149+
* @param array<array<\NunoMaduro\PhpInsights\Domain\Sniffs\SniffWrapper>> $tokenListeners
149150
*/
150151
public function processWithTokenListenersAndFileInfo(array $tokenListeners, SmartFileInfo $fileInfo): void
151152
{
@@ -154,6 +155,16 @@ public function processWithTokenListenersAndFileInfo(array $tokenListeners, Smar
154155
$this->process();
155156
}
156157

158+
/**
159+
* Get's the file info from the file.
160+
*
161+
* @return SmartFileInfo
162+
*/
163+
public function getFileInfo(): SmartFileInfo
164+
{
165+
return $this->fileInfo;
166+
}
167+
157168
/**
158169
* {@inheritdoc}
159170
*/
@@ -181,12 +192,12 @@ protected function addMessage(
181192
}
182193

183194
/**
184-
* @param Sniff $sniff
195+
* @param SniffWrapper $sniff
185196
*/
186-
private function reportActiveSniffClass(Sniff $sniff): void
197+
private function reportActiveSniffClass(SniffWrapper $sniff): void
187198
{
188199
// used in other places later
189-
$this->activeSniffClass = get_class($sniff);
200+
$this->activeSniffClass = get_class($sniff->getWrappedSniff());
190201

191202
if (! $this->easyCodingStandardStyle->isDebug()) {
192203
return;

src/Domain/FileProcessor.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ final class FileProcessor implements FileProcessorInterface
2020
private $sniffs = [];
2121

2222
/**
23-
* @var array<array<\PHP_CodeSniffer\Sniffs\Sniff>>
23+
* @var array<array<\NunoMaduro\PhpInsights\Domain\Sniffs\SniffWrapper>>
2424
*/
2525
private $tokenListeners = [];
2626

src/Domain/Insights/InsightCollectionFactory.php

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,16 +92,23 @@ public function get(array $metrics, array $config, string $dir): InsightCollecti
9292
*/
9393
private function getInsights(string $metricClass, array $config): array
9494
{
95+
/** @var HasInsights $metric */
9596
$metric = new $metricClass();
9697

97-
$insights = array_key_exists(HasInsights::class, class_implements($metricClass)) ? $metric->getInsights() : [];
98+
$insights = array_key_exists(
99+
HasInsights::class,
100+
class_implements($metricClass)
101+
) ? $metric->getInsights() : [];
98102

99103
$toAdd = array_key_exists('add', $config) &&
100104
array_key_exists($metricClass, $config['add']) &&
101-
is_array($config['add'][$metricClass]) ? $config['add'][$metricClass] : [];
105+
is_array($config['add'][$metricClass])
106+
? $config['add'][$metricClass]
107+
: [];
102108

103109
$insights = array_merge($insights, $toAdd);
104110

111+
// Remove insights based on config.
105112
return array_diff($insights, $config['remove'] ?? []);
106113
}
107114
}

src/Domain/Insights/InsightFactory.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use NunoMaduro\PhpInsights\Domain\EcsContainer;
1010
use NunoMaduro\PhpInsights\Domain\FileProcessor;
1111
use NunoMaduro\PhpInsights\Domain\Reflection;
12+
use NunoMaduro\PhpInsights\Domain\Sniffs\SniffWrapper;
1213
use PHP_CodeSniffer\Sniffs\Sniff as SniffContract;
1314
use Symplify\EasyCodingStandard\Application\EasyCodingStandardApplication;
1415
use Symplify\EasyCodingStandard\Configuration\Configuration;
@@ -173,7 +174,7 @@ private function getSniffCollector(array $config): ErrorAndDiffCollector
173174

174175
$sniffer = Container::make()->get(FileProcessor::class);
175176
foreach ($this->sniffsFrom($this->insightsClasses, $config) as $sniff) {
176-
$sniffer->addSniff($sniff);
177+
$sniffer->addSniff(new SniffWrapper($sniff));
177178
}
178179

179180
/** @var \Symplify\EasyCodingStandard\Application\EasyCodingStandardApplication $application */
@@ -192,6 +193,10 @@ private function getSniffCollector(array $config): ErrorAndDiffCollector
192193
/** @var \Symplify\EasyCodingStandard\Error\ErrorAndDiffCollector $errorAndDiffCollector */
193194
$errorAndDiffCollector = $ecsContainer->get(ErrorAndDiffCollector::class);
194195

196+
// Destroy the container, so we insights doesn't fail on consecutive
197+
// runs. This is needed for tests also.
198+
$ecsContainer->reset();
199+
195200
return $this->sniffCollector = $errorAndDiffCollector;
196201
}
197202
}

src/Domain/Insights/Sniff.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ public function getDetails(): array
7979
public function getInsightClass(): string
8080
{
8181
if (\count($this->errors) === 0) {
82-
throw new SniffClassNotFound('Unable to found Sniff used.');
82+
throw new SniffClassNotFound('Unable to find Sniff used.');
8383
}
8484

8585
return explode('.', $this->errors[0]->getSourceClass())[0];

src/Domain/Sniffs/SniffWrapper.php

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace NunoMaduro\PhpInsights\Domain\Sniffs;
6+
7+
use NunoMaduro\PhpInsights\Domain\File as InsightFile;
8+
use PHP_CodeSniffer\Files\File;
9+
use PHP_CodeSniffer\Sniffs\Sniff;
10+
11+
/**
12+
* This wrapper is meant for us to add custom logic which is applied to all
13+
* sniffs.
14+
*
15+
* This logic could be for example to exclude the sniff if it's running on
16+
* a specific class.
17+
*/
18+
final class SniffWrapper implements Sniff
19+
{
20+
/** @var Sniff */
21+
private $sniff;
22+
23+
/**
24+
* SniffWrapper constructor.
25+
*
26+
* @param Sniff $sniff
27+
*/
28+
public function __construct(Sniff $sniff)
29+
{
30+
$this->sniff = $sniff;
31+
}
32+
33+
/**
34+
* Registers the tokens that this sniff wants to listen for.
35+
*
36+
* @return mixed[]
37+
*
38+
* @see Tokens.php
39+
*/
40+
public function register(): array
41+
{
42+
return $this->sniff->register();
43+
}
44+
45+
/**
46+
* Called when one of the token types that this sniff is listening for
47+
* is found.
48+
*
49+
* @param File|InsightFile $file The PHP_CodeSniffer file
50+
* @param int $stackPtr The position in the PHP_CodeSniffer file's
51+
* token stack
52+
*
53+
* @return void|int Optionally returns a stack pointer. The sniff will not be
54+
* called again on the current file until the returned stack
55+
* pointer is reached. Return (count($tokens) + 1) to skip
56+
* the rest of the file.
57+
*/
58+
public function process(File $file, $stackPtr)
59+
{
60+
if ($file instanceof InsightFile) {
61+
// skip files if they are part of ignore files array.
62+
if ($this->skipFilesFromIgnoreFiles($file)) {
63+
return;
64+
}
65+
}
66+
67+
return $this->sniff->process($file, $stackPtr);
68+
}
69+
70+
private function skipFilesFromIgnoreFiles(InsightFile $file): bool
71+
{
72+
$path = $file->getFileInfo()->getRealPath();
73+
74+
if ($path === false) {
75+
return false;
76+
}
77+
78+
foreach ($this->getIgnoreFilesSetting() as $ignoreFile) {
79+
if (self::pathsAreEqual(
80+
$ignoreFile,
81+
$path
82+
)) {
83+
return true;
84+
}
85+
}
86+
return false;
87+
}
88+
89+
/**
90+
* Contains the setting for all files which the sniff should ignore.
91+
*
92+
* @return array<string>
93+
*/
94+
private function getIgnoreFilesSetting(): array
95+
{
96+
return $this->sniff->ignoreFiles ?? [];
97+
}
98+
99+
private static function pathsAreEqual(string $pathA, string $pathB): bool
100+
{
101+
return realpath($pathA) === realpath($pathB);
102+
}
103+
104+
/**
105+
* Returns the sniff which we have wrapped.
106+
*
107+
* @return Sniff
108+
*/
109+
public function getWrappedSniff(): Sniff
110+
{
111+
return $this->sniff;
112+
}
113+
}

0 commit comments

Comments
 (0)