Passed
Push — master ( 9a53bc...14e3bb )
by Bruno
08:14
created

FrontendGenerator::makeVuePaginationComponent()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 15
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
eloc 9
c 0
b 0
f 0
dl 0
loc 15
ccs 0
cts 9
cp 0
rs 9.9666
cc 1
nc 1
nop 0
crap 2
1
<?php declare(strict_types=1);
2
3
namespace Modelarium\Frontend;
4
5
use Formularium\Datatype;
6
use Formularium\Element;
7
use Formularium\Field;
8
use Formularium\Model;
9
use Formularium\FrameworkComposer;
10
use Formularium\Frontend\Blade\Framework as FrameworkBlade;
11
use Formularium\Frontend\HTML\Element\Button;
12
use Formularium\Frontend\HTML\Element\Table;
13
use Formularium\Frontend\Vue\Element\Pagination as PaginationVue;
0 ignored issues
show
Bug introduced by
The type Formularium\Frontend\Vue\Element\Pagination was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
14
use Formularium\Frontend\Vue\Framework as FrameworkVue;
15
use Formularium\HTMLNode;
16
use Formularium\Renderable;
17
use Modelarium\GeneratedCollection;
18
use Modelarium\GeneratedItem;
19
use Modelarium\GeneratorInterface;
20
use Modelarium\GeneratorNameTrait;
21
22
use function Safe\file_get_contents;
23
use function Safe\json_encode;
24
25
class FrontendGenerator implements GeneratorInterface
26
{
27
    use GeneratorNameTrait;
28
29
    /**
30
     * @var FrameworkComposer
31
     */
32
    protected $composer = null;
33
34
    /**
35
     * @var Model
36
     */
37
    protected $model = null;
38
39
    /**
40
     * @var GeneratedCollection
41
     */
42
    protected $collection;
43
44
    /**
45
     *
46
     * @var string
47
     */
48
    protected $stubDir = __DIR__ . '/stubs';
49
50
    /**
51
     * String substitution
52
     *
53
     * @var array
54
     */
55
    protected $templateParameters = [];
56
57
    /**
58
     * Card fields
59
     *
60
     * @var Field[]
61
     */
62
    protected $cardFields = [];
63
64
    /**
65
     * Table fields
66
     *
67
     * @var Field[]
68
     */
69
    protected $tableFields = [];
70
71
    public function __construct(FrameworkComposer $composer, Model $model)
72
    {
73
        $this->composer = $composer;
74
        $this->model = $model;
75
        $this->setBaseName($model->getName());
76
        $this->buildTemplateParameters();
77
    }
78
79
    public function generate(): GeneratedCollection
80
    {
81
        $this->collection = new GeneratedCollection();
82
83
        /**
84
         * @var FrameworkVue $vue
85
         */
86
        $vue = $this->composer->getByName('Vue');
87
        // $blade = FrameworkComposer::getByName('Blade');
88
89
        if ($vue !== null) {
90
            $cardFieldNames = array_map(function (Field $f) {
91
                return $f->getName();
92
            }, $this->cardFields);
93
            $tableFieldNames = array_map(function (Field $f) {
94
                return $f->getName();
95
            }, $this->tableFields);
96
97
            $vue->setFieldModelVariable('model.');
98
            $vue->setExtraProps([
99
                [
100
                    'name' => 'id',
101
                    'type' => 'String',
102
                    'required' => true
103
                ]
104
            ]);
105
            $this->makeJSModel();
106
            $this->makeVue($vue, 'Card', 'viewable', $cardFieldNames);
107
            $this->makeVue($vue, 'List', 'viewable');
108
            $this->makeVue($vue, 'Table', 'viewable');
109
            $this->makeVue($vue, 'TableItem', 'viewable', $tableFieldNames);
110
            $this->makeVue($vue, 'Show', 'viewable');
111
            $this->makeVue($vue, 'Edit', 'editable');
112
            $this->makeVue($vue, 'Form', 'editable');
113
            $this->makeVueRoutes();
114
            $this->makeVueIndex();
115
            $this->makeVuePaginationComponent();
116
        }
117
118
        $this->makeGraphql();
119
120
        return $this->collection;
121
    }
122
123
    protected function makeVuePaginationComponent(): void
124
    {
125
        $pagination = $this->composer->nodeElement(
126
            'Pagination',
127
            [
128
            ]
129
        );
130
        $html = $pagination->getRenderHTML();
131
        $script = PaginationVue::script();
132
133
        $this->collection->push(
134
            new GeneratedItem(
135
                GeneratedItem::TYPE_FRONTEND,
136
                "<template>\n$html\n</template>\n<script>\n$script\n</script>\n",
137
                "Pagination.vue"
138
            )
139
        );
140
    }
141
142
    protected function buildTemplateParameters(): void
143
    {
144
        $this->cardFields = $this->model->filterField(
145
            function (Field $field) {
146
                return $field->getRenderable('card', false);
147
            }
148
        );
149
        $this->tableFields = $this->model->filterField(
150
            function (Field $field) {
151
                return $field->getRenderable('table', false);
152
            }
153
        );
154
        if (!$this->tableFields) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->tableFields of type array 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...
155
            $this->tableFields = $this->cardFields;
156
        }
157
158
        $buttonCreate = $this->composer->nodeElement(
159
            'Button',
160
            [
161
                Button::TYPE => 'a',
162
                Button::ATTRIBUTES => ['href' => "/{$this->lowerName}/edit" ],
163
            ]
164
        )->setContent(
165
            '<i class="fa fa-plus"></i> Add new',
166
            true,
167
            true
168
        )->getRenderHTML();
169
170
        $buttonEdit = $this->composer->nodeElement(
171
            'Button',
172
            [
173
                Button::TYPE => ($this->composer->getByName('Vue') ? 'router-link' : 'a'),
174
                Button::ATTRIBUTES => [':to' => "'/{$this->lowerName}/' + model.id + '/edit'"],
175
            ]
176
        )->setContent(
177
            '<i class="fa fa-pencil"></i> Edit',
178
            true,
179
            true
180
        )->getRenderHTML();
181
182
        $buttonDelete = $this->composer->nodeElement(
183
            'Button',
184
            [
185
                Button::TYPE => 'a',
186
                Button::COLOR => Button::COLOR_WARNING,
187
                Button::ATTRIBUTES => [
188
                    'href' => '#',
189
                    '@click.prevent' => 'remove'
190
                ],
191
            ]
192
        )->setContent(
193
            '<i class="fa fa-trash"></i> Delete',
194
            true,
195
            true
196
        )->getRenderHTML();
197
198
        /*
199
         * table
200
         */
201
        $table = $this->composer->nodeElement(
202
            'Table',
203
            [
204
                Table::ROW_NAMES => array_map(
205
                    function (Field $field) {
206
                        return $field->getRenderable(Renderable::LABEL, $field->getName());
207
                    },
208
                    $this->tableFields
209
                ),
210
                Table::STRIPED => true
211
            ]
212
        );
213
        /**
214
         * @var HTMLNode $tbody
215
         */
216
        $tbody = $table->get('tbody')[0];
217
        $tbody->setContent(
218
            '<' . $this->studlyName . 'TableItem v-for="l in list" :key="l.id" v-bind="l"></' . $this->studlyName . 'TableItem>',
219
            true,
220
            true
221
        );
222
        $titleFields = $this->model->filterField(
223
            function (Field $field) {
224
                return $field->getRenderable('title', false);
225
            }
226
        );
227
228
        $spinner = $this->composer->nodeElement('Spinner')
229
        ->addAttribute(
230
            'v-if',
231
            'isLoading'
232
        )->getRenderHTML();
233
        var_dump($spinner);
0 ignored issues
show
Security Debugging Code introduced by
var_dump($spinner) looks like debug code. Are you sure you do not want to remove it?
Loading history...
234
        $this->templateParameters = [
235
            'buttonSubmit' => $this->composer->element(
236
                'Button',
237
                [
238
                    Button::TYPE => 'submit',
239
                    Element::LABEL => 'Submit'
240
                ]
241
            ),
242
            'buttonCreate' => $buttonCreate,
243
            'buttonEdit' => $buttonEdit,
244
            'buttonDelete' => $buttonDelete,
245
            // TODO 'hasCan' => $this->model
246
            'spinner' => $spinner,
247
            'tablelist' => $table->getRenderHTML(),
248
            'tableItemFields' => array_keys(array_map(function (Field $f) {
249
                return $f->getName();
250
            }, $this->tableFields)),
251
            'titleField' => array_key_first($titleFields) ?: 'id'
252
        ];
253
    }
254
255
    public function templateCallback(string $stub, FrameworkVue $vue, array $data, Model $m): string
0 ignored issues
show
Unused Code introduced by
The parameter $m is not used and could be removed. ( Ignorable by Annotation )

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

255
    public function templateCallback(string $stub, FrameworkVue $vue, array $data, /** @scrutinizer ignore-unused */ Model $m): string

This check looks for 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 $vue is not used and could be removed. ( Ignorable by Annotation )

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

255
    public function templateCallback(string $stub, /** @scrutinizer ignore-unused */ FrameworkVue $vue, array $data, Model $m): string

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

Loading history...
256
    {
257
        $x = $this->templateFile(
258
            $stub,
259
            array_merge(
260
                $this->templateParameters,
261
                $data
262
            )
263
        );
264
        return $x;
265
    }
266
267
    protected function makeVue(FrameworkVue $vue, string $component, string $mode, array $restrictFields = null): void
268
    {
269
        $path = $this->model->getName() . '/' .
270
            $this->model->getName() . $component . '.vue';
271
272
        $stub = $this->stubDir . "/Vue{$component}.mustache.vue";
273
274
        if ($mode == 'editable') {
275
            $vue->setEditableTemplate(
276
                function (FrameworkVue $vue, array $data, Model $m) use ($stub) {
277
                    return $this->templateCallback($stub, $vue, $data, $m);
278
                }
279
            );
280
281
            $this->collection->push(
282
                new GeneratedItem(
283
                    GeneratedItem::TYPE_FRONTEND,
284
                    $this->model->editable($this->composer, [], $restrictFields),
285
                    $path
286
                )
287
            );
288
        } else {
289
            $vue->setViewableTemplate(
290
                function (FrameworkVue $vue, array $data, Model $m) use ($stub) {
291
                    return $this->templateCallback($stub, $vue, $data, $m);
292
                }
293
            );
294
295
            $this->collection->push(
296
                new GeneratedItem(
297
                    GeneratedItem::TYPE_FRONTEND,
298
                    $this->model->viewable($this->composer, [], $restrictFields),
299
                    $path
300
                )
301
            );
302
        }
303
    }
304
305
    protected function getFilters(): array
306
    {
307
        $filters = [];
308
        return $filters;
309
    }
310
311
    protected function makeGraphql(): void
312
    {
313
        /*
314
         * card
315
         */
316
        $cardFieldNames = array_map(
317
            function (Field $field) {
318
                return $field->getName();
319
            },
320
            $this->cardFields
321
        );
322
        $cardFieldParameters = implode("\n", $cardFieldNames);
323
324
        $listQuery = <<<EOF
325
query (\$page: Int!) {
326
    {$this->lowerNamePlural}(page: \$page) {
327
        data {
328
            id
329
            $cardFieldParameters
330
        }
331
      
332
        paginatorInfo {
333
            currentPage
334
            perPage
335
            total
336
            lastPage
337
        }
338
    }
339
}
340
EOF;
341
        $this->collection->push(
342
            new GeneratedItem(
343
                GeneratedItem::TYPE_FRONTEND,
344
                $listQuery,
345
                $this->model->getName() . '/queryList.graphql'
346
            )
347
        );
348
349
        /*
350
         * table
351
         */
352
        $tableFieldNames = array_map(
353
            function (Field $field) {
354
                return $field->getName();
355
            },
356
            $this->tableFields
357
        );
358
        $tableFieldParameters = implode("\n", $tableFieldNames);
359
360
        $tableQuery = <<<EOF
361
query (\$page: Int!) {
362
    {$this->lowerNamePlural}(page: \$page) {
363
        data {
364
            id
365
            $tableFieldParameters
366
        }
367
      
368
        paginatorInfo {
369
            currentPage
370
            perPage
371
            total
372
            lastPage
373
        }
374
    }
375
}
376
EOF;
377
        $this->collection->push(
378
            new GeneratedItem(
379
                GeneratedItem::TYPE_FRONTEND,
380
                $tableQuery,
381
                $this->model->getName() . '/queryTable.graphql'
382
            )
383
        );
384
385
        /*
386
         * item
387
         */
388
        $graphqlQuery = $this->model->toGraphqlQuery();
389
        $itemQuery = <<<EOF
390
query (\$id: ID!) {
391
    {$this->lowerName}(id: \$id) {
392
        id
393
        $graphqlQuery
394
    }
395
}
396
EOF;
397
398
        $this->collection->push(
399
            new GeneratedItem(
400
                GeneratedItem::TYPE_FRONTEND,
401
                $itemQuery,
402
                $this->model->getName() . '/queryItem.graphql'
403
            )
404
        );
405
406
        $upsertMutation = <<<EOF
407
mutation upsert(\${$this->lowerName}: {$this->studlyName}Input!) {
408
    upsert{$this->studlyName}(input: \${$this->lowerName}) {
409
        id
410
    }
411
}
412
EOF;
413
        $this->collection->push(
414
            new GeneratedItem(
415
                GeneratedItem::TYPE_FRONTEND,
416
                $upsertMutation,
417
                $this->model->getName() . '/mutationUpsert.graphql'
418
            )
419
        );
420
421
        $deleteMutation = <<<EOF
422
mutation delete(\$id: ID!) {
423
    delete{$this->studlyName}(id: \$id) {
424
        id
425
    }
426
}
427
EOF;
428
        $this->collection->push(
429
            new GeneratedItem(
430
                GeneratedItem::TYPE_FRONTEND,
431
                $deleteMutation,
432
                $this->model->getName() . '/mutationDelete.graphql'
433
            )
434
        );
435
    }
436
437
    protected function makeVueIndex(): void
438
    {
439
        $path = $this->model->getName() . '/index.js';
440
        $name = $this->studlyName;
441
442
        $items = [
443
            'Card',
444
            'Edit',
445
            'List',
446
            'Show',
447
            'Table',
448
        ];
449
450
        $import = array_map(
451
            function ($i) use ($name) {
452
                return "import {$name}$i from './{$name}$i.vue';";
453
            },
454
            $items
455
        );
456
457
        $export = array_map(
458
            function ($i) use ($name) {
459
                return "    {$name}$i,\n";
460
            },
461
            $items
462
        );
463
464
        $this->collection->push(
465
            new GeneratedItem(
466
                GeneratedItem::TYPE_FRONTEND,
467
                implode("\n", $import) . "\n" .
468
                "export {\n" .
469
                implode("\n", $export) . "\n};\n",
470
                $path
471
            )
472
        );
473
    }
474
475
    protected function makeVueRoutes(): void
476
    {
477
        $path = $this->model->getName() . '/routes.js';
478
479
        $this->collection->push(
480
            new GeneratedItem(
481
                GeneratedItem::TYPE_FRONTEND,
482
                $this->templateFile($this->stubDir . "/routes.mustache.js"),
483
                $path
484
            )
485
        );
486
    }
487
488
    protected function makeJSModel(): void
489
    {
490
        $path = $this->model->getName() . '/model.js';
491
        $modelValues = $this->model->getDefault();
492
        $modelValues['id'] = 0;
493
        $modelJS = 'const model = ' . json_encode($modelValues) .
494
            ";\n\nexport default model;\n";
495
        
496
        $this->collection->push(
497
            new GeneratedItem(
498
                GeneratedItem::TYPE_FRONTEND,
499
                $modelJS,
500
                $path
501
            )
502
        );
503
    }
504
}
505