Completed
Pull Request — master (#254)
by Loïc
02:13
created

MakeGrid::askForNextField()   A

Complexity

Conditions 5
Paths 6

Size

Total Lines 38

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 38
rs 9.0008
c 0
b 0
f 0
cc 5
nc 6
nop 2
1
<?php
2
3
/*
4
 * This file is part of monofony.
5
 *
6
 * (c) Mobizel
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
declare(strict_types=1);
13
14
namespace App\Maker;
15
16
use App\Maker\Helper\GridHelper;
17
use App\Maker\Helper\ResourceHelper;
18
use Symfony\Bundle\MakerBundle\ConsoleStyle;
19
use Symfony\Bundle\MakerBundle\DependencyBuilder;
20
use Symfony\Bundle\MakerBundle\Generator;
21
use Symfony\Bundle\MakerBundle\InputConfiguration;
22
use Symfony\Bundle\MakerBundle\Maker\AbstractMaker;
23
use Symfony\Component\Console\Command\Command;
24
use Symfony\Component\Console\Input\InputArgument;
25
use Symfony\Component\Console\Input\InputInterface;
26
use Symfony\Component\Console\Question\ChoiceQuestion;
27
use Symfony\Component\Filesystem\Filesystem;
28
use Webmozart\Assert\Assert;
29
30
final class MakeGrid extends AbstractMaker
31
{
32
    /** @var string */
33
    private $projectDir;
34
35
    /** @var ResourceHelper */
36
    private $resourceHelper;
37
38
    /** @var GridHelper */
39
    private $gridHelper;
40
41
    /** @var Filesystem */
42
    private $fileSystem;
43
44
    public function __construct(string $projectDir, ResourceHelper $resourceHelper, GridHelper $gridHelper)
45
    {
46
        $this->projectDir = $projectDir;
47
        $this->resourceHelper = $resourceHelper;
48
        $this->gridHelper = $gridHelper;
49
50
        $this->fileSystem = new Filesystem();
51
    }
52
53
    public static function getCommandName(): string
54
    {
55
        return 'make:sylius-grid';
56
    }
57
58
    public function configureCommand(Command $command, InputConfiguration $inputConfig)
59
    {
60
        $command
61
            ->setDescription('Creates a new grid')
62
            ->addArgument('section', InputArgument::REQUIRED, 'Section of the grid (backend or frontend)')
63
            ->addArgument('resource', InputArgument::REQUIRED, 'Resource alias of the grid')
64
        ;
65
66
        $inputConfig->setArgumentAsNonInteractive('resource');
67
        $inputConfig->setArgumentAsNonInteractive('section');
68
    }
69
70
    public function interact(InputInterface $input, ConsoleStyle $io, Command $command)
71
    {
72
        if (!$input->getArgument('section')) {
73
            $question = new ChoiceQuestion(
74
                'Please select a section for your grid',
75
                ['backend', 'frontend'],
76
                0
77
            );
78
79
            $section = $io->askQuestion($question);
80
81
            $input->setArgument('section', $section);
82
        }
83
84
        if (!$input->getArgument('resource')) {
85
            $question = new ChoiceQuestion(
86
                'Please select a resource for your grid',
87
                $this->resourceHelper->getResourcesAliases(),
88
                0
89
            );
90
91
            $resourceAlias = $io->askQuestion($question);
92
93
            $input->setArgument('resource', $resourceAlias);
94
        }
95
96
        if ($resourceAlias = $input->getArgument('resource')) {
97
            Assert::true($this->resourceHelper->isResourceAliasExist($resourceAlias), sprintf(
0 ignored issues
show
Bug introduced by
It seems like $resourceAlias defined by $input->getArgument('resource') on line 96 can also be of type array<integer,string>; however, App\Maker\Helper\Resourc...:isResourceAliasExist() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
98
                    'Resource with alias %s not found',
99
                    $resourceAlias
100
                )
101
            );
102
        }
103
    }
104
105
    public function configureDependencies(DependencyBuilder $dependencies)
106
    {
107
    }
108
109
    public function generate(InputInterface $input, ConsoleStyle $io, Generator $generator)
110
    {
111
        $resourceAlias = $input->getArgument('resource');
112
113
        $fields = [];
114
        $isFirstField = true;
115
        while (true) {
116
            $newField = $this->askForNextField($io, $isFirstField);
117
            $isFirstField = false;
118
119
            if (null === $newField) {
120
                break;
121
            }
122
123
            $fields[] = $newField;
124
        }
125
126
        $actions = [
127
            'main' => [],
128
            'item' => [],
129
            'bulk' => [],
130
        ];
131
132
        foreach ($actions as $section => $data) {
133
            $hasSectionAction = $io->confirm(sprintf('Do you have %s actions?', $section), false);
134
135
            if ($hasSectionAction) {
136
                $isFirstAction = true;
137
                while (true) {
138
                    $newAction = $this->askForNextAction($io, $isFirstAction);
139
                    $isFirstAction = false;
140
141
                    if (null === $newAction) {
142
                        break;
143
                    }
144
145
                    $actions[$section][] = $newAction;
146
                }
147
            }
148
        }
149
150
151
        $this->generateGridConfigFile($input, $io, $generator, $fields, $actions);
152
    }
153
154
    private function askForNextField(ConsoleStyle $io, bool $isFirstField)
155
    {
156
        $io->writeln('');
157
158
        if ($isFirstField) {
159
            $questionText = 'New field name (press <return> to stop adding fields)';
160
        } else {
161
            $questionText = 'Add another field? Enter the field name (or press <return> to stop adding fields)';
162
        }
163
164
        $fieldName = $io->ask($questionText, null, function ($name) {
165
            // allow it to be empty
166
            if (!$name) {
167
                return $name;
168
            }
169
170
            return $name;
171
        });
172
173
        if (!$fieldName) {
174
            return null;
175
        }
176
177
        $fieldType = $io->choice('Enter the field type', $this->gridHelper->getFilterIds(), 'string');
178
        $fieldLabel = $io->ask('Enter the field label', '~');
179
        $isSortable = $io->confirm('Is the field sortable?', true);
180
181
        if ($isSortable) {
182
            $fieldSortable = $io->ask('Enter the sortable path', '~');
183
        }
184
185
        return [
186
            $fieldName,
187
            $fieldType,
188
            $fieldLabel,
189
            $fieldSortable ?? null,
190
        ];
191
    }
192
193
    private function askForNextAction(ConsoleStyle $io, bool $isFirstAction)
194
    {
195
        $io->writeln('');
196
197
        if ($isFirstAction) {
198
            $questionText = 'New action name (press <return> to stop adding actions)';
199
        } else {
200
            $questionText = 'Add another action? Enter the action name (or press <return> to stop adding actions)';
201
        }
202
203
        $actionName = $io->ask($questionText, null, function ($name) {
204
            // allow it to be empty
205
            if (!$name) {
206
                return $name;
207
            }
208
209
            return $name;
210
        });
211
212
        if (!$actionName) {
213
            return null;
214
        }
215
216
        $actionType = $io->choice('Enter the action type', ['create', 'update', 'delete'], $actionName);
217
218
        return [
219
            $actionName,
220
            $actionType,
221
        ];
222
    }
223
224
    private function generateGridConfigFile(
225
        InputInterface $input,
226
        ConsoleStyle $io,
0 ignored issues
show
Unused Code introduced by
The parameter $io 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...
227
        Generator $generator,
0 ignored issues
show
Unused Code introduced by
The parameter $generator 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...
228
        array $fields,
229
        array $actions
230
    ): void {
231
        $section = $input->getArgument('section');
232
        $resourceAlias = $input->getArgument('resource');
233
        [$appName, $resourceName] = $this->resourceHelper->splitResourceAlias($resourceAlias);
0 ignored issues
show
Bug introduced by
It seems like $resourceAlias defined by $input->getArgument('resource') on line 232 can also be of type array<integer,string> or null; however, App\Maker\Helper\Resourc...r::splitResourceAlias() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
234
        $gridId = sprintf('%s_%s_%s', $appName, $section, $resourceName);
235
236
        $gridConfigDir = $this->getGridConfigDir($resourceAlias, $section);
0 ignored issues
show
Bug introduced by
It seems like $resourceAlias defined by $input->getArgument('resource') on line 232 can also be of type array<integer,string> or null; however, App\Maker\MakeGrid::getGridConfigDir() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
Bug introduced by
It seems like $section defined by $input->getArgument('section') on line 231 can also be of type array<integer,string> or null; however, App\Maker\MakeGrid::getGridConfigDir() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
237
        $modelClass = $this->resourceHelper->getResourceModelFromAlias($resourceAlias);
0 ignored issues
show
Bug introduced by
It seems like $resourceAlias defined by $input->getArgument('resource') on line 232 can also be of type array<integer,string> or null; however, App\Maker\Helper\Resourc...esourceModelFromAlias() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
238
239
        $formattedFields = $this->formatFields($fields);
240
        $formattedActions = $this->formatActions($actions);
241
242
        $this->fileSystem->dumpFile($gridConfigDir, <<<EOM
243
sylius_grid:
244
    grids:
245
        $gridId:
246
            driver:
247
                name: doctrine/orm
248
                options:
249
                    class: "%$modelClass%"
250
            fields:
251
                $formattedFields
252
            actions:
253
                $formattedActions                
254
255
EOM
256
);
257
    }
258
259
    private function getGridConfigDir(string $resourceAlias, string $section)
260
    {
261
        $resource = $this->resourceHelper->getResourceNameFromAlias($resourceAlias);
262
        $filename = $resource.'.yaml';
263
264
        return sprintf('%s/%s/%s', $this->projectDir.'/config/packages/grids', $section, $filename);
265
    }
266
267
    private function formatFields(array $fields): string
268
    {
269
        $data = '';
270
271
        foreach ($fields as $field) {
272
            [$name, $type, $label, $sortable] = $field;
273
274
            $data .= <<<EOM
275
$name:
276
                    type: $type
277
                    label: $label
278
EOM;
279
280
            if (null !== $sortable) {
281
                $data .= <<<EOM
282
283
                    sortable: $sortable
284
EOM;
285
            }
286
        }
287
288
        return $data;
289
    }
290
291
    private function formatActions(array $actions): string
0 ignored issues
show
Unused Code introduced by
The parameter $actions 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...
292
    {
293
        return '';
294
    }
295
}
296