Passed
Pull Request — master (#116)
by Théo
02:03
created

StubGenerator   A

Complexity

Total Complexity 26

Size/Duplication

Total Lines 216
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 26
dl 0
loc 216
rs 10
c 0
b 0
f 0

13 Methods

Rating   Name   Duplication   Size   Complexity  
A generateBannerStmt() 0 17 2
A getAliasStmt() 0 3 2
A generate() 0 23 2
A arg() 0 3 1
A alias() 0 5 1
A intercept() 0 5 1
A shebang() 0 9 2
C generatePharConfigStmt() 0 48 10
A checkRequirements() 0 5 1
A getShebang() 0 3 1
A banner() 0 5 1
A create() 0 3 1
A index() 0 5 1
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the box project.
7
 *
8
 * (c) Kevin Herrera <[email protected]>
9
 *     Théo Fidry <[email protected]>
10
 *
11
 * This source file is subject to the MIT license that is bundled
12
 * with this source code in the file LICENSE.
13
 */
14
15
namespace KevinGH\Box;
16
17
use Assert\Assertion;
18
use KevinGH\Box\RequirementChecker\RequirementsDumper;
19
20
/**
21
 * Generates a new PHP bootstrap loader stub for a PHAR.
22
 *
23
 * @private
24
 */
25
final class StubGenerator
26
{
27
    private const CHECK_FILE_NAME = RequirementsDumper::CHECK_FILE_NAME;
28
29
    private const STUB_TEMPLATE = <<<'STUB'
30
__BOX_SHEBANG__
31
<?php
32
__BOX_BANNER__
33
34
__BOX_PHAR_CONFIG__
35
36
__HALT_COMPILER(); ?>
37
38
STUB;
39
40
    /**
41
     * @var null|string The alias to be used in "phar://" URLs
42
     */
43
    private $alias;
44
45
    /**
46
     * @var null|string The top header comment banner text
47
     */
48
    private $banner;
49
50
    /**
51
     * @var null|string The location within the PHAR of index script
52
     */
53
    private $index;
54
55
    /**
56
     * @var bool Use the Phar::interceptFileFuncs() method?
57
     */
58
    private $intercept = false;
59
60
    /**
61
     * @var null|string The shebang line
62
     */
63
    private $shebang;
64
65
    private $checkRequirements = true;
66
67
    /**
68
     * Creates a new instance of the stub generator.
69
     *
70
     * @return StubGenerator the stub generator
71
     */
72
    public static function create()
73
    {
74
        return new static();
75
    }
76
77
    /**
78
     * @return string The stub
79
     */
80
    public function generate(): string
81
    {
82
        $stub = self::STUB_TEMPLATE;
83
84
        $stub = str_replace(
85
            "__BOX_SHEBANG__\n",
86
            null === $this->shebang ? '' : $this->shebang."\n",
87
            $stub
88
        );
89
90
        $stub = str_replace(
91
            "__BOX_BANNER__\n",
92
            $this->generateBannerStmt(),
93
            $stub
94
        );
95
96
        $stub = str_replace(
97
            "__BOX_PHAR_CONFIG__\n",
98
            (string) $this->generatePharConfigStmt(),
99
            $stub
100
        );
101
102
        return $stub;
103
    }
104
105
    public function alias(?string $alias): self
106
    {
107
        $this->alias = $alias;
108
109
        return $this;
110
    }
111
112
    public function banner(?string $banner): self
113
    {
114
        $this->banner = $banner;
115
116
        return $this;
117
    }
118
119
    public function index(?string $index): self
120
    {
121
        $this->index = $index;
122
123
        return $this;
124
    }
125
126
    public function intercept(bool $intercept): self
127
    {
128
        $this->intercept = $intercept;
129
130
        return $this;
131
    }
132
133
    public function shebang(?string $shebang): self
134
    {
135
        if (null !== $shebang) {
136
            Assertion::notEmpty($shebang, 'Cannot use an empty string for the shebang.');
137
        }
138
139
        $this->shebang = $shebang;
140
141
        return $this;
142
    }
143
144
    public function getShebang(): ?string
145
    {
146
        return $this->shebang;
147
    }
148
149
    public function checkRequirements(bool $checkRequirements): self
150
    {
151
        $this->checkRequirements = $checkRequirements;
152
153
        return $this;
154
    }
155
156
    /**
157
     * Escapes an argument so it can be written as a string in a call.
158
     *
159
     * @param string $arg
160
     * @param string $quote
161
     *
162
     * @return string The escaped argument
163
     */
164
    private function arg(string $arg, string $quote = "'"): string
165
    {
166
        return $quote.addcslashes($arg, $quote).$quote;
167
    }
168
169
    private function getAliasStmt(): ?string
170
    {
171
        return null !== $this->alias ? 'Phar::mapPhar('.$this->arg($this->alias).');' : null;
172
    }
173
174
    private function generateBannerStmt(): string
175
    {
176
        if (null === $this->banner) {
177
            return '';
178
        }
179
180
        $banner = "/*\n * ";
181
182
        $banner .= str_replace(
183
            " \n",
184
            "\n",
185
            str_replace("\n", "\n * ", $this->banner)
186
        );
187
188
        $banner .= "\n */";
189
190
        return "\n".$banner."\n";
191
    }
192
193
    private function generatePharConfigStmt(): ?string
194
    {
195
        $previous = false;
196
        $stub = [];
197
198
        if (null !== $aliasStmt = $this->getAliasStmt()) {
199
            $stub[] = $aliasStmt;
200
201
            $previous = true;
202
        }
203
204
        if ($this->intercept) {
205
            $stub[] = 'Phar::interceptFileFuncs();';
206
207
            $previous = true;
208
        }
209
210
        if (false !== $this->checkRequirements) {
211
            if ($previous) {
212
                $stub[] = '';
213
            }
214
215
            $checkRequirementsFile = self::CHECK_FILE_NAME;
216
217
            $stub[] = null === $this->alias
218
                ? "require 'phar://' . __FILE__ . '/.box/{$checkRequirementsFile}';"
219
                : "require 'phar://{$this->alias}/.box/{$checkRequirementsFile}';"
220
            ;
221
222
            $previous = true;
223
        }
224
225
        if (null !== $this->index) {
226
            if ($previous) {
227
                $stub[] = '';
228
            }
229
230
            $stub[] = null === $this->alias
231
                ? "require 'phar://' . __FILE__ . '/{$this->index}';"
232
                : "require 'phar://{$this->alias}/{$this->index}';"
233
            ;
234
        }
235
236
        if ([] === $stub) {
237
            return "// No PHAR config\n";
238
        }
239
240
        return implode("\n", $stub)."\n";
241
    }
242
}
243