DomainGenerator::generateDomainJsonFile()   A
last analyzed

Complexity

Conditions 2
Paths 1

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 5
dl 0
loc 10
rs 10
c 0
b 0
f 0
cc 2
nc 1
nop 0
1
<?php
2
3
namespace Salah3id\Domains\Generators;
4
5
use Illuminate\Config\Repository as Config;
6
use Illuminate\Console\Command as Console;
7
use Illuminate\Filesystem\Filesystem;
8
use Illuminate\Support\Str;
9
use Salah3id\Domains\Contracts\ActivatorInterface;
10
use Salah3id\Domains\FileRepository;
11
use Salah3id\Domains\Support\Config\GenerateConfigReader;
12
use Salah3id\Domains\Support\Stub;
13
14
class DomainGenerator extends Generator
15
{
16
    /**
17
     * The domain name will created.
18
     *
19
     * @var string
20
     */
21
    protected $name;
22
23
    /**
24
     * The laravel config instance.
25
     *
26
     * @var Config
27
     */
28
    protected $config;
29
30
    /**
31
     * The laravel filesystem instance.
32
     *
33
     * @var Filesystem
34
     */
35
    protected $filesystem;
36
37
    /**
38
     * The laravel console instance.
39
     *
40
     * @var Console
41
     */
42
    protected $console;
43
44
    /**
45
     * The laravel component Factory instance.
46
     *
47
     * @var \Illuminate\Console\View\Components\Factory
48
     */
49
    protected $component;
50
51
52
    /**
53
     * The activator instance
54
     *
55
     * @var ActivatorInterface
56
     */
57
    protected $activator;
58
59
    /**
60
     * The domain instance.
61
     *
62
     * @var \Salah3id\Domains\Domain
63
     */
64
    protected $domain;
65
66
    /**
67
     * Force status.
68
     *
69
     * @var bool
70
     */
71
    protected $force = false;
72
73
    /**
74
     * set default domain type.
75
     *
76
     * @var string
77
     */
78
    protected $type = 'web';
79
80
    /**
81
     * Enables the domain.
82
     *
83
     * @var bool
84
     */
85
    protected $isActive = false;
86
87
    /**
88
     * The constructor.
89
     * @param $name
90
     * @param FileRepository $domain
91
     * @param Config     $config
92
     * @param Filesystem $filesystem
93
     * @param Console    $console
94
     */
95
    public function __construct(
96
        $name,
97
        FileRepository $domain = null,
98
        Config $config = null,
99
        Filesystem $filesystem = null,
100
        Console $console = null,
101
        ActivatorInterface $activator = null
102
    ) {
103
        $this->name = $name;
104
        $this->config = $config;
105
        $this->filesystem = $filesystem;
106
        $this->console = $console;
107
        $this->domain = $domain;
0 ignored issues
show
Documentation Bug introduced by
It seems like $domain can also be of type Salah3id\Domains\FileRepository. However, the property $domain is declared as type Salah3id\Domains\Domain. 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...
108
        $this->activator = $activator;
109
    }
110
111
    /**
112
     * Set type.
113
     *
114
     * @param string $type
115
     *
116
     * @return $this
117
     */
118
    public function setType($type)
119
    {
120
        $this->type = $type;
121
122
        return $this;
123
    }
124
125
    /**
126
     * Set active flag.
127
     *
128
     * @param bool $active
129
     *
130
     * @return $this
131
     */
132
    public function setActive(bool $active)
133
    {
134
        $this->isActive = $active;
135
136
        return $this;
137
    }
138
139
    /**
140
     * Get the name of domain will created. By default in studly case.
141
     *
142
     * @return string
143
     */
144
    public function getName()
145
    {
146
        return Str::studly($this->name);
147
    }
148
149
    /**
150
     * Get the laravel config instance.
151
     *
152
     * @return Config
153
     */
154
    public function getConfig()
155
    {
156
        return $this->config;
157
    }
158
159
    /**
160
     * Set the laravel config instance.
161
     *
162
     * @param Config $config
163
     *
164
     * @return $this
165
     */
166
    public function setConfig($config)
167
    {
168
        $this->config = $config;
169
170
        return $this;
171
    }
172
173
    /**
174
     * Set the domains activator
175
     *
176
     * @param ActivatorInterface $activator
177
     *
178
     * @return $this
179
     */
180
    public function setActivator(ActivatorInterface $activator)
181
    {
182
        $this->activator = $activator;
183
184
        return $this;
185
    }
186
187
    /**
188
     * Get the laravel filesystem instance.
189
     *
190
     * @return Filesystem
191
     */
192
    public function getFilesystem()
193
    {
194
        return $this->filesystem;
195
    }
196
197
    /**
198
     * Set the laravel filesystem instance.
199
     *
200
     * @param Filesystem $filesystem
201
     *
202
     * @return $this
203
     */
204
    public function setFilesystem($filesystem)
205
    {
206
        $this->filesystem = $filesystem;
207
208
        return $this;
209
    }
210
211
    /**
212
     * Get the laravel console instance.
213
     *
214
     * @return Console
215
     */
216
    public function getConsole()
217
    {
218
        return $this->console;
219
    }
220
221
    /**
222
     * Set the laravel console instance.
223
     *
224
     * @param Console $console
225
     *
226
     * @return $this
227
     */
228
    public function setConsole($console)
229
    {
230
        $this->console = $console;
231
232
        return $this;
233
    }
234
235
    /**
236
     * @return \Illuminate\Console\View\Components\Factory
237
     */
238
    public function getComponent(): \Illuminate\Console\View\Components\Factory
239
    {
240
        return $this->component;
241
    }
242
243
    /**
244
     * @param \Illuminate\Console\View\Components\Factory $component
245
     */
246
    public function setComponent(\Illuminate\Console\View\Components\Factory $component): self
247
    {
248
        $this->component = $component;
249
        return $this;
250
    }
251
252
    /**
253
     * Get the domain instance.
254
     *
255
     * @return \Salah3id\Domains\Domain
256
     */
257
    public function getDomain()
258
    {
259
        return $this->domain;
260
    }
261
262
    /**
263
     * Set the domain instance.
264
     *
265
     * @param mixed $domain
266
     *
267
     * @return $this
268
     */
269
    public function setDomain($domain)
270
    {
271
        $this->domain = $domain;
272
273
        return $this;
274
    }
275
276
    /**
277
     * Get the list of folders will created.
278
     *
279
     * @return array
280
     */
281
    public function getFolders()
282
    {
283
        return $this->domain->config('paths.generator');
0 ignored issues
show
Bug introduced by
The method config() does not exist on Salah3id\Domains\Domain. 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

283
        return $this->domain->/** @scrutinizer ignore-call */ config('paths.generator');
Loading history...
284
    }
285
286
    /**
287
     * Get the list of files will created.
288
     *
289
     * @return array
290
     */
291
    public function getFiles()
292
    {
293
        return $this->domain->config('stubs.files');
294
    }
295
296
    /**
297
     * Set force status.
298
     *
299
     * @param bool|int $force
300
     *
301
     * @return $this
302
     */
303
    public function setForce($force)
304
    {
305
        $this->force = $force;
0 ignored issues
show
Documentation Bug introduced by
It seems like $force can also be of type integer. However, the property $force is declared as type boolean. 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...
306
307
        return $this;
308
    }
309
310
    /**
311
     * Generate the domain.
312
     */
313
    public function generate(): int
314
    {
315
        $name = $this->getName();
316
317
        if ($this->domain->has($name)) {
0 ignored issues
show
Bug introduced by
The method has() does not exist on Salah3id\Domains\Domain. 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

317
        if ($this->domain->/** @scrutinizer ignore-call */ has($name)) {
Loading history...
318
            if ($this->force) {
319
                $this->domain->delete($name);
0 ignored issues
show
Unused Code introduced by
The call to Salah3id\Domains\Domain::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

319
                $this->domain->/** @scrutinizer ignore-call */ 
320
                               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...
320
            } else {
321
                $this->component->error("Domain [{$name}] already exists!");
322
323
                return E_ERROR;
324
            }
325
        }
326
        $this->component->info("Creating domain: [$name]");
327
328
        $this->generateFolders();
329
330
        $this->generateDomainJsonFile();
331
332
        if ($this->type !== 'plain') {
333
            $this->generateFiles();
334
            $this->generateResources();
335
        }
336
337
        if ($this->type === 'plain') {
338
            $this->cleanDomainJsonFile();
339
        }
340
341
        $this->activator->setActiveByName($name, $this->isActive);
342
343
        $this->console->newLine(1);
344
345
        $this->component->info("Domain [{$name}] created successfully.");
346
347
        return 0;
348
    }
349
350
    /**
351
     * Generate the folders.
352
     */
353
    public function generateFolders()
354
    {
355
        foreach ($this->getFolders() as $key => $folder) {
356
            $folder = GenerateConfigReader::read($key);
357
358
            if ($folder->generate() === false) {
359
                continue;
360
            }
361
362
            $path = $this->domain->getDomainPath($this->getName()) . '/' . $folder->getPath();
0 ignored issues
show
Bug introduced by
The method getDomainPath() does not exist on Salah3id\Domains\Domain. 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

362
            $path = $this->domain->/** @scrutinizer ignore-call */ getDomainPath($this->getName()) . '/' . $folder->getPath();
Loading history...
363
364
            $this->filesystem->makeDirectory($path, 0755, true);
365
            if (config('domains.stubs.gitkeep')) {
366
                $this->generateGitKeep($path);
367
            }
368
        }
369
    }
370
371
    /**
372
     * Generate git keep to the specified path.
373
     *
374
     * @param string $path
375
     */
376
    public function generateGitKeep($path)
377
    {
378
        $this->filesystem->put($path . '/.gitkeep', '');
379
    }
380
381
    /**
382
     * Generate the files.
383
     */
384
    public function generateFiles()
385
    {
386
        foreach ($this->getFiles() as $stub => $file) {
387
            $path = $this->domain->getDomainPath($this->getName()) . $file;
388
389
            $this->component->task("Generating file {$path}",function () use ($stub, $path) {
390
                if (!$this->filesystem->isDirectory($dir = dirname($path))) {
391
                    $this->filesystem->makeDirectory($dir, 0775, true);
392
                }
393
394
                $this->filesystem->put($path, $this->getStubContents($stub));
395
            });
396
        }
397
    }
398
399
    /**
400
     * Generate some resources.
401
     */
402
    public function generateResources()
403
    {
404
        if (GenerateConfigReader::read('seeder')->generate() === true) {
405
            $this->console->call('domain:make-seed', [
406
                'name' => $this->getName(),
407
                'domain' => $this->getName(),
408
                '--master' => true,
409
            ]);
410
        }
411
412
        if (GenerateConfigReader::read('provider')->generate() === true) {
413
            $this->console->call('domain:make-provider', [
414
                'name' => $this->getName() . 'ServiceProvider',
415
                'domain' => $this->getName(),
416
                '--master' => true,
417
            ]);
418
            $this->console->call('domain:route-provider', [
419
                'domain' => $this->getName(),
420
            ]);
421
422
            $this->console->call('domain:make-provider', [
423
                'name' => 'RepositoryServiceProvider',
424
                'domain' => $this->getName(),
425
            ]);
426
        }
427
    }
428
429
    /**
430
     * Get the contents of the specified stub file by given stub name.
431
     *
432
     * @param $stub
433
     *
434
     * @return string
435
     */
436
    protected function getStubContents($stub)
437
    {
438
        return (new Stub(
439
            '/' . $stub . '.stub',
440
            $this->getReplacement($stub)
441
        )
442
        )->render();
443
    }
444
445
    /**
446
     * get the list for the replacements.
447
     */
448
    public function getReplacements()
449
    {
450
        return $this->domain->config('stubs.replacements');
451
    }
452
453
    /**
454
     * Get array replacement for the specified stub.
455
     *
456
     * @param $stub
457
     *
458
     * @return array
459
     */
460
    protected function getReplacement($stub)
461
    {
462
        $replacements = $this->domain->config('stubs.replacements');
463
464
        if (!isset($replacements[$stub])) {
465
            return [];
466
        }
467
468
        $keys = $replacements[$stub];
469
470
        $replaces = [];
471
472
        if ($stub === 'json' || $stub === 'composer') {
473
            if (in_array('PROVIDER_NAMESPACE', $keys, true) === false) {
474
                $keys[] = 'PROVIDER_NAMESPACE';
475
            }
476
        }
477
        foreach ($keys as $key) {
478
            if (method_exists($this, $method = 'get' . ucfirst(Str::studly(strtolower($key))) . 'Replacement')) {
479
                $replaces[$key] = $this->$method();
480
            } else {
481
                $replaces[$key] = null;
482
            }
483
        }
484
485
        return $replaces;
486
    }
487
488
    /**
489
     * Generate the domain.json file
490
     */
491
    private function generateDomainJsonFile()
492
    {
493
        $path = $this->domain->getDomainPath($this->getName()) . 'domain.json';
494
495
        $this->component->task("Generating file $path",function () use ($path) {
496
            if (!$this->filesystem->isDirectory($dir = dirname($path))) {
497
                $this->filesystem->makeDirectory($dir, 0775, true);
498
            }
499
500
            $this->filesystem->put($path, $this->getStubContents('json'));
501
        });
502
    }
503
504
    /**
505
     * Remove the default service provider that was added in the domain.json file
506
     * This is needed when a --plain domain was created
507
     */
508
    private function cleanDomainJsonFile()
509
    {
510
        $path = $this->domain->getDomainPath($this->getName()) . 'domain.json';
511
512
        $content = $this->filesystem->get($path);
513
        $namespace = $this->getDomainNamespaceReplacement();
514
        $studlyName = $this->getStudlyNameReplacement();
515
516
        $provider = '"' . $namespace . '\\\\' . $studlyName . '\\\\Providers\\\\' . $studlyName . 'ServiceProvider"';
517
518
        $content = str_replace($provider, '', $content);
519
520
        $this->filesystem->put($path, $content);
521
    }
522
523
    /**
524
     * Get the domain name in lower case.
525
     *
526
     * @return string
527
     */
528
    protected function getLowerNameReplacement()
529
    {
530
        return strtolower($this->getName());
531
    }
532
533
    /**
534
     * Get the domain name in studly case.
535
     *
536
     * @return string
537
     */
538
    protected function getStudlyNameReplacement()
539
    {
540
        return $this->getName();
541
    }
542
543
    /**
544
     * Get replacement for $VENDOR$.
545
     *
546
     * @return string
547
     */
548
    protected function getVendorReplacement()
549
    {
550
        return $this->domain->config('composer.vendor');
551
    }
552
553
    /**
554
     * Get replacement for $DOMAIN_NAMESPACE$.
555
     *
556
     * @return string
557
     */
558
    protected function getDomainNamespaceReplacement()
559
    {
560
        return str_replace('\\', '\\\\', $this->domain->config('namespace'));
561
    }
562
563
    /**
564
     * Get replacement for $AUTHOR_NAME$.
565
     *
566
     * @return string
567
     */
568
    protected function getAuthorNameReplacement()
569
    {
570
        return $this->domain->config('composer.author.name');
571
    }
572
573
    /**
574
     * Get replacement for $AUTHOR_EMAIL$.
575
     *
576
     * @return string
577
     */
578
    protected function getAuthorEmailReplacement()
579
    {
580
        return $this->domain->config('composer.author.email');
581
    }
582
583
    protected function getProviderNamespaceReplacement(): string
584
    {
585
        return str_replace('\\', '\\\\', GenerateConfigReader::read('provider')->getNamespace());
586
    }
587
}
588