nazonohito51 /
dependency-analyzer
| 1 | <?php |
||
| 2 | declare(strict_types=1); |
||
| 3 | |||
| 4 | namespace DependencyAnalyzer; |
||
| 5 | |||
| 6 | use DependencyAnalyzer\DependencyDumper\CollectDependenciesVisitor; |
||
| 7 | use DependencyAnalyzer\DependencyDumper\NullObserver; |
||
| 8 | use DependencyAnalyzer\DependencyDumper\ObserverInterface; |
||
| 9 | use DependencyAnalyzer\Exceptions\AnalyzedFileException; |
||
| 10 | use PHPStan\AnalysedCodeException; |
||
| 11 | use PHPStan\Analyser\ScopeContext; |
||
| 12 | use PHPStan\Parser\Parser; |
||
| 13 | use PHPStan\Analyser\NodeScopeResolver; |
||
| 14 | use PHPStan\Analyser\ScopeFactory; |
||
| 15 | use PHPStan\DependencyInjection\ContainerFactory; |
||
| 16 | use PHPStan\File\FileFinder; |
||
| 17 | use PHPStan\ShouldNotHappenException; |
||
| 18 | |||
| 19 | class DependencyDumper |
||
| 20 | { |
||
| 21 | /** |
||
| 22 | * @var CollectDependenciesVisitor |
||
| 23 | */ |
||
| 24 | protected $collectNodeVisitor; |
||
| 25 | |||
| 26 | /** |
||
| 27 | * @var NodeScopeResolver |
||
| 28 | */ |
||
| 29 | protected $nodeScopeResolver; |
||
| 30 | |||
| 31 | /** |
||
| 32 | * @var Parser |
||
| 33 | */ |
||
| 34 | protected $parser; |
||
| 35 | |||
| 36 | /** |
||
| 37 | * @var ScopeFactory |
||
| 38 | */ |
||
| 39 | protected $scopeFactory; |
||
| 40 | |||
| 41 | /** |
||
| 42 | * @var FileFinder |
||
| 43 | */ |
||
| 44 | protected $fileFinder; |
||
| 45 | |||
| 46 | /** |
||
| 47 | * @var ObserverInterface |
||
| 48 | */ |
||
| 49 | protected static $observer = null; |
||
| 50 | |||
| 51 | public function __construct( |
||
| 52 | NodeScopeResolver $nodeScopeResolver, |
||
| 53 | Parser $parser, |
||
| 54 | ScopeFactory $scopeFactory, |
||
| 55 | FileFinder $fileFinder, |
||
| 56 | CollectDependenciesVisitor $collectNodeVisitor |
||
| 57 | ) |
||
| 58 | { |
||
| 59 | $this->nodeScopeResolver = $nodeScopeResolver; |
||
| 60 | $this->parser = $parser; |
||
| 61 | $this->scopeFactory = $scopeFactory; |
||
| 62 | $this->fileFinder = $fileFinder; |
||
| 63 | $this->collectNodeVisitor = $collectNodeVisitor; |
||
| 64 | } |
||
| 65 | |||
| 66 | public static function createFromConfig(string $currentDir, string $tmpDir, array $additionalConfigFiles): self |
||
| 67 | { |
||
| 68 | $phpStanContainer = (new ContainerFactory($currentDir))->create($tmpDir, $additionalConfigFiles, []); |
||
| 69 | |||
| 70 | return new self( |
||
| 71 | $phpStanContainer->getByType(NodeScopeResolver::class), |
||
| 72 | $phpStanContainer->getByType(Parser::class), |
||
| 73 | $phpStanContainer->getByType(ScopeFactory::class), |
||
| 74 | $phpStanContainer->getByType(FileFinder::class), |
||
| 75 | $phpStanContainer->getByType(CollectDependenciesVisitor::class) |
||
| 76 | ); |
||
| 77 | } |
||
| 78 | |||
| 79 | public function dump(array $paths, array $excludePaths = []): DependencyGraph |
||
| 80 | { |
||
| 81 | $excludeFiles = $this->getAllFilesRecursive($excludePaths); |
||
| 82 | $files = $this->getAllFilesRecursive($paths); |
||
| 83 | |||
| 84 | $this->notifyDumpStart(array_reduce($files, function (int $max, string $file) use ($excludeFiles) { |
||
| 85 | if (!in_array($file, $excludeFiles)) { |
||
| 86 | $max++; |
||
| 87 | } |
||
| 88 | |||
| 89 | return $max; |
||
| 90 | }, 0)); |
||
| 91 | foreach ($files as $file) { |
||
| 92 | if (!in_array($file, $excludeFiles)) { |
||
| 93 | $this->notifyCurrentFile($file); |
||
| 94 | |||
| 95 | try { |
||
| 96 | $this->dumpFile($file); |
||
| 97 | } catch (AnalyzedFileException $e) { |
||
| 98 | $this->notifyAnalyzedFileException($e); |
||
| 99 | } |
||
| 100 | } |
||
| 101 | } |
||
| 102 | $this->notifyDumpEnd(); |
||
| 103 | |||
| 104 | return $this->collectNodeVisitor->getDependencyGraphBuilder()->build(); |
||
| 105 | } |
||
| 106 | |||
| 107 | protected function dumpFile(string $file): void |
||
| 108 | { |
||
| 109 | try { |
||
| 110 | $this->collectNodeVisitor->setFile($file); |
||
| 111 | |||
| 112 | // collect dependencies in $this->collectNodeVisitor |
||
| 113 | $this->nodeScopeResolver->processNodes( |
||
| 114 | $this->parser->parseFile($file), |
||
| 115 | $this->scopeFactory->create(ScopeContext::create($file)), |
||
| 116 | \Closure::fromCallable($this->collectNodeVisitor) // type hint of processNodes() is \Closure... |
||
| 117 | ); |
||
| 118 | } catch (ShouldNotHappenException $e) { |
||
| 119 | throw new AnalyzedFileException($file, 'analyzing file is failed, because unexpected error', 0, $e); |
||
| 120 | } catch (AnalysedCodeException $e) { |
||
| 121 | throw new AnalyzedFileException($file, 'analyzing file is failed, because unexpected error', 0, $e); |
||
| 122 | } |
||
| 123 | } |
||
| 124 | |||
| 125 | protected function getAllFilesRecursive(array $paths): array |
||
| 126 | { |
||
| 127 | try { |
||
| 128 | $fileFinderResult = $this->fileFinder->findFiles($paths); |
||
| 129 | } catch (\PHPStan\File\PathNotFoundException $e) { |
||
| 130 | throw new AnalyzedFileException($e->getPath(), 'path was not found.', 0, $e); |
||
| 131 | } |
||
| 132 | |||
| 133 | return $fileFinderResult->getFiles(); |
||
| 134 | } |
||
| 135 | |||
| 136 | public function setObserver(ObserverInterface $observer = null): self |
||
| 137 | { |
||
| 138 | self::$observer = $observer; |
||
| 139 | $this->collectNodeVisitor->getDependencyGraphBuilder()->setObserver($observer); |
||
|
0 ignored issues
–
show
Bug
introduced
by
Loading history...
|
|||
| 140 | |||
| 141 | return $this; |
||
| 142 | } |
||
| 143 | |||
| 144 | /** |
||
| 145 | * @return ObserverInterface |
||
| 146 | * @da-internal \DependencyAnalyzer\DependencyDumper |
||
| 147 | * @da-internal \DependencyAnalyzer\DependencyDumper\ |
||
| 148 | */ |
||
| 149 | public static function getObserver(): ObserverInterface |
||
| 150 | { |
||
| 151 | if (!is_null(self::$observer)) { |
||
| 152 | return self::$observer; |
||
| 153 | } |
||
| 154 | |||
| 155 | return new NullObserver(); |
||
| 156 | } |
||
| 157 | |||
| 158 | protected function notifyDumpStart(int $max): void |
||
| 159 | { |
||
| 160 | self::getObserver()->start($max); |
||
| 161 | } |
||
| 162 | |||
| 163 | protected function notifyCurrentFile(string $file): void |
||
| 164 | { |
||
| 165 | self::getObserver()->update($file); |
||
| 166 | } |
||
| 167 | |||
| 168 | protected function notifyAnalyzedFileException(AnalyzedFileException $e): void |
||
| 169 | { |
||
| 170 | self::getObserver()->notifyAnalyzeFileError($e); |
||
| 171 | } |
||
| 172 | |||
| 173 | protected function notifyDumpEnd(): void |
||
| 174 | { |
||
| 175 | self::getObserver()->end(); |
||
| 176 | } |
||
| 177 | } |
||
| 178 |