Completed
Push — master ( 67f65f...23a098 )
by Song
14s queued 10s
created

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