Passed
Push — master ( 9251f2...ca8fc4 )
by Herberto
03:14
created

PDependAdapter::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 5
ccs 4
cts 4
cp 1
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 3
nc 1
nop 2
crap 1
1
<?php
2
3
namespace Hgraca\Phorensic\Miner\Code\PDepend;
4
5
use Hgraca\Helper\StringHelper;
6
use Hgraca\Phorensic\Miner\Code\CodeMinerInterface;
7
use Hgraca\Phorensic\SharedKernel\Port\FileSystem\Adapter\FileSystem\FileSystemAdapter;
8
use Hgraca\Phorensic\SharedKernel\Port\FileSystem\FileSystemInterface;
9
use PDepend\Application;
10
use PDepend\Engine;
11
use PDepend\Metrics\Analyzer;
12
use PDepend\Metrics\Analyzer\ClassLevelAnalyzer;
13
use PDepend\Report\CodeAwareGenerator;
14
use PDepend\Source\AST\AbstractASTClassOrInterface;
15
use PDepend\Source\AST\ASTArtifact;
16
use PDepend\Source\AST\ASTArtifactList;
17
use PDepend\Source\AST\ASTClass;
18
use PDepend\Source\AST\ASTInterface;
19
use PDepend\Source\ASTVisitor\AbstractASTVisitor;
20
21
final class PDependAdapter extends AbstractASTVisitor implements CodeAwareGenerator, CodeMinerInterface
22
{
23
    /** @var ClassLevelAnalyzer[] */
24
    private $analyzers;
25
26
    /** @var ASTArtifactList */
27
    private $artifacts;
28
29
    /** @var array ['filePath' => ['metricA' => value, 'metricB' => value, ...]] */
30
    private $sourceFileMetricsList = [];
31
32
    /** @var FileSystemInterface */
33
    private $fileSystem;
34
35
    /** @var Engine */
36
    private $pdepend;
37
38
    /** @var string[] */
39
    private static $unsupportedTokenList = ['class(', 'yield'];
40
41 1
    public function __construct(Engine $pdepend = null, FileSystemInterface $fileSystem = null)
42
    {
43 1
        $this->fileSystem = $fileSystem ?? new FileSystemAdapter();
44 1
        $this->pdepend = $pdepend ?? (new Application())->getEngine();
45 1
    }
46
47
    /**
48
     * @param string[] $filePathList
49
     */
50 1
    public function mine(array $filePathList, string $basePath = ''): array
51
    {
52 1
        $basePath = rtrim($basePath, '/') . '/';
53
54 1
        foreach ($filePathList as $filePath) {
55 1
            $filePath = $basePath . $filePath;
56 1
            if ($this->fileCanNotBeHandledByPdepend($filePath)) {
57 1
                continue;
58
            }
59 1
            $this->pdepend->addFile($filePath);
60
        }
61
62 1
        $this->pdepend->addReportGenerator($this);
63 1
        $this->pdepend->analyze();
64
65 1
        if ($basePath !== '') {
66 1
            $this->sourceFileMetricsList = $this->removeBasePathFromBeginningOfAllPaths(
67
                $basePath,
68 1
                $this->sourceFileMetricsList
69
            );
70
        }
71
72 1
        return $this->sourceFileMetricsList;
73
    }
74
75
    /**
76
     * Sets the context code nodes.
77
     *
78
     * @codeCoverageIgnore
79
     */
80
    public function setArtifacts(ASTArtifactList $artifacts)
81
    {
82
        $this->artifacts = $artifacts;
83
    }
84
85
    /**
86
     * Adds an analyzer to log. If this logger accepts the given analyzer it
87
     * with return <b>true</b>, otherwise the return value is <b>false</b>.
88
     *
89
     * @codeCoverageIgnore
90
     *
91
     * @return boolean
92
     */
93
    public function log(Analyzer $analyzer)
94
    {
95
        $this->analyzers[] = $analyzer;
96
97
        return true;
98
    }
99
100
    /**
101
     * Closes the logger process and writes the output file.
102
     *
103
     * @codeCoverageIgnore
104
     */
105
    public function close()
106
    {
107
        foreach ($this->artifacts as $node) {
108
            $node->accept($this);
109
        }
110
    }
111
112
    /**
113
     * Returns an <b>array</b> with accepted analyzer types. These types can be
114
     * concrete analyzer classes or one of the descriptive analyzer interfaces.
115
     *
116
     * @codeCoverageIgnore
117
     *
118
     * @return string[]
119
     */
120
    public function getAcceptedAnalyzers()
121
    {
122
        return [
123
            'pdepend.analyzer.cyclomatic_complexity',
124
            'pdepend.analyzer.node_loc',
125
            'pdepend.analyzer.npath_complexity',
126
            'pdepend.analyzer.inheritance',
127
            'pdepend.analyzer.node_count',
128
            'pdepend.analyzer.hierarchy',
129
            'pdepend.analyzer.crap_index',
130
            'pdepend.analyzer.code_rank',
131
            'pdepend.analyzer.coupling',
132
            'pdepend.analyzer.class_level',
133
            'pdepend.analyzer.cohesion',
134
        ];
135
    }
136
137
    /**
138
     * Visits a class node.
139
     *
140
     * @codeCoverageIgnore
141
     */
142
    public function visitClass(ASTClass $node)
143
    {
144
        $this->visitFile($node);
145
146
        parent::visitClass($node);
147
    }
148
149
    /**
150
     * Visits an interface node.
151
     *
152
     * @codeCoverageIgnore
153
     */
154
    public function visitInterface(ASTInterface $node)
155
    {
156
        $this->visitFile($node);
157
158
        parent::visitInterface($node);
159
    }
160
161
    /**
162
     * @codeCoverageIgnore
163
     */
164
    private function visitFile(AbstractASTClassOrInterface $node)
165
    {
166
        if (!$node->isUserDefined()) {
167
            return;
168
        }
169
170
        $this->sourceFileMetricsList[$node->getCompilationUnit()->getFileName()] = $this->collectMetrics($node);
171
    }
172
173
    /**
174
     * Collects the collected metrics for the given node and adds them to the <b>$node</b>.
175
     *
176
     * @codeCoverageIgnore
177
     */
178
    private function collectMetrics(ASTArtifact $node)
179
    {
180
        $metrics = [];
181
182
        foreach ($this->analyzers as $analyzer) {
183
            $metrics = array_merge($metrics, $analyzer->getNodeMetrics($node));
184
        }
185
186
        return $metrics;
187
    }
188
189
    /**
190
     * This method returns true if the given file contains a token that is not currently supported by pdepend
191
     */
192 1
    private function fileCanNotBeHandledByPdepend(string $filePath): bool
193
    {
194 1
        if (empty(self::$unsupportedTokenList)) {
195
            return false;
196
        }
197
198 1
        $fileContents = $this->fileSystem->readFile($filePath);
199 1
        foreach (self::$unsupportedTokenList as $unsupportedToken) {
200 1
            if (StringHelper::has($unsupportedToken, $fileContents)) {
201 1
                return true;
202
            }
203
        }
204
205 1
        return false;
206
    }
207
208 1
    private function removeBasePathFromBeginningOfAllPaths(string $basePath, array $sourceFileMetricsList)
209
    {
210 1
        $cleanedUpSourceFileMetricsList = [];
211 1
        foreach ($sourceFileMetricsList as $sourceFilePath => $sourceFileMetrics) {
212 1
            $cleanedUpSourceFilePath = StringHelper::removeFromBeginning($basePath, $sourceFilePath);
213 1
            $cleanedUpSourceFileMetricsList[$cleanedUpSourceFilePath] = $sourceFileMetrics;
214
        }
215 1
        return $cleanedUpSourceFileMetricsList;
216
    }
217
}
218