ModuleGenerator::getFiles()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
c 1
b 0
f 0
dl 0
loc 3
rs 10
cc 1
nc 1
nop 0
1
<?php
2
3
namespace Rawilk\LaravelModules\Generators;
4
5
use Illuminate\Console\Command as Console;
6
use Illuminate\Contracts\Config\Repository as Config;
7
use Illuminate\Filesystem\Filesystem;
8
use Illuminate\Support\Str;
9
use Rawilk\LaravelModules\Contracts\Activator;
10
use Rawilk\LaravelModules\FileRepository;
11
use Rawilk\LaravelModules\Support\Config\GenerateConfigReader;
12
use Rawilk\LaravelModules\Support\Stub;
13
14
class ModuleGenerator extends Generator
15
{
16
    /** @var \Rawilk\LaravelModules\Contracts\Activator */
17
    protected $activator;
18
19
    /** @var \Illuminate\Contracts\Config\Repository */
20
    protected $config;
21
22
    /** @var \Illuminate\Console\Command */
23
    protected $console;
24
25
    /** @var \Illuminate\Filesystem\Filesystem */
26
    protected $filesystem;
27
28
    /** @var bool */
29
    protected $force = false;
30
31
    /** @var bool */
32
    protected $isActive = false;
33
34
    /** @var \Rawilk\LaravelModules\Module */
35
    protected $module;
36
37
    /** @var string */
38
    protected $name;
39
40
    /** @var bool */
41
    protected $plain = false;
42
43
    /**
44
     * @param string $name
45
     * @param \Rawilk\LaravelModules\FileRepository|null $module
46
     * @param \Illuminate\Contracts\Config\Repository|null $config
47
     * @param \Illuminate\Filesystem\Filesystem|null $filesystem
48
     * @param \Illuminate\Console\Command|null $console
49
     * @param \Rawilk\LaravelModules\Contracts\Activator|null $activator
50
     */
51
    public function __construct(
52
        string $name,
53
        FileRepository $module = null,
54
        Config $config = null,
55
        Filesystem $filesystem = null,
56
        Console $console = null,
57
        Activator $activator = null
58
    )
59
    {
60
        $this->name = $name;
61
        $this->config = $config;
62
        $this->filesystem = $filesystem;
63
        $this->console = $console;
64
        $this->module = $module;
0 ignored issues
show
Documentation Bug introduced by
It seems like $module can also be of type Rawilk\LaravelModules\FileRepository. However, the property $module is declared as type Rawilk\LaravelModules\Module. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
65
        $this->activator = $activator;
66
    }
67
68
    public function generate(): void
69
    {
70
        $name = $this->getName();
71
72
        if ($this->module->has($name)) {
0 ignored issues
show
Bug introduced by
The method has() does not exist on Rawilk\LaravelModules\Module. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

72
        if ($this->module->/** @scrutinizer ignore-call */ has($name)) {
Loading history...
73
            if ($this->force) {
74
                $this->module->delete($name);
0 ignored issues
show
Unused Code introduced by
The call to Rawilk\LaravelModules\Module::delete() has too many arguments starting with $name. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

74
                $this->module->/** @scrutinizer ignore-call */ 
75
                               delete($name);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
75
            } else {
76
                $this->console->error("Module [{$name}] already exists!");
77
78
                return;
79
            }
80
        }
81
82
        $this->generateFolders();
83
84
        $this->generateModuleJsonFile();
85
86
        if ($this->plain) {
87
            $this->cleanModuleJsonFile();
88
        } else {
89
            $this->generateFiles();
90
            $this->generateResources();
91
        }
92
93
        $this->activator->setActiveByName($name, $this->isActive);
94
95
        $this->console->info("Module [{$name}] was created successfully!");
96
    }
97
98
    public function generateFiles(): void
99
    {
100
        foreach ($this->getFiles() as $stub => $file) {
101
            $path = $this->module->getModulePath($this->getName()) . $file;
0 ignored issues
show
Bug introduced by
The method getModulePath() does not exist on Rawilk\LaravelModules\Module. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

101
            $path = $this->module->/** @scrutinizer ignore-call */ getModulePath($this->getName()) . $file;
Loading history...
102
103
            if (! $this->filesystem->isDirectory($dir = dirname($path))) {
104
                $this->filesystem->makeDirectory($dir, 0775, true);
105
            }
106
107
            $this->filesystem->put($path, $this->getStubContents($stub));
108
109
            $this->console->info("Created: {$path}");
110
        }
111
    }
112
113
    public function generateFolders(): void
114
    {
115
        foreach ($this->getFolders() as $key => $folder) {
116
            $folder = GenerateConfigReader::read($key);
117
118
            if ($folder->generate() === false) {
119
                continue;
120
            }
121
122
            $path = str_replace(
123
                '//',
124
                '/',
125
                $this->module->getModulePath($this->getName()) . '/' . $folder->getPath()
126
            );
127
128
            if (! $this->filesystem->isDirectory($path)) {
129
                $this->filesystem->makeDirectory($path, 0755, true);
130
131
                if (config('modules.stubs.gitkeep')) {
132
                    $this->generateGitKeep($path);
133
                }
134
            }
135
        }
136
    }
137
138
    public function generateGitKeep(string $path): void
139
    {
140
        $this->filesystem->put("{$path}/.gitkeep", '');
141
    }
142
143
    public function generateResources(): void
144
    {
145
        $this->console->call('module:make-seed', [
146
            'name'     => $this->getName(),
147
            'module'   => $this->getName(),
148
            '--master' => true
149
        ]);
150
151
        $this->console->call('module:make-provider', [
152
            'name'     => $this->getName() . 'ServiceProvider',
153
            'module'   => $this->getName(),
154
            '--master' => true
155
        ]);
156
157
        $this->console->call('module:route-provider', [
158
            'module' => $this->getName()
159
        ]);
160
    }
161
162
    public function getConfig(): Config
163
    {
164
        return $this->config;
165
    }
166
167
    public function getConsole(): Console
168
    {
169
        return $this->console;
170
    }
171
172
    public function getFiles(): array
173
    {
174
        return $this->module->config('stubs.files');
0 ignored issues
show
Bug introduced by
The method config() does not exist on Rawilk\LaravelModules\Module. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

174
        return $this->module->/** @scrutinizer ignore-call */ config('stubs.files');
Loading history...
175
    }
176
177
    public function getFilesystem(): Filesystem
178
    {
179
        return $this->filesystem;
180
    }
181
182
    public function getFolders(): array
183
    {
184
        return $this->module->config('paths.generator');
185
    }
186
187
    public function getModule(): FileRepository
188
    {
189
        return $this->module;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->module returns the type Rawilk\LaravelModules\Module which is incompatible with the type-hinted return Rawilk\LaravelModules\FileRepository.
Loading history...
190
    }
191
192
    public function getName(): string
193
    {
194
        return Str::studly($this->name);
195
    }
196
197
    public function getReplacements(): array
198
    {
199
        return $this->module->config('stubs.replacements');
200
    }
201
202
    public function setActivator(Activator $activator): self
203
    {
204
        $this->activator = $activator;
205
206
        return $this;
207
    }
208
209
    public function setActive(bool $active): self
210
    {
211
        $this->isActive = $active;
212
213
        return $this;
214
    }
215
216
    public function setConfig(Config $config): self
217
    {
218
        $this->config = $config;
219
220
        return $this;
221
    }
222
223
    public function setConsole(Console $console): self
224
    {
225
        $this->console = $console;
226
227
        return $this;
228
    }
229
230
    public function setForce(bool $force): self
231
    {
232
        $this->force = $force;
233
234
        return $this;
235
    }
236
237
    public function setPlain(bool $plain): self
238
    {
239
        $this->plain = $plain;
240
241
        return $this;
242
    }
243
244
    public function setFilesystem(Filesystem $filesystem): self
245
    {
246
        $this->filesystem = $filesystem;
247
248
        return $this;
249
    }
250
251
    public function setModule(FileRepository $module): self
252
    {
253
        $this->module = $module;
0 ignored issues
show
Documentation Bug introduced by
It seems like $module of type Rawilk\LaravelModules\FileRepository is incompatible with the declared type Rawilk\LaravelModules\Module of property $module.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
254
255
        return $this;
256
    }
257
258
    protected function getAuthorEmailReplacement(): string
259
    {
260
        return $this->module->config('composer.author.email');
261
    }
262
263
    protected function getAuthorNameReplacement(): string
264
    {
265
        return $this->module->config('composer.author.name');
266
    }
267
268
    protected function getLowerNameReplacement(): string
269
    {
270
        return strtolower($this->getName());
271
    }
272
273
    protected function getModuleNamespaceReplacement(): string
274
    {
275
        return str_replace('\\', '\\\\', $this->module->config('namespace'));
276
    }
277
278
    protected function getReplacement(string $stub): array
279
    {
280
        $replacements = $this->getReplacements();
281
282
        if (! isset($replacements[$stub])) {
283
            return [];
284
        }
285
286
        $keys = $replacements[$stub];
287
288
        $replaces = [];
289
290
        foreach ($keys as $key) {
291
            if (method_exists($this, $method = 'get' . ucfirst(Str::studly(strtolower($key))) . 'Replacement')) {
292
                $replaces[$key] = $this->$method();
293
            } else {
294
                $replaces[$key] = null;
295
            }
296
        }
297
298
        return $replaces;
299
    }
300
301
    protected function getStubContents(string $stub): string
302
    {
303
        return (new Stub(
304
            "/{$stub}.stub",
305
            $this->getReplacement($stub)
306
        ))->render();
307
    }
308
309
    protected function getStudlyNameReplacement(): string
310
    {
311
        return $this->getName();
312
    }
313
314
    protected function getVendorReplacement(): string
315
    {
316
        return $this->module->config('composer.vendor');
317
    }
318
319
    /**
320
     * Remove the default service provider that was added in the module.json file.
321
     * This is needed when a --plain module is created.
322
     */
323
    private function cleanModuleJsonFile(): void
324
    {
325
        $path = $this->module->getModulePath($this->getName()) . 'module.json';
326
327
        $content = $this->filesystem->get($path);
328
        $namespace = $this->getModuleNamespaceReplacement();
329
        $studlyName = $this->getStudlyNameReplacement();
330
331
        $provider = '"' . $namespace . '\\\\' . $studlyName . '\\\\Providers\\\\' . $studlyName . 'ServiceProvider"';
332
333
        $content = str_replace($provider, '', $content);
334
335
        $this->filesystem->put($path, $content);
336
    }
337
338
    private function generateModuleJsonFile(): void
339
    {
340
        $path = $this->module->getModulePath($this->getName()) . 'module.json';
341
342
        if (! $this->filesystem->isDirectory($dir = dirname($path))) {
343
            $this->filesystem->makeDirectory($dir, 0775, true);
344
        }
345
346
        $this->filesystem->put($path, $this->getStubContents('json'));
347
348
        $this->console->info("Created: {$path}");
349
    }
350
}
351