Completed
Push — main ( 44d9a4...6d0af8 )
by Mohammad
16s queued 13s
created

Generator::getFileGeneration()   A

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
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 1
b 0
f 0
1
<?php
2
3
namespace Shamaseen\Repository\Commands;
4
5
use Illuminate\Console\Command;
6
use Illuminate\Support\Facades\Config;
7
use Illuminate\Support\Str;
8
use Shamaseen\Generator\Generator as GeneratorService;
9
use Shamaseen\Repository\Events\RepositoryFilesGenerated;
10
use Shamaseen\Repository\PathResolver;
11
12
/**
13
 * Class RepositoryGenerator.
14
 */
15
class Generator extends Command
16
{
17
    public const REPOSITORY_OPTION = 'repository';
18
    public const CONTROLLER_OPTION = 'controller';
19
    public const MODEL_OPTION = 'model';
20
    public const RESOURCE_OPTION = 'transformer';
21
    public const POLICY_OPTION = 'policy';
22
    public const REQUEST_OPTION = 'input';
23
    public const TEST_OPTION = 'test';
24
    public const COLLECTION_OPTION = 'collection';
25
26
    /**
27
     * The name and signature of the console command.
28
     *
29
     * @var string
30
     */
31
    protected $signature = 'generate:repository
32
    {name : Class (singular) for example User}
33
    {--base= : Base path to inject the files\folders in}
34
    {--f|force : force overwrite files}
35
    {--no-override : don\'t override any file}
36
    {--m|model : model only}
37
    {--c|controller : controller only}
38
    {--r|repository : repository only}
39
    {--C|collection : transformer (API collection resource) only}
40
    {--t|transformer : transformer (API single resource) only}
41
    {--p|policy : policy only}
42
    {--test : test only}
43
    {--i|input : input validation (request file) only}';
44
45
    protected $description = 'Create repository files';
46
47
    protected string $modelName;
48
    protected string $userPath;
49
    // relative to project directory
50
    protected string $basePath;
51
    private GeneratorService $generator;
52
53
    private PathResolver $pathResolver;
54
55
    /**
56
     * Create a new command instance.
57
     */
58
    public function __construct(GeneratorService $generator)
59
    {
60
        parent::__construct();
61
        $this->generator = $generator;
62
    }
63
64
    /**
65
     * Execute the console command.
66
     */
67
    public function handle(): int
68
    {
69
        // if no file is specified, then generate them all
70
        if (!$this->option(self::REQUEST_OPTION) && !$this->option(self::CONTROLLER_OPTION)
71
            && !$this->option(self::REPOSITORY_OPTION) && !$this->option(self::RESOURCE_OPTION)
72
            && !$this->option(self::MODEL_OPTION) && !$this->option(self::POLICY_OPTION)
73
            && !$this->option(self::TEST_OPTION)
74
            && !$this->option(self::COLLECTION_OPTION)
75
        ) {
76
            $options = $this->getFileGeneration();
77
            foreach ($options as $option) {
78
                $this->input->setOption($option, true);
79
            }
80
        }
81
82
        $paths = preg_split(' ([/\\\]) ', $this->argument('name'));
0 ignored issues
show
Bug introduced by
It seems like $this->argument('name') can also be of type array; however, parameter $subject of preg_split() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

82
        $paths = preg_split(' ([/\\\]) ', /** @scrutinizer ignore-type */ $this->argument('name'));
Loading history...
83
84
        if (!$paths) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $paths of type string[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
85
            $this->error('Name argument is not correct.');
86
87
            return self::FAILURE;
88
        }
89
90
        $this->modelName = array_pop($paths);
91
        $this->userPath = implode('/', str_replace('\\', '/', $paths));
92
        $this->basePath = $this->option('base') ? $this->option('base') : Config::get('repository.base_path');
93
94
        $this->pathResolver = new PathResolver($this->modelName, $this->userPath, $this->basePath);
95
96
        config(['generator.base_path' => base_path($this->basePath)]);
97
98
        return $this->makeRepositoryPatternFiles();
99
    }
100
101
    public function makeRepositoryPatternFiles(): int
102
    {
103
        // Parent Classes
104
        $modelParent = Config::get('repository.model_parent');
105
        $repositoryParent = Config::get('repository.repository_parent');
106
        $controllerParent = Config::get('repository.controller_parent');
107
        $requestParent = Config::get('repository.request_parent');
108
        $resourceParent = Config::get('repository.resource_parent');
109
        $collectionParent = Config::get('repository.collection_parent');
110
111
        if ($this->option(self::CONTROLLER_OPTION)) {
112
            $this->generate('Controller', $controllerParent);
113
        }
114
115
        if ($this->option(self::MODEL_OPTION)) {
116
            $this->generate('Model', $modelParent);
117
        }
118
119
        if ($this->option(self::REQUEST_OPTION)) {
120
            $this->generate('Request', $requestParent);
121
        }
122
123
        if ($this->option(self::COLLECTION_OPTION)) {
124
            $this->generate('Collection', $collectionParent);
125
        }
126
127
        if ($this->option(self::REPOSITORY_OPTION)) {
128
            $this->generate('Repository', $repositoryParent);
129
        }
130
131
        if ($this->option(self::RESOURCE_OPTION)) {
132
            $this->generate('Resource', $resourceParent);
133
        }
134
135
        if ($this->option(self::POLICY_OPTION)) {
136
            $this->generate('Policy');
137
        }
138
139
        if ($this->option(self::POLICY_OPTION)) {
140
            $this->generate('Test');
141
        }
142
143
        RepositoryFilesGenerated::dispatch($this->basePath, $this->userPath, $this->modelName);
144
145
        $this->dumpAutoload();
146
147
        return self::SUCCESS;
148
    }
149
150
    /**
151
     * @param string $type define which kind of files should be generated
152
     */
153
    protected function generate(string $type, string $parentClass = ''): bool
154
    {
155
        $outputPath = $this->pathResolver->outputPath($type);
156
157
        if (!$this->option('force') && $realpath = realpath($this->generator->absolutePath($outputPath))) {
158
            if ($this->option('no-override') || !$this->confirm('File '.$realpath.' exists, do you want to overwrite it?')) {
159
                return false;
160
            }
161
        }
162
163
        $namespace = $this->pathResolver->typeNamespace($type);
164
        $lcModelName = Str::lower($this->modelName);
165
        $lcPluralModelName = Str::plural($lcModelName);
166
        $snackLcPluralModelName = Str::snake($this->modelName);
167
168
        $this->generator->stub($this->pathResolver->getStubPath($type))
169
            ->replace('{{parentClass}}', $parentClass)
170
            ->replace('{{modelName}}', $this->modelName)
171
            ->replace('{{lcModelName}}', $lcModelName)
172
            ->replace('{{lcPluralModelName}}', $lcPluralModelName)
173
            ->replace('{{snackLcPluralModelName}}', $snackLcPluralModelName)
174
            ->replace('{{namespace}}', $namespace)
175
            ->replace('{{RequestsNamespace}}', $this->pathResolver->typeNamespace('Request'))
176
            ->replace('{{RepositoriesNamespace}}', $this->pathResolver->typeNamespace('Repository'))
177
            ->replace('{{ResourcesNamespace}}', $this->pathResolver->typeNamespace('Resource'))
178
            ->replace('{{ModelNamespace}}', $this->pathResolver->typeNamespace('Model'))
179
            ->replace('{{PoliciesNamespace}}', $this->pathResolver->typeNamespace('Policy'))
180
            ->replace('{{ResourcesProperties}}', $this->resourceProperty())
181
            ->replace('{{RequestProperty}}', $this->requestProperty())
182
            ->replace('{{PolicyProperty}}', $this->policyProperty())
183
            ->output($outputPath);
184
185
        return true;
186
    }
187
188
    public function resourceProperty(): string
189
    {
190
        $result = '';
191
192
        if ($this->option(self::RESOURCE_OPTION)) {
193
            $result .= "\n\t".'public ?string $resourceClass = '. $this->modelName .'Resource::class;'."\n";
194
            $result .= "\n\t".'public ?string $collectionClass = '. $this->modelName .'Collection::class;'."\n";
195
        }
196
197
        return $result;
198
    }
199
200
    public function requestProperty(): string
201
    {
202
        $result = '';
203
204
        if ($this->option(self::RESOURCE_OPTION)) {
205
            $result .= "\n\t".'public string $requestClass = '. $this->modelName .'Request::class;'."\n";
206
        }
207
208
        return $result;
209
    }
210
211
    public function policyProperty(): string
212
    {
213
        $result = '';
214
215
        if ($this->option(self::RESOURCE_OPTION)) {
216
            $result .= "\n\t".'public ?string $policyClass = '. $this->modelName .'Policy::class;'."\n";
217
        }
218
219
        return $result;
220
    }
221
222
    private function dumpAutoload(): void
223
    {
224
        shell_exec('composer dump-autoload');
225
    }
226
227
    public function getFileGeneration(): array
228
    {
229
        return config('repository.default_generated_files');
230
    }
231
}
232