Completed
Push — master ( 1d3c0c...8bf0fe )
by Song
03:06
created

Form::radio()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

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