Completed
Push — master ( b71b82...076f7e )
by Song
02:33
created

Form::modalSmall()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 6
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Encore\Admin\Actions\Interactor;
4
5
use Encore\Admin\Actions\Action;
6
use Encore\Admin\Actions\RowAction;
7
use Encore\Admin\Admin;
8
use Encore\Admin\Form\Field;
9
use Illuminate\Http\Request;
10
use Illuminate\Support\MessageBag;
11
use Illuminate\Validation\ValidationException;
12
use Illuminate\Validation\Validator;
13
use Symfony\Component\DomCrawler\Crawler;
14
15
class Form extends Interactor
16
{
17
    /**
18
     * @var array
19
     */
20
    protected $fields = [];
21
22
    /**
23
     * @var string
24
     */
25
    protected $modalId;
26
27
    /**
28
     * @var string
29
     */
30
    protected $modalSize = '';
31
32
    /**
33
     * @var string
34
     */
35
    protected $confirm = '';
36
37
    /**
38
     * @param string $label
39
     *
40
     * @return array
41
     */
42
    protected function formatLabel($label)
43
    {
44
        return array_filter((array) $label);
45
    }
46
47
    /**
48
     * @param string $column
49
     * @param string $label
50
     *
51
     * @return Field\Text
52
     */
53
    public function text($column, $label = '')
54
    {
55
        $field = new Field\Text($column, $this->formatLabel($label));
56
57
        $this->addField($field);
58
59
        return $field;
60
    }
61
62
    /**
63
     * @param $column
64
     * @param string   $label
65
     * @param \Closure $builder
66
     *
67
     * @return Field\Table
68
     */
69
    public function table($column, $label = '', $builder = null)
70
    {
71
        $field = new Field\Table($column, [$label, $builder]);
72
73
        $this->addField($field);
74
75
        return $field;
76
    }
77
78
    /**
79
     * @param string $column
80
     * @param string $label
81
     *
82
     * @return Field\Text
83
     */
84
    public function email($column, $label = '')
85
    {
86
        $field = new Field\Email($column, $this->formatLabel($label));
87
88
        $this->addField($field)->setView('admin::actions.form.text');
89
90
        return $field->inputmask(['alias' => 'email']);
91
    }
92
93
    /**
94
     * @param string $column
95
     * @param string $label
96
     *
97
     * @return Field\Text
98
     */
99
    public function integer($column, $label = '')
100
    {
101
        return $this->text($column, $label)
102
            ->width('200px')
103
            ->inputmask(['alias' => 'integer']);
104
    }
105
106
    /**
107
     * @param string $column
108
     * @param string $label
109
     *
110
     * @return Field\Text
111
     */
112
    public function ip($column, $label = '')
113
    {
114
        return $this->text($column, $label)
115
            ->width('200px')
116
            ->inputmask(['alias' => 'ip']);
117
    }
118
119
    /**
120
     * @param string $column
121
     * @param string $label
122
     *
123
     * @return Field\Text
124
     */
125
    public function url($column, $label = '')
126
    {
127
        return $this->text($column, $label)
128
            ->inputmask(['alias' => 'url'])
129
            ->width('200px');
130
    }
131
132
    /**
133
     * @param string $column
134
     * @param string $label
135
     *
136
     * @return Field\Text
137
     */
138
    public function password($column, $label = '')
139
    {
140
        return $this->text($column, $label)
141
            ->attribute('type', 'password');
142
    }
143
144
    /**
145
     * @param string $column
146
     * @param string $label
147
     *
148
     * @return Field\Text
149
     */
150
    public function mobile($column, $label = '')
151
    {
152
        return $this->text($column, $label)
153
            ->inputmask(['mask' => '99999999999'])
154
            ->width('100px');
155
    }
156
157
    /**
158
     * @param string $column
159
     * @param string $label
160
     *
161
     * @return Field\Textarea
162
     */
163
    public function textarea($column, $label = '')
164
    {
165
        $field = new Field\Textarea($column, $this->formatLabel($label));
166
167
        $this->addField($field);
168
169
        return $field;
170
    }
171
172
    /**
173
     * @param string $column
174
     * @param string $label
175
     *
176
     * @return Field\Select
177
     */
178
    public function select($column, $label = '')
179
    {
180
        $field = new Field\Select($column, $this->formatLabel($label));
181
182
        $this->addField($field);
183
184
        return $field;
185
    }
186
187
    /**
188
     * @param string $column
189
     * @param string $label
190
     *
191
     * @return Field\MultipleSelect
192
     */
193
    public function multipleSelect($column, $label = '')
194
    {
195
        $field = new Field\MultipleSelect($column, $this->formatLabel($label));
196
197
        $this->addField($field);
198
199
        return $field;
200
    }
201
202
    /**
203
     * @param string $column
204
     * @param string $label
205
     *
206
     * @return Field\Checkbox
207
     */
208
    public function checkbox($column, $label = '')
209
    {
210
        $field = new Field\Checkbox($column, $this->formatLabel($label));
211
212
        $this->addField($field);
213
214
        return $field;
215
    }
216
217
    /**
218
     * @param string $column
219
     * @param string $label
220
     *
221
     * @return Field\Radio
222
     */
223
    public function radio($column, $label = '')
224
    {
225
        $field = new Field\Radio($column, $this->formatLabel($label));
226
227
        $this->addField($field);
228
229
        return $field;
230
    }
231
232
    /**
233
     * @param string $column
234
     * @param string $label
235
     *
236
     * @return Field\File
237
     */
238
    public function file($column, $label = '')
239
    {
240
        $field = new Field\File($column, $this->formatLabel($label));
241
242
        $this->addField($field);
243
244
        return $field;
245
    }
246
247
    /**
248
     * @param string $column
249
     * @param string $label
250
     *
251
     * @return Field\MultipleFile
252
     */
253
    public function multipleFile($column, $label = '')
254
    {
255
        $field = new Field\MultipleFile($column, $this->formatLabel($label));
256
257
        $this->addField($field);
258
259
        return $field;
260
    }
261
262
    /**
263
     * @param string $column
264
     * @param string $label
265
     *
266
     * @return Field\Image
267
     */
268
    public function image($column, $label = '')
269
    {
270
        $field = new Field\Image($column, $this->formatLabel($label));
271
272
        $this->addField($field)->setView('admin::actions.form.file');
273
274
        return $field;
275
    }
276
277
    /**
278
     * @param string $column
279
     * @param string $label
280
     *
281
     * @return Field\MultipleImage
282
     */
283
    public function multipleImage($column, $label = '')
284
    {
285
        $field = new Field\MultipleImage($column, $this->formatLabel($label));
286
287
        $this->addField($field)->setView('admin::actions.form.muitplefile');
288
289
        return $field;
290
    }
291
292
    /**
293
     * @param string $column
294
     * @param string $label
295
     *
296
     * @return Field\Date
297
     */
298
    public function date($column, $label = '')
299
    {
300
        $field = new Field\Date($column, $this->formatLabel($label));
301
302
        $this->addField($field);
303
304
        return $field;
305
    }
306
307
    /**
308
     * @param string $column
309
     * @param string $label
310
     *
311
     * @return Field\Date
312
     */
313
    public function datetime($column, $label = '')
314
    {
315
        return $this->date($column, $label)->format('YYYY-MM-DD HH:mm:ss');
316
    }
317
318
    /**
319
     * @param string $column
320
     * @param string $label
321
     *
322
     * @return Field\Date
323
     */
324
    public function time($column, $label = '')
325
    {
326
        return $this->date($column, $label)->format('HH:mm:ss');
327
    }
328
329
    /**
330
     * @param string $column
331
     * @param string $label
332
     *
333
     * @return Field\Hidden
334
     */
335
    public function hidden($column, $label = '')
336
    {
337
        $field = new Field\Hidden($column, $this->formatLabel($label));
338
339
        $this->addField($field);
340
341
        return $field;
342
    }
343
344
    /**
345
     * @param $message
346
     * @return $this
347
     */
348
    public function confirm($message)
349
    {
350
        $this->confirm = $message;
351
352
        return $this;
353
    }
354
355
    /**
356
     * @return $this
357
     */
358
    public function modalLarge()
359
    {
360
        $this->modalSize = 'modal-lg';
361
362
        return $this;
363
    }
364
365
    /**
366
     * @return $this
367
     */
368
    public function modalSmall()
369
    {
370
        $this->modalSize = 'modal-sm';
371
372
        return $this;
373
    }
374
375
    /**
376
     * @param string $content
377
     * @param string $selector
378
     *
379
     * @return string
380
     */
381
    public function addElementAttr($content, $selector)
382
    {
383
        $crawler = new Crawler($content);
384
385
        $node = $crawler->filter($selector)->getNode(0);
386
        $node->setAttribute('modal', $this->getModalId());
387
388
        return $crawler->children()->html();
389
    }
390
391
    /**
392
     * @param Field $field
393
     *
394
     * @return Field
395
     */
396 View Code Duplication
    protected function addField(Field $field)
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...
397
    {
398
        $elementClass = array_merge(['action'], $field->getElementClass());
399
400
        $field->addElementClass($elementClass);
401
402
        $field->setView($this->resolveView(get_class($field)));
403
404
        array_push($this->fields, $field);
405
406
        return $field;
407
    }
408
409
    /**
410
     * @param Request $request
411
     *
412
     * @throws ValidationException
413
     * @throws \Exception
414
     *
415
     * @return void
416
     */
417
    public function validate(Request $request)
418
    {
419 View Code Duplication
        if ($this->action instanceof RowAction) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
420
            call_user_func([$this->action, 'form'], $this->action->getRow());
421
        } else {
422
            call_user_func([$this->action, 'form']);
423
        }
424
425
        $failedValidators = [];
426
427
        /** @var Field $field */
428 View Code Duplication
        foreach ($this->fields as $field) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
429
            if (!$validator = $field->getValidator($request->all())) {
430
                continue;
431
            }
432
433
            if (($validator instanceof Validator) && !$validator->passes()) {
434
                $failedValidators[] = $validator;
435
            }
436
        }
437
438
        $message = $this->mergeValidationMessages($failedValidators);
439
440
        if ($message->any()) {
441
            throw ValidationException::withMessages($message->toArray());
442
        }
443
    }
444
445
    /**
446
     * Merge validation messages from input validators.
447
     *
448
     * @param \Illuminate\Validation\Validator[] $validators
449
     *
450
     * @return MessageBag
451
     */
452
    protected function mergeValidationMessages($validators)
453
    {
454
        $messageBag = new MessageBag();
455
456
        foreach ($validators as $validator) {
457
            $messageBag = $messageBag->merge($validator->messages());
458
        }
459
460
        return $messageBag;
461
    }
462
463
    /**
464
     * @param string $class
465
     *
466
     * @return string
467
     */
468 View Code Duplication
    protected function resolveView($class)
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...
469
    {
470
        $path = explode('\\', $class);
471
472
        $name = strtolower(array_pop($path));
473
474
        return "admin::actions.form.{$name}";
475
    }
476
477
    /**
478
     * @return void
479
     */
480
    public function addModalHtml()
481
    {
482
        $data = [
483
            'fields'     => $this->fields,
484
            'title'      => $this->action->name(),
485
            'modal_id'   => $this->getModalId(),
486
            'modal_size' => $this->modalSize,
487
        ];
488
489
        $modal = view('admin::actions.form.modal', $data)->render();
0 ignored issues
show
Bug introduced by
The method render does only exist in Illuminate\View\View, but not in Illuminate\Contracts\View\Factory.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
490
491
        Admin::html($modal);
492
    }
493
494
    /**
495
     * @return string
496
     */
497
    public function getModalId()
498
    {
499
        if (!$this->modalId) {
500
            if ($this->action instanceof RowAction) {
501
                $this->modalId = uniqid('row-action-modal-').mt_rand(1000, 9999);
502
            } else {
503
                $this->modalId = strtolower(str_replace('\\', '-', get_class($this->action)));
504
            }
505
        }
506
507
        return $this->modalId;
508
    }
509
510
    /**
511
     * @return void
512
     */
513
    public function addScript()
514
    {
515
        $this->action->attribute('modal', $this->getModalId());
516
517
        $parameters = json_encode($this->action->parameters());
518
519
        $script = <<<SCRIPT
520
521
(function ($) {
522
    $('{$this->action->selector($this->action->selectorPrefix)}').off('{$this->action->event}').on('{$this->action->event}', function() {
523
        var data = $(this).data();
524
        var target = $(this);
525
        var modalId = $(this).attr('modal');
526
        Object.assign(data, {$parameters});
527
        {$this->action->actionScript()}
528
        $('#'+modalId).modal('show');
529
        $('#'+modalId+' form').off('submit').on('submit', function (e) {
530
            e.preventDefault();
531
            var form = this;
532
            {$this->buildActionPromise()}
533
            {$this->action->handleActionPromise()}
534
        });
535
    });
536
})(jQuery);
537
538
SCRIPT;
539
540
        Admin::script($script);
541
    }
542
543
    /**
544
     * @return string
545
     */
546
    protected function buildConfirmActionPromise()
547
    {
548
        $trans = [
549
            'cancel' => trans('admin.cancel'),
550
            'submit' => trans('admin.submit'),
551
        ];
552
553
        $settings = [
554
            'type'                => 'question',
555
            'showCancelButton'    => true,
556
            'showLoaderOnConfirm' => true,
557
            'confirmButtonText'   => $trans['submit'],
558
            'cancelButtonText'    => $trans['cancel'],
559
            'title'               => $this->confirm,
560
            'text'                => '',
561
        ];
562
563
        $settings = trim(substr(json_encode($settings, JSON_PRETTY_PRINT), 1, -1));
564
565
        return <<<PROMISE
566
        var process = $.admin.swal({
567
            {$settings},
568
            preConfirm: function() {
569
                {$this->buildGeneralActionPromise()}
570
571
                return process;
572
            }
573
        }).then(function(result) {
574
575
            if (typeof result.dismiss !== 'undefined') {
576
                return Promise.reject();
577
            }
578
579
            var result = result.value[0];
580
581
            if (typeof result.status === "boolean") {
582
                var response = result;
583
            } else {
584
                var response = result.value;
585
            }
586
587
            return [response, target];
588
        });
589
PROMISE;
590
    }
591
592
    protected function buildGeneralActionPromise()
593
    {
594
        return <<<SCRIPT
595
        var process = new Promise(function (resolve,reject) {
596
            Object.assign(data, {
597
                _token: $.admin.token,
598
                _action: '{$this->action->getCalledClass()}',
599
            });
600
601
            var formData = new FormData(form);
602
            for (var key in data) {
603
                formData.append(key, data[key]);
604
            }
605
606
            $.ajax({
607
                method: '{$this->action->getMethod()}',
608
                url: '{$this->action->getHandleRoute()}',
609
                data: formData,
610
                cache: false,
611
                contentType: false,
612
                processData: false,
613
                success: function (data) {
614
                    resolve([data, target]);
615
                    if (data.status === true) {
616
                        $('#'+modalId).modal('hide');
617
                    }
618
                },
619
                error:function(request){
620
                    reject(request);
621
                }
622
            });
623
        });
624
SCRIPT;
625
    }
626
627
    /**
628
     * @throws \Exception
629
     *
630
     * @return string
631
     */
632
    protected function buildActionPromise()
633
    {
634 View Code Duplication
        if ($this->action instanceof RowAction) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
635
            call_user_func([$this->action, 'form'], $this->action->getRow());
636
        } else {
637
            call_user_func([$this->action, 'form']);
638
        }
639
640
        $this->addModalHtml();
641
642
        if (!empty($this->confirm)) {
643
            return $this->buildConfirmActionPromise();
644
        }
645
646
        return $this->buildGeneralActionPromise();
647
    }
648
}
649