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

MakeGrid::generate()   B

Complexity

Conditions 7
Paths 15

Size

Total Lines 45

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 45
rs 8.2666
c 0
b 0
f 0
cc 7
nc 15
nop 3
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 Symfony\Component\Yaml\Yaml;
29
use Webmozart\Assert\Assert;
30
31
final class MakeGrid extends AbstractMaker
32
{
33
    /** @var string */
34
    private $projectDir;
35
36
    /** @var ResourceHelper */
37
    private $resourceHelper;
38
39
    /** @var GridHelper */
40
    private $gridHelper;
41
42
    /** @var Filesystem */
43
    private $fileSystem;
44
45
    public function __construct(string $projectDir, ResourceHelper $resourceHelper, GridHelper $gridHelper)
46
    {
47
        $this->projectDir = $projectDir;
48
        $this->resourceHelper = $resourceHelper;
49
        $this->gridHelper = $gridHelper;
50
51
        $this->fileSystem = new Filesystem();
52
    }
53
54
    public static function getCommandName(): string
55
    {
56
        return 'make:sylius-grid';
57
    }
58
59
    public function configureCommand(Command $command, InputConfiguration $inputConfig)
60
    {
61
        $command
62
            ->setDescription('Creates a new grid')
63
            ->addArgument('section', InputArgument::REQUIRED, 'Section of the grid (backend or frontend)')
64
            ->addArgument('resource', InputArgument::REQUIRED, 'Resource alias of the grid')
65
        ;
66
67
        $inputConfig->setArgumentAsNonInteractive('resource');
68
        $inputConfig->setArgumentAsNonInteractive('section');
69
    }
70
71
    public function interact(InputInterface $input, ConsoleStyle $io, Command $command)
72
    {
73
        if (!$input->getArgument('section')) {
74
            $question = new ChoiceQuestion(
75
                'Please select a section for your grid',
76
                ['backend', 'frontend'],
77
                0
78
            );
79
80
            $section = $io->askQuestion($question);
81
82
            $input->setArgument('section', $section);
83
        }
84
85
        if (!$input->getArgument('resource')) {
86
            $question = new ChoiceQuestion(
87
                'Please select a resource for your grid',
88
                $this->resourceHelper->getResourcesAliases(),
89
                0
90
            );
91
92
            $resourceAlias = $io->askQuestion($question);
93
94
            $input->setArgument('resource', $resourceAlias);
95
        }
96
97
        if ($resourceAlias = $input->getArgument('resource')) {
98
            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 97 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...
99
                    'Resource with alias %s not found',
100
                    $resourceAlias
101
                )
102
            );
103
        }
104
    }
105
106
    public function configureDependencies(DependencyBuilder $dependencies)
107
    {
108
    }
109
110
    public function generate(InputInterface $input, ConsoleStyle $io, Generator $generator)
111
    {
112
        $resourceAlias = $input->getArgument('resource');
113
114
        $fields = [];
115
        $isFirstField = true;
116
        while (true) {
117
            $newField = $this->askForNextField($io, $isFirstField);
118
            $isFirstField = false;
119
120
            if (null === $newField) {
121
                break;
122
            }
123
124
            $fields = array_merge($fields, $newField);
125
        }
126
127
        $actions = [
128
            'main' => [],
129
            'item' => [],
130
            'bulk' => [],
131
        ];
132
133
        foreach ($actions as $section => $data) {
134
            $hasSectionAction = $io->confirm(sprintf('Do you have %s actions?', $section), false);
135
136
            if ($hasSectionAction) {
137
                $isFirstAction = true;
138
                while (true) {
139
                    $newAction = $this->askForNextAction($io, $isFirstAction);
140
                    $isFirstAction = false;
141
142
                    if (null === $newAction) {
143
                        break;
144
                    }
145
146
                    $actions[$section] = array_merge($actions[$section], $newAction);
147
                }
148
            } else {
149
                unset($actions[$section]);
150
            }
151
        }
152
153
        $this->generateGridConfigFile($input, $io, $generator, $fields, $actions);
154
    }
155
156
    private function askForNextField(ConsoleStyle $io, bool $isFirstField)
157
    {
158
        $io->writeln('');
159
160
        if ($isFirstField) {
161
            $questionText = 'New field name (press <return> to stop adding fields)';
162
        } else {
163
            $questionText = 'Add another field? Enter the field name (or press <return> to stop adding fields)';
164
        }
165
166
        $fieldName = $io->ask($questionText, null, function ($name) {
167
            // allow it to be empty
168
            if (!$name) {
169
                return $name;
170
            }
171
172
            return $name;
173
        });
174
175
        if (!$fieldName) {
176
            return null;
177
        }
178
179
        $fieldType = $io->choice('Enter the field type', $this->gridHelper->getFilterIds(), 'string');
180
        $fieldLabel = $io->ask('Enter the field label', '~');
181
        $isSortable = $io->confirm('Is the field sortable?', true);
182
183
        if ($isSortable) {
184
            $fieldSortable = $io->ask('Enter the sortable path', '~');
185
        }
186
187
        $fieldData = [
188
            'type' => $fieldType,
189
            'label' => $fieldLabel,
190
        ];
191
192
        if ($isSortable) {
193
            $fieldData['sortable'] = $fieldSortable;
194
        }
195
196
        return [
197
            $fieldName => [
198
                'type' => $fieldType,
199
                'label' => $fieldLabel,
200
                'sortable' => $fieldSortable ?? null,
201
            ],
202
        ];
203
    }
204
205
    private function askForNextAction(ConsoleStyle $io, bool $isFirstAction)
206
    {
207
        $io->writeln('');
208
209
        if ($isFirstAction) {
210
            $questionText = 'New action name (press <return> to stop adding actions)';
211
        } else {
212
            $questionText = 'Add another action? Enter the action name (or press <return> to stop adding actions)';
213
        }
214
215
        $actionName = $io->ask($questionText, null, function ($name) {
216
            // allow it to be empty
217
            if (!$name) {
218
                return $name;
219
            }
220
221
            return $name;
222
        });
223
224
        if (!$actionName) {
225
            return null;
226
        }
227
228
        $actionType = $io->choice('Enter the action type', ['create', 'update', 'delete'], $actionName);
229
230
        return [
231
            $actionName => [
232
                'type' => $actionType,
233
            ],
234
        ];
235
    }
236
237
    private function generateGridConfigFile(
238
        InputInterface $input,
239
        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...
240
        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...
241
        array $fields,
242
        array $actions
243
    ): void {
244
        $section = $input->getArgument('section');
245
        $resourceAlias = $input->getArgument('resource');
246
        [$appName, $resourceName] = $this->resourceHelper->splitResourceAlias($resourceAlias);
0 ignored issues
show
Bug introduced by
It seems like $resourceAlias defined by $input->getArgument('resource') on line 245 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...
247
        $gridId = sprintf('%s_%s_%s', $appName, $section, $resourceName);
248
249
        $gridConfigDir = $this->getGridConfigDir($resourceAlias, $section);
0 ignored issues
show
Bug introduced by
It seems like $resourceAlias defined by $input->getArgument('resource') on line 245 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 244 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...
250
        $modelClass = $this->resourceHelper->getResourceModelFromAlias($resourceAlias);
0 ignored issues
show
Bug introduced by
It seems like $resourceAlias defined by $input->getArgument('resource') on line 245 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...
251
252
        $gridData = [
253
            'driver' => [
254
                'name' => 'doctrine/orm',
255
                'options' => [
256
                    'class' => '"%'.$modelClass.'%"',
257
                ],
258
            ],
259
        ];
260
261
        if (count($fields) > 0) {
262
            $gridData['fields'] = $fields;
263
        }
264
265
        if (count($actions) > 0) {
266
            $gridData['actions'] = $actions;
267
        }
268
269
        $data = [
270
            'sylius_grids' => [
271
                'grids' => [
272
                    $gridId => $gridData,
273
                ],
274
            ],
275
        ];
276
277
        $yaml = Yaml::dump($data, 10);
278
279
        $this->fileSystem->dumpFile($gridConfigDir, $yaml);
280
    }
281
282
    private function getGridConfigDir(string $resourceAlias, string $section)
283
    {
284
        $resource = $this->resourceHelper->getResourceNameFromAlias($resourceAlias);
285
        $filename = $resource.'.yaml';
286
287
        return sprintf('%s/%s/%s', $this->projectDir.'/config/packages/grids', $section, $filename);
288
    }
289
}
290