Passed
Push — master ( b3365b...65b7f9 )
by Chris
16:01
created

ModelCommand::makeCollectionFiles()   B

Complexity

Conditions 9
Paths 26

Size

Total Lines 50
Code Lines 33

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 90

Importance

Changes 0
Metric Value
cc 9
eloc 33
c 0
b 0
f 0
nc 26
nop 3
dl 0
loc 50
ccs 0
cts 34
cp 0
crap 90
rs 8.0555
1
<?php
2
3
namespace Leonidas\Console\Command\Make;
4
5
use DirectoryIterator;
6
use Leonidas\Console\Command\HopliteCommand;
7
use Leonidas\Console\Library\ModelComponentFactory;
8
use Symfony\Component\Console\Input\InputArgument;
9
use Symfony\Component\Console\Input\InputOption;
10
11
class ModelCommand extends HopliteCommand
12
{
13
    protected static $defaultName = 'make:model';
14
15
    protected function configure()
16
    {
17
        $this
18
            ->addArgument('model', InputArgument::REQUIRED, '')
19
            ->addArgument('entity', InputArgument::REQUIRED, '')
20
            ->addArgument('single', InputArgument::REQUIRED, '')
21
            ->addArgument('plural', InputArgument::REQUIRED, '')
22
            ->addOption('namespace', 'l', InputOption::VALUE_OPTIONAL, '')
23
            ->addOption('contracts', 'c', InputOption::VALUE_OPTIONAL, '')
24
            ->addOption('abstracts', 'a', InputOption::VALUE_OPTIONAL, '')
25
            ->addOption('template', 't', InputOption::VALUE_REQUIRED, '', 'post')
26
            ->addOption('components', 'p', InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'The component set to generate')
27
            ->addOption('only-interface', 'o', InputOption::VALUE_NONE, 'Generate interfaces only')
28
            ->addOption('from-interface', 'f', InputOption::VALUE_NONE, 'Generate classes using interfaces as guide')
29
            ->addOption('replace', 'r', InputOption::VALUE_OPTIONAL, '');
30
    }
31
32
    protected function handle(): int
33
    {
34
        $template = $this->input->getOption('template');
35
36
        if ($this->isValidTemplate($template)) {
37
            $status = $this->makeFiles($template);
38
        } else {
39
            $this->output->error("Template \"{$template}\" is not valid");
40
41
            $status = self::FAILURE;
42
        }
43
44
        return $status;
45
    }
46
47
    protected function isValidTemplate(string $template): bool
48
    {
49
        return in_array($template, [
50
            'post',
51
            'post:h',
52
            'attachment',
53
            'term',
54
            'term:h',
55
            'user',
56
        ]);
57
    }
58
59
    protected function setupTestDir(string $dir): void
60
    {
61
        if ($this->filesystem->exists($dir)) {
62
            // $this->filesystem->remove($playground);
63
        } else {
64
            $this->filesystem->mkdir($dir);
65
        }
66
67
        foreach (new DirectoryIterator($dir) as $file) {
68
            if (!$file->isFile()) {
69
                continue;
70
            }
71
72
            if (!str_ends_with($file->getBasename(), '-interface.php')) {
73
                $this->filesystem->remove($file->getPathname());
74
            } else {
75
                require $file->getPathname();
76
            }
77
        }
78
    }
79
80
    protected function makeFiles(string $template): int
81
    {
82
        $playground = $this->external('/.playground/model');
83
84
        $this->setupTestDir($playground);
85
86
        $model = $this->input->getArgument('model');
87
        $entity = $this->input->getArgument('entity');
88
        $single = $this->input->getArgument('single');
89
        $plural = $this->input->getArgument('plural');
90
91
        $model = $this->convert($model)->toPascal();
92
93
        $namespace = $this->getNamespaceFromPath($this->configuredOption(
0 ignored issues
show
Bug introduced by
It seems like $this->configuredOption(...'make.model.namespace') can also be of type null; however, parameter $path of Leonidas\Console\Command...:getNamespaceFromPath() 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

93
        $namespace = $this->getNamespaceFromPath(/** @scrutinizer ignore-type */ $this->configuredOption(
Loading history...
94
            'namespace',
95
            'make.model.namespace'
96
        )) . '\\' . $model;
97
98
        $contracts = $this->getNamespaceFromPath($this->configuredOption(
99
            'contracts',
100
            'make.model.contracts'
101
        )) . '\\' . $model;
102
103
        $abstracts = $this->resolveAbstractNamespace($namespace);
104
105
        $factory = ModelComponentFactory::build([
106
            'model' => $model,
107
            'namespace' => $namespace,
108
            'contracts' => $contracts,
109
            'abstracts' => $abstracts,
110
            'entity' => $entity,
111
            'single' => $single,
112
            'plural' => $plural,
113
            'template' => $template,
114
        ]);
115
116
        if ($this->input->getOption('only-interface')) {
117
            $build = 'interfaces';
118
        } elseif ($this->input->getOption('from-interface')) {
119
            $build = 'classes';
120
        } else {
121
            $build = 'complete';
122
        }
123
124
        $typed = [
125
            'makeModelFiles',
126
            'makeCollectionFiles',
127
            'makeRepositoryFiles',
128
        ];
129
130
        foreach ($typed as $method) {
131
            $status = $this->$method($playground, $factory, $build);
132
133
            if (self::SUCCESS !== $status) {
134
                return $status;
135
            }
136
        }
137
138
        $support = [
139
            'makeFactoryFiles',
140
            'makeAccessProviderFiles',
141
        ];
142
143
        if ('interfaces' !== $build) {
144
            foreach ($support as $method) {
145
                $status = $this->$method($playground, $factory);
146
147
                if (self::SUCCESS !== $status) {
148
                    return $status;
149
                }
150
            }
151
        }
152
153
        return self::SUCCESS;
154
    }
155
156
    protected function makeModelFiles(string $playground, ModelComponentFactory $factory, string $build): int
157
    {
158
        $interface = $factory->getModelInterfacePrinter();
159
        $class = $factory->getModelPrinter();
160
161
        if ('interfaces' === $build || 'complete' === $build) {
162
            $this->printPhp($output = $interface->printFile());
163
            $this->writeFile($playground . '/model-interface.php', $output);
164
        } elseif ('classes' === $build) {
165
            if (!interface_exists($interfaceFqn = $interface->getClassFqn())) {
166
                $this->output->error("Interface {$interfaceFqn} does not exist");
167
168
                return self::INVALID;
169
            }
170
171
            $this->printPhp($output = $class->printFromType());
172
            $this->writeFile($playground . '/model-class.php', $output);
173
        }
174
175
        if ('complete' === $build) {
176
            $this->printPhp($class = $class->printFile());
177
            $this->writeFile($playground . '/model-class.php', $class);
178
        }
179
180
        return self::SUCCESS;
181
    }
182
183
    protected function makeCollectionFiles(string $playground, ModelComponentFactory $factory, string $build): int
184
    {
185
        $isPost = $factory->isPostTemplate();
186
187
        $interface = $factory->getCollectionInterfacePrinter();
188
        $collection = $isPost
189
            ? $factory->getChildCollectionPrinter()
190
            : $factory->getCollectionPrinter();
191
        $abstract = $factory->getAbstractCollectionPrinter();
192
        $query = $factory->getChildQueryPrinter();
193
194
        if ('interfaces' === $build || 'complete' === $build) {
195
            $this->printPhp($output = $interface->printFile());
196
            $this->writeFile($playground . '/collection-interface.php', $output);
197
        } elseif ('classes' === $build) {
198
            if (!interface_exists($interface->getClassFqn())) {
199
                $this->output->error("Interface {$interface->getClassFqn()} does not exist");
200
201
                return self::INVALID;
202
            }
203
204
            if ($isPost) {
205
                $this->printPhp($output = $abstract->printFromType());
206
                $this->writeFile($playground . '/collection-abstract.php', $output);
207
208
                $this->printPhp($output = $collection->printFile());
209
                $this->writeFile($playground . '/collection-class.php', $output);
210
211
                $this->printPhp($output = $query->printFile());
212
                $this->writeFile($playground . '/collection-query.php', $output);
213
            } else {
214
                $this->printPhp($output = $collection->printFromType());
0 ignored issues
show
Bug introduced by
The method printFromType() does not exist on Leonidas\Console\Library...ollectionAsChildPrinter. ( Ignorable by Annotation )

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

214
                $this->printPhp($output = $collection->/** @scrutinizer ignore-call */ printFromType());

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
215
                $this->writeFile($playground . '/collection-class.php', $output);
216
            }
217
        }
218
219
        if ('complete' === $build) {
220
            $this->printPhp($output = $collection->printFile());
221
            $this->writeFile($playground . '/collection-class.php', $output);
222
223
            if ($isPost) {
224
                $this->printPhp($output = $abstract->printFile());
225
                $this->writeFile($playground . '/collection-abstract.php', $output);
226
227
                $this->printPhp($output = $query->printFile());
228
                $this->writeFile($playground . '/collection-query.php', $output);
229
            }
230
        }
231
232
        return self::SUCCESS;
233
    }
234
235
    protected function makeRepositoryFiles(string $playground, ModelComponentFactory $factory, string $build): int
236
    {
237
        $interface = $factory->getRepositoryInterfacePrinter();
238
        $class = $factory->getRepositoryPrinter();
239
240
        if ('interfaces' === $build || 'complete' === $build) {
241
            $this->printPhp($interface = $interface->printFile());
242
            $this->writeFile($playground . '/repository-interface.php', $interface);
243
        } elseif ('classes' === $build) {
244
            if (!interface_exists($interfaceFqn = $interface->getClassFqn())) {
245
                $this->output->error("Interface {$interfaceFqn} does not exist");
246
247
                return self::INVALID;
248
            }
249
250
            $this->printPhp($class = $class->printFromType());
251
            $this->writeFile($playground . '/repository-class.php', $class);
252
        }
253
254
        if ('complete' === $build) {
255
            $this->printPhp($class = $class->printFile());
256
            $this->writeFile($playground . '/repository-class.php', $class);
257
        }
258
259
        return self::SUCCESS;
260
    }
261
262
    protected function makeFactoryFiles(string $playground, ModelComponentFactory $factory): int
263
    {
264
        $model = $factory->getModelConverterPrinter();
265
        $collection = $factory->getCollectionFactoryPrinter();
266
267
        $this->printPhp($model = $model->printFile());
268
        $this->writeFile($playground . '/factory-model.php', $model);
269
270
        $this->printPhp($collection = $collection->printFile());
271
        $this->writeFile($playground . '/factory-collection.php', $collection);
272
273
        if ($factory->isPostTemplate()) {
274
            $query = $factory->getQueryFactoryPrinter();
275
276
            $this->printPhp($query = $query->printFile());
277
            $this->writeFile($playground . '/factory-query.php', $query);
278
        }
279
280
        return self::SUCCESS;
281
    }
282
283
    protected function makeAccessProviderFiles(string $playground, ModelComponentFactory $factory): int
284
    {
285
        $get = $factory->getGetAccessProviderPrinter();
286
        $set = $factory->getSetAccessProviderPrinter();
287
288
        $this->printPhp($get = $get->printFile());
289
        $this->writeFile($playground . '/access-get.php', $get);
290
291
        $this->printPhp($set = $set->printFile());
292
        $this->writeFile($playground . '/access-set.php', $set);
293
294
        if ($factory->isPostTemplate()) {
295
            $tag = $factory->getTagAccessProviderPrinter();
296
297
            $this->printPhp($tag = $tag->printFile());
298
            $this->writeFile($playground . '/access-tag.php', $tag);
299
        }
300
301
        return self::SUCCESS;
302
    }
303
}
304