CodeCommand::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 3
cts 3
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
crap 1
1
<?php declare(strict_types=1);
2
3
namespace Bigwhoop\Trumpet\Commands;
4
5
use Bigwhoop\Trumpet\CodeParsing\Php\PhpCodeParser;
6
7
/**
8
 * !code file.php
9
 * !code file.php line 12
10
 * !code file.php lines 12 16
11
 * !code file.php function my_function_name
12
 * !code file.php class My\Class\Name
13
 * !code file.php method My\Class\Name myMethod.
14
 */
15
final class CodeCommand implements Command
16
{
17
    /** @var PhpCodeParser */
18
    private $parser;
19
20 1
    public function __construct(PhpCodeParser $parser)
21
    {
22 1
        $this->parser = $parser;
23 1
    }
24
    
25 1
    public function getToken(): string
26
    {
27 1
        return 'code';
28
    }
29
    
30 10
    public function execute(CommandParams $params, CommandExecutionContext $executionContext): string
31
    {
32 10
        $fileName = $params->getFirstArgument();
33
34 10
        if (is_readable($fileName)) {
35
            $contents = file_get_contents($fileName);
36
        } else {
37 10
            if (!$executionContext->hasFileInWorkingDirectory($fileName)) {
38
                throw new ExecutionFailedException("File '$fileName' does not exist.");
39
            }
40
41 10
            $contents = $executionContext->getContentsOfFileInWorkingDirectory($fileName);
42
        }
43
44 10
        switch ($params->getSecondArgument()) {
45 10
            case 'class':
46 2
                return $this->findClass($contents, $params, $fileName);
47
48 8
            case 'abstract':
49
                return $this->findAbstract($contents);
50
51 8
            case 'method':
52 4
                return $this->findMethod($contents, $params, $fileName);
53
54 4
            case 'function':
55 1
                return $this->findFunction($contents, $params, $fileName);
56
57 3
            case 'line':
58 2
                return $this->findLines($contents, $params);
59
60
            default:
61 1
                return $this->wrapLines($contents);
62
        }
63
    }
64
    
65 2
    private function findClass(string $contents, CommandParams $params, string $fileName): string
66
    {
67 2
        $className = $params->getArgument(2);
68 2
        $result = $this->parser->parse($contents);
69
70 2
        if (!$result->hasClass($className)) {
71 1
            $availableClasses = implode(', ', array_keys($result->getClasses()));
72 1
            throw new ExecutionFailedException("Class '$className' was not found in file '$fileName'. Available classes: $availableClasses");
73
        }
74
75 1
        return $this->wrapLines($result->getClass($className)->getSource());
76
    }
77
78
    private function findAbstract(string $contents): string
79
    {
80
        $result = $this->parser->parse($contents);
81
82
        $out = [];
83
84
        $classes = $result->getClasses();
85
        if (count($classes)) {
86
            $out[] = 'CLASSES ('.count($classes).')';
87
            foreach ($classes as $class) {
88
                $out[] = ' '.$class->getFullName();
89
                foreach ($class->getMethods() as $method) {
90
                    $out[] = '  '.($method->isStatic() ? 'static ' : '').$method->getName().'()';
91
                }
92
            }
93
        }
94
95
        $functions = $result->getFunctions();
96
        if (count($functions)) {
97
            if (!empty($out)) {
98
                $out[] = '';
99
            }
100
            $out[] = 'FUNCTIONS ('.count($functions).')';
101
            foreach ($functions as $function) {
102
                $out[] = ' '.$function->getFullName();
103
            }
104
        }
105
106
        return $this->wrapLines($out);
107
    }
108
    
109 4
    private function findMethod(string $contents, CommandParams $params, string $fileName): string
110
    {
111 4
        $className = $params->getArgument(2);
112 4
        $methodName = $params->getArgument(3);
113 4
        $result = $this->parser->parse($contents);
114
115 4
        if (!$result->hasClass($className)) {
116 1
            $availableClasses = implode(', ', array_keys($result->getClasses()));
117 1
            throw new ExecutionFailedException("Class '$className' was not found in file '$fileName'. Available classes: $availableClasses");
118
        }
119
120 3
        $class = $result->getClass($className);
121
122 3
        if (!$class->hasMethod($methodName)) {
123 1
            throw new ExecutionFailedException("Method '$methodName' of class '$className' was not found in file '$fileName'.");
124
        }
125
126 2
        return $this->wrapLines($class->getMethod($methodName)->getSource());
127
    }
128
129 1
    private function findFunction(string $contents, CommandParams $params, string $fileName): string
130
    {
131 1
        $functionName = $params->getArgument(2);
132 1
        $result = $this->parser->parse($contents);
133
134 1
        if (!$result->hasFunction($functionName)) {
135
            throw new ExecutionFailedException("Function '$functionName' was not found in file '$fileName'.");
136
        }
137
138 1
        return $this->wrapLines($result->getFunction($functionName)->getSource());
139
    }
140
    
141 2
    private function findLines(string $contents, CommandParams $params): string
142
    {
143 2
        $lines = explode("\n", $contents);
144 2
        $range = $params->getThirdArgument();
145
146 2
        if (is_numeric($range)) {
147 1
            return $this->wrapLines(array_slice($lines, $range - 1, 1));
148
        }
149
150 1
        $matches = [];
151 1
        if (!preg_match('|(\d+)-(\d+)|', $range, $matches)) {
152
            throw new ExecutionFailedException("Line definition '$range' is not valid. Must be in format N or N-N.");
153
        }
154
155 1
        $from = min([$matches[1], $matches[2]]);
156 1
        $to = max([$matches[1], $matches[2]]);
157
158 1
        return $this->wrapLines(array_slice($lines, $from - 1, $to - $from + 1));
159
    }
160
161
    /**
162
     * @param array|string $lines
163
     *
164
     * @return string
165
     */
166 7
    private function wrapLines($lines): string
167
    {
168 7
        if (!is_array($lines)) {
169 5
            $lines = explode("\n", $lines);
170
        }
171
172 7
        $indented = array_map(function ($e) {
173 7
            return '    '.$e;
174 7
        }, $lines);
175
176 7
        return implode("\n", $indented);
177
    }
178
}
179