Completed
Pull Request — master (#94)
by James
05:34 queued 04:08
created

FixMissingSemicolonSolution::getRunParameters()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 8
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
namespace Facade\Ignition\Solutions;
4
5
use Facade\IgnitionContracts\RunnableSolution;
6
use Illuminate\Support\Str;
7
8
class FixMissingSemicolonSolution implements RunnableSolution
9
{
10
    private $filePath;
11
    private $lineNumber;
12
    private $unexpected;
13
14
    public function __construct($filePath = null, $lineNumber = null, $unexpected = null)
15
    {
16
        $this->filePath = $filePath;
17
        $this->lineNumber = $lineNumber;
18
        $this->unexpected = $unexpected;
19
    }
20
21
    public function getSolutionTitle(): string
22
    {
23
        return 'You are missing a semicolon.';
24
    }
25
26
    public function getDocumentationLinks(): array
27
    {
28
        return [];
29
    }
30
31
    public function getSolutionActionDescription(): string
32
    {
33
        return 'Each instruction requires termination with a semicolon.';
34
    }
35
36
    public function getRunButtonText(): string
37
    {
38
        return 'Insert missing semicolon';
39
    }
40
41
    public function getSolutionDescription(): string
42
    {
43
        return '';
44
    }
45
46
    public function getRunParameters(): array
47
    {
48
        return [
49
            'filePath' => $this->filePath,
50
            'lineNumber' => $this->lineNumber,
51
            'unexpected' => $this->unexpected,
52
        ];
53
    }
54
55
    public function isRunnable()
56
    {
57
        return $this->insertSemicolon($this->getRunParameters()) !== false;
58
    }
59
60
    public function run(array $parameters = [])
61
    {
62
        $output = $this->insertSemicolon($parameters);
63
        if ($output !== false) {
64
            file_put_contents(base_path().$parameters['filePath'], $output);
65
        }
66
    }
67
68
    public function insertSemicolon(array $parameters = [])
69
    {
70
        if (strpos($parameters['filePath'], 'ignition/tests/stubs') !== false) {
71
            $file = $parameters['filePath'];
72
        } else {
73
            $file = base_path().$parameters['filePath'];
74
        }
75
        if (! is_file($file)) {
76
            return false;
77
        }
78
        $contents = file_get_contents($file);
79
        $tokens = token_get_all($contents);
80
81
        $proposedFix = $this->generateProposedFileFromTokens($tokens, $parameters['lineNumber'], $parameters['unexpected']);
82
        $result = exec(sprintf('echo %s | php -l', escapeshellarg($proposedFix)), $output, $exit);
83
84
        if (! Str::contains($result, 'No syntax errors')) {
85
            return false;
86
        }
87
88
        return $proposedFix;
89
    }
90
91
    protected function generateProposedFileFromTokens(array $tokens, int $lineNumber, string $unexpectedChar): string
92
    {
93
        $reverseTokens = array_reverse($tokens);
94
        $output = [];
95
        $insertSemicolon = false;
96
        $line = 0;
97
        foreach ($reverseTokens as $token) {
98
            $char = isset($token[1]) ? $token[1] : $token;
99
100
            $output[] = $char;
101
102
            if (isset($token[2])) {
103
                $line = $token[2];
104
            }
105
            if (is_string($token) && $line == $lineNumber && $char == $unexpectedChar) {
106
                $insertSemicolon = true;
107
            }
108
            if ($insertSemicolon && isset($token[0]) && $token[0] == T_WHITESPACE) {
109
                $insertSemicolon = false;
110
                $output[] = ';';
111
            }
112
        }
113
114
        return implode('', array_reverse($output));
115
    }
116
}
117