CompleteEngine   A
last analyzed

Complexity

Total Complexity 19

Size/Duplication

Total Lines 162
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 11

Importance

Changes 0
Metric Value
wmc 19
lcom 1
cbo 11
dl 0
loc 162
rs 10
c 0
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 18 1
B createCompletion() 0 41 5
A findEntries() 0 10 2
A prepareContent() 0 11 2
C processFileContent() 0 46 8
A isValidCache() 0 6 1
1
<?php
2
3
namespace Padawan\Framework\Complete;
4
5
use Padawan\Domain\Project;
6
use Padawan\Domain\Project\File;
7
use Padawan\Domain\Scope;
8
use Padawan\Domain\Scope\FileScope;
9
use Padawan\Domain\Project\FQN;
10
use Padawan\Parser\Parser;
11
use Padawan\Domain\Generator\IndexGenerator;
12
use Padawan\Domain\Completer\CompleterFactory;
13
use Padawan\Framework\Complete\Resolver\ContextResolver;
14
use Padawan\Parser\Walker\IndexGeneratingWalker;
15
use Padawan\Parser\Walker\ScopeWalker;
16
use Psr\Log\LoggerInterface;
17
18
class CompleteEngine
19
{
20
    public function __construct(
21
        Parser $parser,
22
        IndexGenerator $generator,
23
        ContextResolver $contextResolver,
24
        CompleterFactory $completer,
25
        IndexGeneratingWalker $indexGeneratingWalker,
26
        ScopeWalker $scopeWalker,
27
        LoggerInterface $logger
28
    ) {
29
        $this->parser                   = $parser;
30
        $this->generator                = $generator;
31
        $this->contextResolver          = $contextResolver;
32
        $this->completerFactory         = $completer;
33
        $this->indexGeneratingWalker    = $indexGeneratingWalker;
34
        $this->scopeWalker              = $scopeWalker;
35
        $this->logger                   = $logger;
36
        $this->cachePool                = [];
37
    }
38
    public function createCompletion(
39
        Project $project,
40
        $content,
41
        $line,
42
        $column,
43
        $file
44
    ) {
45
        $start = microtime(1);
46
        $entries = [];
47
        if ($line) {
48
            list($lines,, $completionLine) = $this->prepareContent(
49
                $content,
50
                $line,
51
                $column
52
            );
53
            try {
54
                $scope = $this->processFileContent($project, $lines, $line, $file);
55
                if (empty($scope)) {
56
                    $scope = new FileScope(new FQN);
57
                }
58
                $this->logger->debug(sprintf(
59
                    "%s seconds for ast processing",
60
                    (microtime(1) - $start)
61
                ));
62
            } catch (\Exception $e) {
63
                $scope = new FileScope(new FQN);
64
            }
65
            $entries = $this->findEntries($project, $scope, $completionLine, $column);
66
            $this->logger->debug(sprintf(
67
                "%s seconds for entries generation",
68
                (microtime(1) - $start)
69
            ));
70
        } elseif (!empty($content)) {
71
            $this->processFileContent($project, $content, $line, $file);
72
        }
73
74
        return [
75
            "entries" => $entries,
76
            "context" => []
77
        ];
78
    }
79
80
    /**
81
     * @param string $badLine
82
     */
83
    protected function findEntries(Project $project, Scope $scope, $badLine, $column)
84
    {
85
        $context = $this->contextResolver->getContext($badLine, $project->getIndex(), $scope);
86
        $completers = $this->completerFactory->getCompleters($project, $context);
87
        $entries = [];
88
        foreach($completers as $completer) {
89
            $entries = array_merge($entries, $completer->getEntries($project, $context));
90
        }
91
        return $entries;
92
    }
93
    /**
94
     * @TODO
95
     * Should check for bad lines
96
     */
97
    protected function prepareContent($content, $line, $column) {
98
        $lines = explode(PHP_EOL, $content);
99
        if ($line > count($lines)) {
100
            $badLine = "";
101
        } else {
102
            $badLine = $lines[$line - 1];
103
        }
104
        $completionLine = substr($badLine, 0, $column - 1);
105
        $lines[$line - 1] = "";
106
        return [$lines, trim($badLine), trim($completionLine)];
107
    }
108
109
    /**
110
     * @return Scope
111
     */
112
    protected function processFileContent(Project $project, $lines, $line, $filePath) {
113
        if (is_array($lines)) {
114
            $content = implode("\n", $lines);
115
        } else {
116
            $content = $lines;
117
        }
118
        if (empty($content)) {
119
            return;
120
        }
121
        if (!array_key_exists($filePath, $this->cachePool)) {
122
            $this->cachePool[$filePath] = [0, [], []];
123
        }
124
        if ($this->isValidCache($filePath, $content)) {
125
            list(,$fileScope, $scope) = $this->cachePool[$filePath];
0 ignored issues
show
Unused Code introduced by
The assignment to $fileScope is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
126
        }
127
        $index = $project->getIndex();
128
        $file = $index->findFileByPath($filePath);
129
        $hash = sha1($content);
130
        if (empty($file)) {
131
            $file = new File($filePath);
132
        }
133
        if (empty($scope)) {
134
            $parser = $this->parser;
135
            $parser->addWalker($this->indexGeneratingWalker);
136
            $parser->setIndex($project->getIndex());
137
            $fileScope = $parser->parseContent($filePath, $content);
138
            $this->generator->processFileScope(
139
                $file,
140
                $project->getIndex(),
141
                $fileScope,
142
                $hash
0 ignored issues
show
Unused Code introduced by
The call to IndexGenerator::processFileScope() has too many arguments starting with $hash.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
143
            );
144
            /** @var \Padawan\Domain\Project\Node\Uses */
145
            $uses = $parser->getUses();
146
            $this->scopeWalker->setLine($line);
147
            $parser->addWalker($this->scopeWalker);
148
            $parser->setIndex($project->getIndex());
149
            $scope = $parser->parseContent($filePath, $content, $uses);
150
            $contentHash = hash('sha1', $content);
151
            $this->cachePool[$filePath] = [$contentHash, $fileScope, $scope];
152
        }
153
        if ($scope) {
154
            return $scope;
155
        }
156
        return null;
157
    }
158
159
    private function isValidCache($file, $content)
160
    {
161
        $contentHash = hash('sha1', $content);
162
        list($hash) = $this->cachePool[$file];
163
        return $hash === $contentHash;
164
    }
165
166
    /** @var Parser */
167
    private $parser;
168
    /** @property IndexGenerator */
169
    private $generator;
170
    private $contextResolver;
171
    private $completerFactory;
172
    /** @property IndexGeneratingWalker */
173
    private $indexGeneratingWalker;
174
    /** @property ScopeWalker */
175
    private $scopeWalker;
176
    private $cachePool;
177
    /** @var LoggerInterface */
178
    private $logger;
179
}
180