Completed
Pull Request — master (#80)
by Jan Philipp
01:46
created

ScriptLoader::loadScript()   C

Complexity

Conditions 10
Paths 14

Size

Total Lines 69

Duplication

Lines 8
Ratio 11.59 %

Importance

Changes 0
Metric Value
dl 8
loc 69
rs 6.8096
c 0
b 0
f 0
cc 10
nc 14
nop 1

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php declare(strict_types=1);
2
3
4
namespace Shopware\Psh\ScriptRuntime;
5
6
use Shopware\Psh\Listing\Script;
7
8
/**
9
 * Load scripts and parse it into commands
10
 */
11
class ScriptLoader
12
{
13
    const MODIFIER_IS_TTY = 'TTY: ';
14
15
    const MODIFIER_IGNORE_ERROR_PREFIX = 'I: ';
16
17
    const MODIFIER_DEFERRED_EXECUTION_PREFIX = 'D: ';
18
19
    const INCLUDE_STATEMENT_PREFIX = 'INCLUDE: ';
20
21
    const WAIT_STATEMENT = 'WAIT:';
22
23
    const TEMPLATE_STATEMENT_PREFIX = 'TEMPLATE: ';
24
25
    const CONCATENATE_PREFIX = '   ';
26
27
    /**
28
     * @var CommandBuilder
29
     */
30
    private $commandBuilder;
31
32
    /**
33
     * @param CommandBuilder $commandBuilder
34
     */
35
    public function __construct(CommandBuilder $commandBuilder)
36
    {
37
        $this->commandBuilder = $commandBuilder;
38
    }
39
40
    /**
41
     * @param Script $script
42
     * @return Command[]
43
     */
44
    public function loadScript(Script $script): array
45
    {
46
        $content = $this->loadFileContents($script->getPath());
47
        $lines = explode("\n", $content);
48
49
        foreach ($lines as $lineNumber => $currentLine) {
50
            $ignoreError = false;
51
            $tty = false;
52
            $deferred = false;
53
54
            if (!$this->isExecutableLine($currentLine)) {
55
                continue;
56
            }
57
58
            if ($this->startsWith(self::CONCATENATE_PREFIX, $currentLine)) {
59
                $this->commandBuilder->add($currentLine);
60
                continue;
61
            }
62
63
            if ($this->startsWith(self::INCLUDE_STATEMENT_PREFIX, $currentLine)) {
64
                $path = $this->findInclude($script, $this->removeFromStart(self::INCLUDE_STATEMENT_PREFIX, $currentLine));
65
                $includeScript = new Script(pathinfo($path, PATHINFO_DIRNAME), pathinfo($path, PATHINFO_BASENAME));
66
67
                $commands = $this->loadScript($includeScript);
68
                $this->commandBuilder->setCommands($commands);
69
70
                continue;
71
            }
72
73
            if ($this->startsWith(self::TEMPLATE_STATEMENT_PREFIX, $currentLine)) {
74
                $definition = $this->removeFromStart(self::TEMPLATE_STATEMENT_PREFIX, $currentLine);
75
                list($rawSource, $rawDestination) = explode(':', $definition);
76
77
                $source = $script->getDirectory() . '/' . $rawSource;
78
                $destination = $script->getDirectory() . '/' . $rawDestination;
79
80
                $this->commandBuilder
81
                    ->addTemplateCommand($source, $destination, $lineNumber);
82
83
                continue;
84
            }
85
86
            if ($this->startsWith(self::WAIT_STATEMENT, $currentLine)) {
87
                $this->commandBuilder
88
                    ->addWaitCommand($lineNumber);
89
                continue;
90
            }
91
92
            if ($this->startsWith(self::MODIFIER_IGNORE_ERROR_PREFIX, $currentLine)) {
93
                $currentLine = $this->removeFromStart(self::MODIFIER_IGNORE_ERROR_PREFIX, $currentLine);
94
                $ignoreError = true;
95
            }
96
97 View Code Duplication
            if ($this->startsWith(self::MODIFIER_IS_TTY, $currentLine)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
98
                $currentLine = $this->removeFromStart(self::MODIFIER_IS_TTY, $currentLine);
99
                $tty = true;
100
            }
101
102 View Code Duplication
            if ($this->startsWith(self::MODIFIER_DEFERRED_EXECUTION_PREFIX, $currentLine)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
103
                $currentLine = $this->removeFromStart(self::MODIFIER_DEFERRED_EXECUTION_PREFIX, $currentLine);
104
                $deferred = true;
105
            }
106
107
            $this->commandBuilder
108
                ->next($currentLine, $lineNumber, $ignoreError, $tty, $deferred);
109
        }
110
111
        return $this->commandBuilder->getAll();
112
    }
113
114
    /**
115
     * @param Script $fromScript
116
     * @param string $includeStatement
117
     * @return string
118
     */
119
    private function findInclude(Script $fromScript, string $includeStatement): string
120
    {
121
        if (file_exists($includeStatement)) {
122
            return $includeStatement;
123
        }
124
125
        if (file_exists($fromScript->getDirectory() . '/' . $includeStatement)) {
126
            return $fromScript->getDirectory() . '/' . $includeStatement;
127
        }
128
129
        throw new \RuntimeException('Unable to parse include statement "' . $includeStatement . '" in "' . $fromScript->getPath() . '"');
130
    }
131
132
    /**
133
     * @param string $command
134
     * @return bool
135
     */
136
    private function isExecutableLine(string $command): bool
137
    {
138
        $command = trim($command);
139
140
        if (!$command) {
141
            return false;
142
        }
143
144
        if ($this->startsWith('#', $command)) {
145
            return false;
146
        }
147
148
        return true;
149
    }
150
151
    /**
152
     * @param string $needle
153
     * @param string $haystack
154
     * @return string
155
     */
156
    private function removeFromStart(string $needle, string $haystack): string
157
    {
158
        return substr($haystack, strlen($needle));
159
    }
160
161
    /**
162
     * @param string $needle
163
     * @param string $haystack
164
     * @return bool
165
     */
166
    private function startsWith(string $needle, string $haystack): bool
167
    {
168
        return strpos($haystack, $needle) === 0;
169
    }
170
171
    /**
172
     * @param string $file
173
     * @return string
174
     */
175
    protected function loadFileContents(string $file): string
176
    {
177
        return file_get_contents($file);
178
    }
179
}
180