Completed
Push — master ( fc34f9...5288c0 )
by Iman
02:03
created

checkImportedClasses()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 3
dl 0
loc 8
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Imanghafoori\LaravelMicroscope;
4
5
use Illuminate\Support\Composer;
6
use Illuminate\Support\Str;
7
use Imanghafoori\LaravelMicroscope\Analyzers\ComposerJson;
8
use Imanghafoori\LaravelMicroscope\Analyzers\FileManipulator;
9
use Imanghafoori\LaravelMicroscope\Analyzers\GetClassProperties;
10
use Imanghafoori\LaravelMicroscope\Analyzers\NamespaceCorrector;
11
use Imanghafoori\LaravelMicroscope\Analyzers\ParseUseStatement;
12
use Imanghafoori\LaravelMicroscope\ErrorReporters\ErrorPrinter;
13
14
class CheckClassReferencesAreValid
15
{
16
    public static function check($tokens, $absFilePath)
17
    {
18
        try {
19
            self::checkReferences($tokens, $absFilePath);
20
        } catch (\ErrorException $e) {
0 ignored issues
show
Bug introduced by
The class ErrorException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
21
            // In case a file is moved or deleted,
22
            // composer will need a dump autoload.
23
            if (! Str::endsWith($e->getFile(), 'vendor\composer\ClassLoader.php')) {
24
                throw $e;
25
            }
26
27
            self::warnDumping($e->getMessage());
28
            resolve(Composer::class)->dumpAutoloads();
29
        }
30
    }
31
32
    public static function warnDumping($msg)
33
    {
34
        $p = resolve(ErrorPrinter::class)->printer;
35
        $p->writeln('It seems composer has some trouble with autoload...');
36
        $p->writeln($msg);
37
        $p->writeln('Running "composer dump-autoload" command...  \(*_*)\  ');
38
    }
39
40
    private static function checkReferences($tokens, $absFilePath)
41
    {
42
        // If file is empty or does not begin with <?php
43
        if (($tokens[0][0] ?? null) !== T_OPEN_TAG) {
44
            return;
45
        }
46
47
        [
48
            $currentNamespace,
0 ignored issues
show
Bug introduced by
The variable $currentNamespace does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
49
            $class,
0 ignored issues
show
Bug introduced by
The variable $class does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
50
            $type,
0 ignored issues
show
Bug introduced by
The variable $type does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
51
            $parent,
0 ignored issues
show
Bug introduced by
The variable $parent does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
52
            $interfaces,
0 ignored issues
show
Bug introduced by
The variable $interfaces does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
53
        ] = GetClassProperties::readClassDefinition($tokens);
54
55
        // It means that, there is no class/trait definition found in the file.
56
        if (! $class) {
57
            return;
58
        }
59
60
        event('laravel_microscope.checking_file', [$absFilePath]);
61
        // @todo better to do it an event listener.
62
63
        self::checkAtSignStrings($tokens, $absFilePath);
64
65
        self::checkNotImportedClasses($tokens, $absFilePath);
66
67
        self::checkImportedClasses($currentNamespace, $class, $absFilePath);
68
    }
69
70
    private static function checkImportedClassesExist($imports, $absFilePath)
71
    {
72
        $printer = app(ErrorPrinter::class);
73
74
        foreach ($imports as $i => $import) {
75
            [$class, $line] = $import;
0 ignored issues
show
Bug introduced by
The variable $class does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $line does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
76
77
            if (! self::isAbsent($class)) {
78
                continue;
79
            }
80
81
            if (\is_dir(base_path(NamespaceCorrector::getRelativePathFromNamespace($class)))) {
82
                continue;
83
            }
84
85
            $isInUserSpace = Str::startsWith($class, array_keys(ComposerJson::readAutoload()));
86
87
            [$isCorrected, $corrects] = FileManipulator::fixReference($absFilePath, $class, $line, '', true);
0 ignored issues
show
Bug introduced by
The variable $isCorrected does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $corrects does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
88
89
            if ($isInUserSpace && $isCorrected) {
90
                $printer->printFixation($absFilePath, $class, $line, $corrects);
91
            } else {
92
                $printer->wrongImport($absFilePath, $class, $line);
93
            }
94
        }
95
    }
96
97
    public static function isAbsent($class)
98
    {
99
        return ! \class_exists($class) && ! \interface_exists($class) && ! \trait_exists($class);
100
    }
101
102
    protected static function fullNamespace($currentNamespace, $class)
103
    {
104
        return $currentNamespace ? $currentNamespace.'\\'.$class : $class;
105
    }
106
107
    public static function checkAtSignStrings($tokens, $absFilePath, $onlyAbsClassPath = false)
108
    {
109
        $printer = app(ErrorPrinter::class);
110
111
        foreach ($tokens as $token) {
112
            // If it is a string containing a single '@'
113
            if ($token[0] != T_CONSTANT_ENCAPSED_STRING || \substr_count($token[1], '@') != 1) {
114
                continue;
115
            }
116
117
            $trimmed = \trim($token[1], '\'\"');
118
119
            if ($onlyAbsClassPath && $trimmed[0] !== '\\') {
120
                continue;
121
            }
122
123
            [$class, $method] = \explode('@', $trimmed);
0 ignored issues
show
Bug introduced by
The variable $method does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $class does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
124
125
            if (\substr_count($class, '\\') <= 0) {
126
                continue;
127
            }
128
129
            if (Str::contains($trimmed, ['-', '/', '[', '*', '+', '.', '(', '$', '^'])) {
130
                continue;
131
            }
132
133
            if (! \class_exists($class)) {
134
                $isInUserSpace = Str::startsWith($class, \array_keys(ComposerJson::readAutoload()));
135
                $result = FileManipulator::fixReference($absFilePath, $class, $token[2]);
136
                if ($isInUserSpace && $result[0]) {
137
                    $printer->printFixation($absFilePath, $class, $token[2], $result[1]);
138
                } else {
139
                    $printer->wrongUsedClassError($absFilePath, $token[1], $token[2]);
140
                }
141
            } elseif (! \method_exists($class, $method)) {
142
                $printer->wrongMethodError($absFilePath, $trimmed, $token[2]);
143
            }
144
        }
145
    }
146
147
    private static function checkImportedClasses($currentNamespace, $class, $absPath)
148
    {
149
        $namespacedClassName = self::fullNamespace($currentNamespace, $class);
150
151
        $imports = ParseUseStatement::getUseStatementsByPath($namespacedClassName, $absPath);
152
153
        self::checkImportedClassesExist($imports, $absPath);
154
    }
155
156
    private static function fix($absFilePath, $class, $line, $namespace)
157
    {
158
        $baseClassName = \str_replace($namespace.'\\', '', $class);
159
160
        $result = FileManipulator::fixReference($absFilePath, $baseClassName, $line, '\\');
161
162
        if ($result[0]) {
163
            return $result;
164
        }
165
166
        return $result = FileManipulator::fixReference($absFilePath, $class, $line);
0 ignored issues
show
Unused Code introduced by
$result is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
167
    }
168
169
    private static function checkNotImportedClasses($tokens, $absFilePath)
170
    {
171
        [$nonImportedClasses, $namespace] = ParseUseStatement::findClassReferences($tokens, $absFilePath);
0 ignored issues
show
Bug introduced by
The variable $namespace does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $nonImportedClasses does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
172
173
        $printer = app(ErrorPrinter::class);
174
175
        loopStart:
176
        foreach ($nonImportedClasses as $nonImportedClass) {
177
            $class = $nonImportedClass['class'];
178
            $line = $nonImportedClass['line'];
179
180
            if (! self::isAbsent($class) || \function_exists($class)) {
181
                continue;
182
            }
183
184
            if (! ComposerJson::isInAppSpace($class)) {
185
                $printer->doesNotExist($class, $absFilePath, $line, 'wrongReference', 'Wrong Reference:');
186
                continue;
187
            }
188
189
            [$isFixed, $corrections] = self::fix($absFilePath, $class, $line, $namespace);
0 ignored issues
show
Bug introduced by
The variable $isFixed does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $corrections does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
190
191
            $method = $isFixed ? 'printFixation' : 'wrongImportPossibleFixes';
192
            $printer->$method($absFilePath, $class, $line, $corrections);
193
            if ($isFixed) {
194
                $tokens = token_get_all(file_get_contents($absFilePath));
195
                ([$nonImportedClasses, $namespace] = ParseUseStatement::findClassReferences($tokens, $absFilePath));
196
                goto loopStart;
197
            }
198
        }
199
    }
200
}
201