Passed
Push — master ( 65484c...fedbc6 )
by Satoshi
02:08
created

DependencyDumper::notifyAnalyzedFileException()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
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, 'analysing file is failed, because unexpected error', 0, $e);
120
        } catch (AnalysedCodeException $e) {
121
            throw new AnalyzedFileException($file, 'analysing 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
It seems like $observer can also be of type null; however, parameter $observer of DependencyAnalyzer\Depen...hBuilder::setObserver() does only seem to accept DependencyAnalyzer\Depen...ilder\ObserverInterface, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

139
        $this->collectNodeVisitor->getDependencyGraphBuilder()->setObserver(/** @scrutinizer ignore-type */ $observer);
Loading history...
140
141
        return $this;
142
    }
143
144
    /**
145
     * @return ObserverInterface
146
     * @deps-internal \DependencyAnalyzer\DependencyDumper
147
     * @deps-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