Completed
Pull Request — master (#94)
by James
01:30
created

FixMissingSemicolonSolution   A

Complexity

Total Complexity 23

Size/Duplication

Total Lines 106
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Importance

Changes 0
Metric Value
wmc 23
lcom 1
cbo 1
dl 0
loc 106
rs 10
c 0
b 0
f 0

10 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A getSolutionTitle() 0 4 1
A getDocumentationLinks() 0 4 1
A getSolutionActionDescription() 0 4 1
A getRunButtonText() 0 4 1
A getSolutionDescription() 0 4 1
A getRunParameters() 0 8 1
A isRunnable() 0 4 1
A run() 0 7 2
C insertSemicolon() 0 45 13
1
<?php
2
3
namespace Facade\Ignition\Solutions;
4
5
use Illuminate\Support\Str;
6
use Facade\IgnitionContracts\RunnableSolution;
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(app_path().$parameters['filePath'], $output);
65
        }
66
    }
67
68
    public function insertSemicolon(array $parameters = [])
69
    {
70
        if (strpos($parameters['filePath'], 'ignition/tests/Solutions') !== false) {
71
            $file = $parameters['filePath'];
72
        } else {
73
            $file = app_path().$parameters['filePath'];
74
        }
75
76
        if (! is_file($file)) {
77
            return false;
78
        }
79
        $contents = file_get_contents($file);
80
        $tokens = token_get_all($contents);
81
82
        $reverseTokens = array_reverse($tokens);
83
84
        $output = [];
85
        $insertSemicolon = false;
86
        $line = 0;
87
        foreach ($reverseTokens as $token) {
88
            $char = isset($token[1]) ? $token[1] : $token;
89
90
            $output[] = $char;
91
92
            if (isset($token[2])) {
93
                $line = $token[2];
94
            }
95
            if (is_string($token) && $line == $parameters['lineNumber'] && $char == $parameters['unexpected']) {
96
                $insertSemicolon = true;
97
            }
98
            if ($insertSemicolon && isset($token[0]) && $token[0] == T_WHITESPACE) {
99
                $insertSemicolon = false;
100
                $output[] = ';';
101
            }
102
        }
103
        $proposedFix = implode('', array_reverse($output));
104
105
        $result = exec(sprintf('echo %s | php -l', escapeshellarg($proposedFix)), $output, $exit);
106
107
        if (Str::contains($result, 'No syntax errors')) {
108
            return $proposedFix;
109
        }
110
111
        return false;
112
    }
113
}
114