1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Imanghafoori\LaravelMicroscope\Commands; |
4
|
|
|
|
5
|
|
|
use Illuminate\Console\Command; |
6
|
|
|
use Illuminate\Support\Composer; |
7
|
|
|
use Illuminate\Support\Str; |
8
|
|
|
use Imanghafoori\LaravelMicroscope\Analyzers\ComposerJson; |
9
|
|
|
use Imanghafoori\LaravelMicroscope\CheckNamespaces; |
10
|
|
|
use Imanghafoori\LaravelMicroscope\ErrorReporters\ErrorPrinter; |
11
|
|
|
use Imanghafoori\LaravelMicroscope\FileReaders\Paths; |
12
|
|
|
use Imanghafoori\LaravelMicroscope\LaravelPaths\FilePath; |
13
|
|
|
use Imanghafoori\LaravelMicroscope\LaravelPaths\LaravelPaths; |
14
|
|
|
use Imanghafoori\LaravelMicroscope\SpyClasses\RoutePaths; |
15
|
|
|
|
16
|
|
|
class CheckPsr4 extends Command |
17
|
|
|
{ |
18
|
|
|
protected $signature = 'check:psr4 {--d|detailed : Show files being checked} {--f|force} {--s|nofix}'; |
19
|
|
|
|
20
|
|
|
protected $description = 'Checks the validity of namespaces'; |
21
|
|
|
|
22
|
|
|
public function handle(ErrorPrinter $errorPrinter) |
23
|
|
|
{ |
24
|
|
|
$this->line(''); |
25
|
|
|
$this->info('Started checking PSR-4 namespaces...'); |
26
|
|
|
$time = microtime(true); |
27
|
|
|
|
28
|
|
|
$errorPrinter->printer = $this->output; |
29
|
|
|
|
30
|
|
|
$autoload = ComposerJson::readAutoload(); |
31
|
|
|
$this->checkNamespaces($autoload); |
32
|
|
|
|
33
|
|
|
$this->option('nofix') && config(['microscope.no_fix' => true]); |
34
|
|
|
|
35
|
|
|
if (CheckNamespaces::$changedNamespaces && ! config('microscope.no_fix')) { |
|
|
|
|
36
|
|
|
$olds = \array_keys(CheckNamespaces::$changedNamespaces); |
37
|
|
|
$news = \array_values(CheckNamespaces::$changedNamespaces); |
38
|
|
|
|
39
|
|
|
$this->fixReferences($autoload, $olds, $news); |
40
|
|
|
} |
41
|
|
|
|
42
|
|
|
if (Str::startsWith(request()->server('argv')[1] ?? '', 'check:psr4')) { |
43
|
|
|
$this->reportResult($autoload); |
44
|
|
|
$this->printErrorsCount($errorPrinter, $time); |
45
|
|
|
} else { |
46
|
|
|
$this->getOutput()->writeln(' - '.CheckNamespaces::$checkedNamespaces.' namespaces were checked.'); |
47
|
|
|
} |
48
|
|
|
|
49
|
|
|
$this->composerDumpIfNeeded($errorPrinter); |
50
|
|
|
} |
51
|
|
|
|
52
|
|
|
private function composerDumpIfNeeded(ErrorPrinter $errorPrinter) |
53
|
|
|
{ |
54
|
|
|
if ($c = $errorPrinter->getCount('badNamespace')) { |
55
|
|
|
$this->output->write('- '.$c.' Namespace'.($c > 1 ? 's' : '').' Fixed, Running: "composer dump"'); |
56
|
|
|
app(Composer::class)->dumpAutoloads(); |
57
|
|
|
$this->info("\n".'finished: "composer dump"'); |
58
|
|
|
} |
59
|
|
|
} |
60
|
|
|
|
61
|
|
|
private function fixRefs($_path, $olds, $news) |
62
|
|
|
{ |
63
|
|
|
$lines = file($_path); |
64
|
|
|
$changed = []; |
65
|
|
|
$olds = $this->deriveVariants($olds); |
66
|
|
|
$news = $this->deriveVariants($news); |
67
|
|
|
foreach ($lines as $i => $line) { |
68
|
|
|
$count = 0; |
69
|
|
|
$lines[$i] = \str_replace($olds, $news, $line, $count); |
70
|
|
|
$count && $changed[] = ($i + 1); |
|
|
|
|
71
|
|
|
} |
72
|
|
|
|
73
|
|
|
$changed && \file_put_contents($_path, \implode('', $lines)); |
|
|
|
|
74
|
|
|
|
75
|
|
|
return $changed; |
76
|
|
|
} |
77
|
|
|
|
78
|
|
|
private function deriveVariants($olds) |
79
|
|
|
{ |
80
|
|
|
$newOld = []; |
81
|
|
|
foreach ($olds as $old) { |
82
|
|
|
$newOld[] = $old.'('; |
83
|
|
|
$newOld[] = $old.'::'; |
84
|
|
|
$newOld[] = $old.';'; |
85
|
|
|
$newOld[] = $old."\n"; |
86
|
|
|
$newOld[] = $old."\r"; |
87
|
|
|
} |
88
|
|
|
|
89
|
|
|
return $newOld; |
90
|
|
|
} |
91
|
|
|
|
92
|
|
|
private function collectNonPsr4Paths() |
93
|
|
|
{ |
94
|
|
|
$paths = [ |
95
|
|
|
RoutePaths::get(), |
96
|
|
|
Paths::getAbsFilePaths(LaravelPaths::migrationDirs()), |
97
|
|
|
Paths::getAbsFilePaths(config_path()), |
98
|
|
|
Paths::getAbsFilePaths(LaravelPaths::factoryDirs()), |
99
|
|
|
Paths::getAbsFilePaths(LaravelPaths::seeders()), |
100
|
|
|
LaravelPaths::bladeFilePaths(), |
101
|
|
|
]; |
102
|
|
|
|
103
|
|
|
return $this->mergePaths($paths); |
104
|
|
|
} |
105
|
|
|
|
106
|
|
|
private function mergePaths($paths) |
107
|
|
|
{ |
108
|
|
|
$all = []; |
109
|
|
|
foreach ($paths as $p) { |
110
|
|
|
$all = array_merge($all, $p); |
111
|
|
|
} |
112
|
|
|
|
113
|
|
|
return $all; |
114
|
|
|
} |
115
|
|
|
|
116
|
|
|
private function fixReferences($autoload, $olds, $news) |
117
|
|
|
{ |
118
|
|
|
foreach ($autoload as $psr4Path) { |
119
|
|
|
$files = FilePath::getAllPhpFiles($psr4Path); |
120
|
|
|
foreach ($files as $classFilePath) { |
121
|
|
|
$_path = $classFilePath->getRealPath(); |
122
|
|
|
$lineNumbers = $this->fixRefs($_path, $olds, $news); |
123
|
|
|
foreach ($lineNumbers as $line) { |
124
|
|
|
$this->report($_path, $line); |
125
|
|
|
} |
126
|
|
|
} |
127
|
|
|
} |
128
|
|
|
|
129
|
|
|
foreach ($this->collectNonPsr4Paths() as $_path) { |
130
|
|
|
$lineNumbers = $this->fixRefs($_path, $olds, $news); |
131
|
|
|
foreach ($lineNumbers as $line) { |
132
|
|
|
$this->report($_path, $line); |
133
|
|
|
} |
134
|
|
|
} |
135
|
|
|
} |
136
|
|
|
|
137
|
|
|
private function checkNamespaces(array $autoload) |
138
|
|
|
{ |
139
|
|
|
foreach ($autoload as $psr4Namespace => $psr4Path) { |
140
|
|
|
$files = FilePath::getAllPhpFiles($psr4Path); |
141
|
|
|
CheckNamespaces::within($files, $psr4Path, $psr4Namespace, $this); |
|
|
|
|
142
|
|
|
} |
143
|
|
|
} |
144
|
|
|
|
145
|
|
|
private function report($_path, $lineNumber) |
146
|
|
|
{ |
147
|
|
|
app(ErrorPrinter::class)->simplePendError('', $_path, $lineNumber, 'ns_replacement', 'Namespace replacement:'); |
148
|
|
|
} |
149
|
|
|
|
150
|
|
|
private function printErrorsCount($errorPrinter, $time) |
151
|
|
|
{ |
152
|
|
|
if ($errorCount = $errorPrinter->errorsList['total']) { |
153
|
|
|
$this->warn(PHP_EOL.$errorCount.' error(s) found in namespaces'); |
154
|
|
|
} else { |
155
|
|
|
$this->noErrorFound($time); |
156
|
|
|
} |
157
|
|
|
} |
158
|
|
|
|
159
|
|
|
private function reportResult($autoload) |
160
|
|
|
{ |
161
|
|
|
$this->getOutput()->writeln(''); |
162
|
|
|
$this->getOutput()->writeln('<fg=green>Finished!</fg=green>'); |
163
|
|
|
$this->getOutput()->writeln('=============================='); |
164
|
|
|
$this->getOutput()->writeln('<options=bold;fg=yellow>'.CheckNamespaces::$checkedNamespaces.' classes were checked under:</>'); |
165
|
|
|
$this->getOutput()->writeln(' - '.implode("\n - ", array_keys($autoload)).''); |
166
|
|
|
} |
167
|
|
|
|
168
|
|
|
private function noErrorFound($time) |
169
|
|
|
{ |
170
|
|
|
$time = microtime(true) - $time; |
171
|
|
|
$this->line(PHP_EOL.'<fg=green>All namespaces are correct!</><fg=blue> You rock \(^_^)/ </>'); |
172
|
|
|
$this->line('<fg=red;options=bold>'.round($time, 5).'(s)</>'); |
173
|
|
|
$this->line(''); |
174
|
|
|
} |
175
|
|
|
} |
176
|
|
|
|
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.