CheckCompact::checkPsr4Classes()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 10
rs 9.9332
c 0
b 0
f 0
cc 3
nc 3
nop 0
1
<?php
2
3
namespace Imanghafoori\LaravelMicroscope\Commands;
4
5
use Illuminate\Console\Command;
6
use Imanghafoori\LaravelMicroscope\Analyzers\ComposerJson;
7
use Imanghafoori\LaravelMicroscope\Analyzers\FunctionCall;
8
use Imanghafoori\LaravelMicroscope\Analyzers\Ifs;
9
use Imanghafoori\LaravelMicroscope\Analyzers\TokenManager;
10
use Imanghafoori\LaravelMicroscope\ErrorReporters\ErrorPrinter;
11
use Imanghafoori\LaravelMicroscope\ErrorTypes\CompactCall;
12
use Imanghafoori\LaravelMicroscope\LaravelPaths\FilePath;
13
use Imanghafoori\LaravelMicroscope\SpyClasses\RoutePaths;
14
15
class CheckCompact extends Command
16
{
17
    protected $signature = 'check:compact';
18
19
    protected $description = 'Checks that compact() function calls are correct';
20
21
    public function handle()
22
    {
23
        event('microscope.start.command');
24
        $this->info('Checking compact() calls, fast and furious!  mm(~_~)mm  ');
25
26
        $this->checkRoutePaths(RoutePaths::get());
27
        $this->checkPsr4Classes();
28
29
        event('microscope.finished.checks', [$this]);
30
31
        return app(ErrorPrinter::class)->hasErrors() ? 1 : 0;
32
    }
33
34
    private function checkPathForCompact($absPath)
35
    {
36
        $tokens = token_get_all(file_get_contents($absPath));
37
38
        foreach ($tokens as $i => $token) {
39
            if ($tokens[$i][0] != T_FUNCTION) {
40
                continue;
41
            }
42
43
            $methodBody = $this->readMethodBodyAsTokens($tokens, $i);
44
45
            if ($methodBody === false) {
46
                continue;
47
            }
48
49
            $signatureVars = $this->collectSignatureVars($tokens, $i);
50
            $this->checkMethodBodyForCompact($absPath, $methodBody, $signatureVars);
51
        }
52
    }
53
54
    private function checkRoutePaths($paths)
55
    {
56
        foreach ($paths as $filePath) {
57
            $this->checkPathForCompact($filePath);
58
        }
59
    }
60
61
    private function checkPsr4Classes()
62
    {
63
        $psr4 = ComposerJson::readAutoload();
64
65
        foreach ($psr4 as $_namespace => $dirPath) {
66
            foreach (FilePath::getAllPhpFiles($dirPath) as $filePath) {
67
                $this->checkPathForCompact($filePath->getRealPath());
68
            }
69
        }
70
    }
71
72
    private function checkMethodBodyForCompact($absPath, $methodBody, $vars)
73
    {
74
        foreach ($methodBody as $c => $token) {
75
            ($token[0] == T_VARIABLE) && $vars[$token[1]] = null;
76
77
            if (! ($pp = FunctionCall::isGlobalCall('compact', $methodBody, $c))) {
78
                continue;
79
            }
80
81
            [, $compactedVars,] = Ifs::readCondition($methodBody, $pp);
0 ignored issues
show
Bug introduced by
The variable $compactedVars 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...
82
            $compactVars = [];
83
            foreach ($compactedVars as $uu => $var) {
84
                $var[0] == T_CONSTANT_ENCAPSED_STRING && $compactVars[] = '$'.\trim($var[1], '\'\"');
85
            }
86
            $compactVars = array_flip($compactVars);
87
88
            unset($vars['$this']);
89
            $missingVars = array_diff_key($compactVars, $vars);
90
            $missingVars && CompactCall::isMissing($absPath, $methodBody[$pp][2], $missingVars);
0 ignored issues
show
Bug Best Practice introduced by
The expression $missingVars of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
91
        }
92
    }
93
94
    private function collectSignatureVars($tokens, $i)
95
    {
96
        [, $signatures,] = Ifs::readCondition($tokens, $i);
0 ignored issues
show
Bug introduced by
The variable $signatures 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...
97
98
        $vars = [];
99
        foreach ($signatures as $sig) {
100
            ($sig[0] == T_VARIABLE) && $vars[$sig[1]] = null;
101
        }
102
103
        return $vars;
104
    }
105
106
    private function readMethodBodyAsTokens($tokens, $i)
107
    {
108
        // fast-forward to the start of function body
109
        [$char, $methodBodyStartIndex] = TokenManager::forwardTo($tokens, $i, ['{', ';']);
0 ignored issues
show
Bug introduced by
The variable $char 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 $methodBodyStartIndex 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...
110
111
        // in order to avoid checking abstract methods (with no body) and do/while
112
        if ($char === ';') {
113
            return false;
114
        }
115
116
        try {
117
            // fast-forward to the end of function body
118
            [$methodBody,] = TokenManager::readBody($tokens, $methodBodyStartIndex);
0 ignored issues
show
Bug introduced by
The variable $methodBody 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...
119
120
            return $methodBody;
121
        } catch (\Exception $e) {
122
            return false;
123
        }
124
    }
125
}
126