Completed
Push — develop ( 73bd0a...ccb498 )
by Tom
05:04
created

MakeTableCommand   A

Complexity

Total Complexity 34

Size/Duplication

Total Lines 360
Duplicated Lines 24.44 %

Coupling/Cohesion

Components 1
Dependencies 8

Importance

Changes 3
Bugs 0 Features 2
Metric Value
wmc 34
c 3
b 0
f 2
lcom 1
cbo 8
dl 88
loc 360
rs 9.2

15 Methods

Rating   Name   Duplication   Size   Complexity  
A configure() 0 7 1
A execute() 0 13 1
A processColumns() 0 13 2
A processColumn() 0 18 1
A askForColumnName() 14 14 2
A askForIdentityColumn() 0 17 4
A askForColumnType() 0 8 1
A askForColumnIsUnsigned() 17 17 3
B askForColumnSize() 0 34 5
A askForColumnIsNullable() 13 13 2
B askForColumnDefault() 0 19 5
A askForColumnComment() 15 15 2
A askForTableName() 14 14 2
A askForTableComment() 15 15 2
A generateCode() 0 7 1

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
/**
3
 * Copyright © 2016 netz98 new media GmbH. All rights reserved.
4
 * See COPYING.txt for license details.
5
 */
6
7
namespace N98\Magento\Command\Developer\Console;
8
9
use Magento\Framework\DB\Ddl\Table;
10
use N98\Magento\Command\Developer\Console\Renderer\PHPCode\TableRenderer;
11
use N98\Magento\Command\Developer\Console\Structure\DDLTable;
12
use N98\Magento\Command\Developer\Console\Structure\DDLTableColumn;
13
use Symfony\Component\Console\Helper\QuestionHelper;
14
use Symfony\Component\Console\Input\InputInterface;
15
use Symfony\Component\Console\Output\OutputInterface;
16
use Symfony\Component\Console\Question\ChoiceQuestion;
17
use Symfony\Component\Console\Question\ConfirmationQuestion;
18
use Symfony\Component\Console\Question\Question;
19
20
class MakeTableCommand extends AbstractGeneratorCommand
21
{
22
    /**
23
     * @var array
24
     */
25
    private $columnTypes = [
26
        Table::TYPE_BOOLEAN,
27
        Table::TYPE_SMALLINT,
28
        Table::TYPE_INTEGER,
29
        Table::TYPE_BIGINT,
30
        Table::TYPE_FLOAT,
31
        Table::TYPE_NUMERIC,
32
        Table::TYPE_DECIMAL,
33
        Table::TYPE_DATE,
34
        Table::TYPE_TIMESTAMP,
35
        Table::TYPE_DATETIME,
36
        Table::TYPE_TEXT,
37
        Table::TYPE_BLOB,
38
        Table::TYPE_VARBINARY,
39
    ];
40
41
    /**
42
     * @var string
43
     */
44
    private $identityColumn = null;
45
46
    protected function configure()
47
    {
48
        $this
49
            ->setName('make:table')
50
            ->setDescription('Creates a new database table')
51
        ;
52
    }
53
54
    /**
55
     * @param InputInterface  $input
56
     * @param OutputInterface $output
57
     *
58
     * @return int|void
59
     */
60
    protected function execute(InputInterface $input, OutputInterface $output)
61
    {
62
        /** @var QuestionHelper $questionHelper */
63
        $questionHelper = $this->getHelper('question');
64
65
        $table = new DDLTable();
66
        
67
        $this->askForTableName($input, $output, $questionHelper, $table);
68
        $this->processColumns($input, $output, $questionHelper, $table);
69
        $this->askForTableComment($input, $output, $questionHelper, $table);
70
71
        $this->generateCode($input, $output, $table);
72
    }
73
74
    /**
75
     * @param InputInterface $input
76
     * @param OutputInterface $output
77
     * @param QuestionHelper $questionHelper
78
     * @param DDLTable $table
79
     * @return void
80
     */
81
    private function processColumns(
82
        InputInterface $input, OutputInterface $output, QuestionHelper $questionHelper, DDLTable $table
83
    ) {
84
        $columns = [];
85
86
        do {
87
            $columns[] = $this->processColumn($input, $output, $questionHelper);
88
89
            $question = new ConfirmationQuestion('<question>Add a new column? [y/n]</question>:');
90
        } while ($questionHelper->ask($input, $output, $question));
91
92
        $table->setColumns($columns);
93
    }
94
95
    /**
96
     * @param InputInterface $input
97
     * @param OutputInterface $output
98
     * @param QuestionHelper $questionHelper
99
     * @return DDLTableColumn
100
     */
101
    private function processColumn(
102
        InputInterface $input, OutputInterface $output, QuestionHelper $questionHelper
103
    ) {
104
        $column = new DDLTableColumn();
105
        
106
        $this->askForColumnName($input, $output, $questionHelper, $column);
107
        $this->askForColumnType($input, $output, $questionHelper, $column);
108
        $this->askForIdentityColumn($input, $output, $questionHelper, $column);
109
        $this->askForColumnSize($input, $output, $questionHelper, $column);
110
        $this->askForColumnIsNullable($input, $output, $questionHelper, $column);
111
        $this->askForColumnIsUnsigned($input, $output, $questionHelper, $column);
112
        $this->askForColumnDefault($input, $output, $questionHelper, $column);
113
        $this->askForColumnComment($input, $output, $questionHelper, $column);
114
115
        $output->writeln('');
116
117
        return $column;
118
    }
119
120
    /**
121
     * @param InputInterface $input
122
     * @param OutputInterface $output
123
     * @param QuestionHelper $questionHelper
124
     * @param DDLTableColumn $column
125
     * @return void
126
     */
127 View Code Duplication
    private function askForColumnName(
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
128
        InputInterface $input, OutputInterface $output, QuestionHelper $questionHelper, DDLTableColumn $column
129
    ) {
130
        $columnNameQuestion = new Question('<question>Column name:</question>');
131
        $columnNameQuestion->setValidator(function ($answer) {
132
            if (empty($answer)) {
133
                throw new \RuntimeException('Column name could not be empty');
134
            }
135
136
            return $answer;
137
        });
138
139
        $column->setName($questionHelper->ask($input, $output, $columnNameQuestion));
140
    }
141
142
    /**
143
     * @param InputInterface $input
144
     * @param OutputInterface $output
145
     * @param QuestionHelper $questionHelper
146
     * @param DDLTableColumn $column
147
     * @return void
148
     */
149
    private function askForIdentityColumn(
150
        InputInterface $input, OutputInterface $output, QuestionHelper $questionHelper, DDLTableColumn $column
151
    ) {
152
        if (!empty($this->identityColumn) || !$column->isIntType()) { // there can only be one identity column
153
            return;
154
        }
155
156
        $columnNameQuestion = new ConfirmationQuestion('<question>Is this your identity column? (y/n)</question>');
157
158
        if ($questionHelper->ask($input, $output, $columnNameQuestion)) {
159
            $this->identityColumn = $column->getName();
160
            $column->setUnsigned(true);
161
            $column->setPrimary(true);
162
            $column->setNullable(false);
163
            $column->setIdentity(true);
164
        }
165
    }
166
167
    /**
168
     * @param InputInterface $input
169
     * @param OutputInterface $output
170
     * @param QuestionHelper $questionHelper
171
     * @param DDLTableColumn $data
172
     * @return void
173
     */
174
    private function askForColumnType(
175
        InputInterface $input, OutputInterface $output, QuestionHelper $questionHelper, DDLTableColumn $data
176
    ) {
177
        $columnTypeQuestion = new ChoiceQuestion('<question>Column type:</question>', $this->columnTypes);
178
        $columnTypeQuestion->setErrorMessage('Type %s is invalid.');
179
180
        $data->setType($questionHelper->ask($input, $output, $columnTypeQuestion));
181
    }
182
183
    /**
184
     * @param InputInterface $input
185
     * @param OutputInterface $output
186
     * @param QuestionHelper $questionHelper
187
     * @param DDLTableColumn $column
188
     * @return void
189
     */
190 View Code Duplication
    private function askForColumnIsUnsigned(
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
191
        InputInterface $input, OutputInterface $output, QuestionHelper $questionHelper, DDLTableColumn $column
192
    ) {
193
        if (!$column->isIntType()) {
194
            return;
195
        }
196
197
        if ($column->getUnsigned() !== null) {
198
            return;
199
        }
200
201
        $columnTypeQuestion = new ConfirmationQuestion(
202
            '<question>Is column unsigned?</question><info>(default yes)</info>'
203
        );
204
205
        $column->setUnsigned($questionHelper->ask($input, $output, $columnTypeQuestion));
206
    }
207
208
    /**
209
     * @param InputInterface $input
210
     * @param OutputInterface $output
211
     * @param QuestionHelper $questionHelper
212
     * @param DDLTableColumn $column
213
     * @return void
214
     */
215
    private function askForColumnSize(
216
        InputInterface $input,
217
        OutputInterface $output,
218
        QuestionHelper $questionHelper,
219
        DDLTableColumn $column
220
    ) {
221
        if (!$column->isTypeWithSize()) {
222
            return;
223
        }
224
225
        $default = null;
226
227
        if ($column->getType() == Table::TYPE_TEXT) {
228
            $default = 255;
229
        }
230
231
        $columnNameQuestion = new Question(
232
            '<question>Column size:</question> <info>(default: ' . $default . ')</info>',
233
            $default
234
        );
235
        $columnNameQuestion->setValidator(function ($answer) {
236
            if (empty($answer)) {
237
                throw new \RuntimeException('Column size could not be empty');
238
            }
239
240
            if ($answer <= 0) {
241
                throw new \RuntimeException('Column size could be greater than zero');
242
            }
243
244
            return (int) $answer;
245
        });
246
247
        $column->setSize($questionHelper->ask($input, $output, $columnNameQuestion));
248
    }
249
250
    /**
251
     * @param InputInterface $input
252
     * @param OutputInterface $output
253
     * @param QuestionHelper $questionHelper
254
     * @param DDLTableColumn $column
255
     * @return void
256
     */
257 View Code Duplication
    private function askForColumnIsNullable(
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
258
        InputInterface $input, OutputInterface $output, QuestionHelper $questionHelper, DDLTableColumn $column
259
    ) {
260
        if ($column->isNullable() !== null) {
261
            return;
262
        }
263
264
        $columnTypeQuestion = new ConfirmationQuestion(
265
            '<question>Is column nullable:</question><info>(default yes)</info>'
266
        );
267
268
        $column->setNullable($questionHelper->ask($input, $output, $columnTypeQuestion));
0 ignored issues
show
Documentation introduced by
$questionHelper->ask($in...t, $columnTypeQuestion) is of type string, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
269
    }
270
271
    /**
272
     * @param InputInterface $input
273
     * @param OutputInterface $output
274
     * @param QuestionHelper $questionHelper
275
     * @param DDLTableColumn $column
276
     * @return void
277
     */
278
    private function askForColumnDefault(
279
        InputInterface $input, OutputInterface $output, QuestionHelper $questionHelper, DDLTableColumn $column
280
    ) {
281
        if ($column->getIdentity()) {
282
            return;
283
        }
284
285
        $question = new Question('<question>Column default value:</question>');
286
        $question->setValidator(function ($answer) use ($column) {
287
288
            if ($column->isIntType() && !is_numeric($answer) && !empty($answer)) {
289
                throw new \InvalidArgumentException('Invalid default value');
290
            }
291
292
            return $answer;
293
        });
294
295
        $column->setDefault($questionHelper->ask($input, $output, $question));
296
    }
297
298
    /**
299
     * @param InputInterface $input
300
     * @param OutputInterface $output
301
     * @param QuestionHelper $questionHelper
302
     * @param DDLTableColumn $column
303
     * @return void
304
     */
305 View Code Duplication
    private function askForColumnComment(
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
306
        InputInterface $input, OutputInterface $output, QuestionHelper $questionHelper, DDLTableColumn $column
307
    ) {
308
        $columnNameQuestion = new Question('<question>Column comment:</question>');
309
        $columnNameQuestion->setValidator(function ($answer) {
310
            if (empty($answer)) {
311
                throw new \RuntimeException('Column comment could not be empty');
312
            }
313
314
            return $answer;
315
        });
316
317
        
318
        $column->setComment($questionHelper->ask($input, $output, $columnNameQuestion));
319
    }
320
321
    /**
322
     * @param InputInterface $input
323
     * @param OutputInterface $output
324
     * @param $questionHelper
325
     * @param DDLTable $table
326
     * @return void
327
     */
328 View Code Duplication
    private function askForTableName(InputInterface $input, OutputInterface $output, $questionHelper, DDLTable $table)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
329
    {
330
        $question = new Question('<question>Table name:</question>');
331
        $question->setValidator(function ($answer) {
332
333
            if (empty($answer)) {
334
                throw new \RuntimeException('Table name could not be empty');
335
            }
336
337
            return $answer;
338
        });
339
340
        $table->setName($questionHelper->ask($input, $output, $question));
341
    }
342
343
    /**
344
     * @param InputInterface $input
345
     * @param OutputInterface $output
346
     * @param $questionHelper
347
     * @param DDLTable $column
348
     * @return void
349
     */
350 View Code Duplication
    private function askForTableComment(
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
351
        InputInterface $input, OutputInterface $output, $questionHelper, DDLTable $column
352
    ) {
353
        $question = new Question('<question>Table comment:</question>');
354
        $question->setValidator(function ($answer) {
355
356
            if (empty($answer)) {
357
                throw new \RuntimeException('Table comment could not be empty');
358
            }
359
360
            return $answer;
361
        });
362
363
        $column->setComment($questionHelper->ask($input, $output, $question));
364
    }
365
366
    /**
367
     * @param InputInterface $input
368
     * @param OutputInterface $output
369
     * @param DDLTable $table
370
     * @return void
371
     */
372
    private function generateCode(
373
        InputInterface $input, OutputInterface $output, DDLTable $table
0 ignored issues
show
Unused Code introduced by
The parameter $input is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $output is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
374
    ) {
375
        $renderer = new TableRenderer($table, $this->getHelper('twig'));
376
377
        echo $renderer->render();
378
    }
379
}
380