Completed
Pull Request — master (#1350)
by
unknown
02:38
created

Builder::submitButton()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 22
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 13
nc 4
nop 0
dl 0
loc 22
rs 8.9197
c 0
b 0
f 0
1
<?php
2
3
namespace Encore\Admin\Form;
4
5
use Encore\Admin\Admin;
6
use Encore\Admin\Form;
7
use Illuminate\Support\Collection;
8
use Illuminate\Support\Facades\URL;
9
use Illuminate\Support\Str;
10
11
/**
12
 * Class Builder.
13
 */
14
class Builder
15
{
16
    /**
17
     *  Previous url key.
18
     */
19
    const PREVIOUS_URL_KEY = '_previous_';
20
21
    /**
22
     * @var mixed
23
     */
24
    protected $id;
25
26
    /**
27
     * @var Form
28
     */
29
    protected $form;
30
31
    /**
32
     * @var
33
     */
34
    protected $action;
35
36
    /**
37
     * @var Collection
38
     */
39
    protected $fields;
40
41
    /**
42
     * @var array
43
     */
44
    protected $options = [
45
        'enableSubmit' => true,
46
        'enableReset'  => true,
47
    ];
48
49
    /**
50
     * Modes constants.
51
     */
52
    const MODE_VIEW = 'view';
53
    const MODE_EDIT = 'edit';
54
    const MODE_CREATE = 'create';
55
56
    /**
57
     * Form action mode, could be create|view|edit.
58
     *
59
     * @var string
60
     */
61
    protected $mode = 'create';
62
63
    /**
64
     * @var array
65
     */
66
    protected $hiddenFields = [];
67
68
    /**
69
     * @var Tools
70
     */
71
    protected $tools;
72
73
    /**
74
     * Width for label and field.
75
     *
76
     * @var array
77
     */
78
    protected $width = [
79
        'label' => 2,
80
        'field' => 8,
81
    ];
82
83
    /**
84
     * View for this form.
85
     *
86
     * @var string
87
     */
88
    protected $view = 'admin::form';
89
90
    /**
91
     * @var
92
     */
93
    public $Rules = [];
94
95
    /**
96
     * @var
97
     */
98
    public $RuleMessages = [];
99
100
    /**
101
     * @var string
102
     */
103
    public $Title = '';
104
105
    /**
106
     * Builder constructor.
107
     *
108
     * @param Form $form
109
     */
110
    public function __construct(Form $form)
111
    {
112
        $this->form = $form;
113
114
        $this->fields = new Collection();
115
116
        $this->setupTools();
117
    }
118
119
    /**
120
     * Setup grid tools.
121
     */
122
    public function setupTools()
123
    {
124
        $this->tools = new Tools($this);
125
    }
126
127
    /**
128
     * @return Tools
129
     */
130
    public function getTools()
131
    {
132
        return $this->tools;
133
    }
134
135
    /**
136
     * Set the builder mode.
137
     *
138
     * @param string $mode
139
     *
140
     * @return void
141
     */
142
    public function setMode($mode = 'create')
143
    {
144
        $this->mode = $mode;
145
    }
146
147
    /**
148
     * Returns builder is $mode.
149
     *
150
     * @param $mode
151
     *
152
     * @return bool
153
     */
154
    public function isMode($mode)
155
    {
156
        return $this->mode == $mode;
157
    }
158
159
    /**
160
     * Set resource Id.
161
     *
162
     * @param $id
163
     *
164
     * @return void
165
     */
166
    public function setResourceId($id)
167
    {
168
        $this->id = $id;
169
    }
170
171
    /**
172
     * @return string
173
     */
174
    public function getResource($slice = null)
175
    {
176
        if ($this->mode == self::MODE_CREATE) {
177
            return $this->form->resource(-1);
178
        }
179
        if ($slice !== null) {
180
            return $this->form->resource($slice);
181
        }
182
183
        return $this->form->resource();
184
    }
185
186
    /**
187
     * @param int $field
188
     * @param int $label
189
     *
190
     * @return $this
191
     */
192
    public function setWidth($field = 8, $label = 2)
193
    {
194
        $this->width = [
195
            'label' => $label,
196
            'field' => $field,
197
        ];
198
199
        return $this;
200
    }
201
202
    /**
203
     * Set form action.
204
     *
205
     * @param string $action
206
     */
207
    public function setAction($action)
208
    {
209
        $this->action = $action;
210
    }
211
212
    /**
213
     * Get Form action.
214
     *
215
     * @return string
216
     */
217
    public function getAction()
218
    {
219
        if ($this->action) {
220
            return $this->action;
221
        }
222
223
        if ($this->isMode(static::MODE_EDIT)) {
224
            return $this->form->resource().'/'.$this->id;
225
        }
226
227
        if ($this->isMode(static::MODE_CREATE)) {
228
            return $this->form->resource(-1);
229
        }
230
231
        return '';
232
    }
233
234
    /**
235
     * Set view for this form.
236
     *
237
     * @param string $view
238
     *
239
     * @return $this
240
     */
241
    public function setView($view)
242
    {
243
        $this->view = $view;
244
245
        return $this;
246
    }
247
248
    /**
249
     * Get fields of this builder.
250
     *
251
     * @return Collection
252
     */
253
    public function fields()
254
    {
255
        return $this->fields;
256
    }
257
258
    /**
259
     * Get specify field.
260
     *
261
     * @param string $name
262
     *
263
     * @return mixed
264
     */
265
    public function field($name)
266
    {
267
        return $this->fields()->first(function (Field $field) use ($name) {
268
            return $field->column() == $name;
269
        });
270
    }
271
272
    /**
273
     * If the parant form has rows.
274
     *
275
     * @return bool
276
     */
277
    public function hasRows()
278
    {
279
        return !empty($this->form->rows);
280
    }
281
282
    /**
283
     * Get field rows of form.
284
     *
285
     * @return array
286
     */
287
    public function getRows()
288
    {
289
        return $this->form->rows;
290
    }
291
292
    /**
293
     * set field rows of form.
294
     *
295
     * @return $this
296
     */
297
    public function setRows($rows)
298
    {
299
        $this->form->rows = $rows;
300
        return $this;
301
    }
302
303
    /**
304
     * @return array
305
     */
306
    public function getHiddenFields()
307
    {
308
        return $this->hiddenFields;
309
    }
310
311
    /**
312
     * @param Field $field
313
     *
314
     * @return void
315
     */
316
    public function addHiddenField(Field $field)
317
    {
318
        $this->hiddenFields[] = $field;
319
    }
320
321
    /**
322
     * Add or get options.
323
     *
324
     * @param array $options
325
     *
326
     * @return array|null
327
     */
328
    public function options($options = [])
329
    {
330
        if (empty($options)) {
331
            return $this->options;
332
        }
333
334
        $this->options = array_merge($this->options, $options);
335
    }
336
337
    /**
338
     * Get or set option.
339
     *
340
     * @param string $option
341
     * @param mixed  $value
342
     *
343
     * @return $this
344
     */
345
    public function option($option, $value = null)
346
    {
347
        if (func_num_args() == 1) {
348
            return array_get($this->options, $option);
349
        }
350
351
        $this->options[$option] = $value;
352
353
        return $this;
354
    }
355
356
    /**
357
     * @return string
358
     */
359
    public function setTitle($title)
360
    {
361
        return $this->Title = $title;
362
    }
363
364
    /**
365
     * @return string
366
     */
367
    public function title()
368
    {
369
        if ($this->Title != "") return $this->Title;
370
371
        if ($this->mode == static::MODE_CREATE) {
372
            return trans('admin.create');
373
        }
374
375
        if ($this->mode == static::MODE_EDIT) {
376
            return trans('admin.edit');
377
        }
378
379
        if ($this->mode == static::MODE_VIEW) {
380
            return trans('admin.view');
381
        }
382
383
        return '';
384
    }
385
386
    /**
387
     * Determine if form fields has files.
388
     *
389
     * @return bool
390
     */
391
    public function hasFile()
392
    {
393
        foreach ($this->fields() as $field) {
394
            if ($field instanceof Field\File) {
395
                return true;
396
            }
397
        }
398
399
        return false;
400
    }
401
402
    /**
403
     * Add field for store redirect url after update or store.
404
     *
405
     * @return void
406
     */
407
    protected function addRedirectUrlField()
408
    {
409
        $previous = URL::previous();
410
411
        if (!$previous || $previous == URL::current()) {
412
            return;
413
        }
414
415
        if (Str::contains($previous, url($this->getResource()))) {
0 ignored issues
show
Bug introduced by
It seems like url($this->getResource()) targeting url() can also be of type object<Illuminate\Contracts\Routing\UrlGenerator>; however, Illuminate\Support\Str::contains() does only seem to accept string|array, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
416
            $this->addHiddenField((new Form\Field\Hidden(static::PREVIOUS_URL_KEY))->value($previous));
417
        }
418
    }
419
420
    /**
421
     * Open up a new HTML form.
422
     *
423
     * @param array $options
424
     *
425
     * @return string
426
     */
427
    public function open($options = [])
428
    {
429
        $attributes = [];
430
431
        if ($this->mode == self::MODE_EDIT) {
432
            $this->addHiddenField((new Form\Field\Hidden('_method'))->value('PUT'));
433
        }
434
435
        $this->addRedirectUrlField();
436
437
        $attributes['action'] = $this->getAction();
438
        $attributes['method'] = array_get($options, 'method', 'post');
439
        $attributes['accept-charset'] = 'UTF-8';
440
441
        $attributes['class'] = array_get($options, 'class');
442
        $attributes['id'] = array_get($options, 'id');
443
444
        if ($this->hasFile()) {
445
            $attributes['enctype'] = 'multipart/form-data';
446
        }
447
448
        $html = [];
449
        foreach ($attributes as $name => $value) {
450
            $html[] = "$name=\"$value\"";
451
        }
452
453
        return '<form '.implode(' ', $html).' pjax-container>';
454
    }
455
456
    /**
457
     * Close the current form.
458
     *
459
     * @return string
460
     */
461
    public function close()
462
    {
463
        $this->form = null;
464
        $this->fields = null;
465
466
        return '</form>';
467
    }
468
469
    /**
470
     * Submit button of form..
471
     *
472
     * @return string
473
     */
474
    public function submitButton()
475
    {
476
        if ($this->mode == self::MODE_VIEW) {
477
            return '';
478
        }
479
480
        if (!$this->options['enableSubmit']) {
481
            return '';
482
        }
483
484
        if ($this->mode == self::MODE_EDIT) {
485
            $text = trans('admin.save');
486
        } else {
487
            $text = trans('admin.submit');
488
        }
489
490
        return <<<EOT
491
<div class="btn-group pull-right">
492
    <button type="submit" class="btn btn-info pull-right" data-loading-text="<i class='fa fa-spinner fa-spin '></i> $text">$text</button>
493
</div>
494
EOT;
495
    }
496
497
    /**
498
     * Reset button of form.
499
     *
500
     * @return string
501
     */
502
    public function resetButton()
503
    {
504
        if (!$this->options['enableReset']) {
505
            return '';
506
        }
507
508
        $text = trans('admin.reset');
509
510
        return <<<EOT
511
<div class="btn-group pull-left">
512
    <button type="reset" class="btn btn-warning">$text</button>
513
</div>
514
EOT;
515
    }
516
517
    /**
518
     * Remove reserved fields like `id` `created_at` `updated_at` in form fields.
519
     *
520
     * @return $this
521
     */
522
    public function removeReservedFields()
523
    {
524
525
        if (!$this->isMode(static::MODE_CREATE)) {
526
            return $this;
527
        }
528
529
        $reservedColumns = [
530
            $this->form->model()->getKeyName(),
531
            $this->form->model()->getCreatedAtColumn(),
532
            $this->form->model()->getUpdatedAtColumn(),
533
        ];
534
535
        $this->fields = $this->fields()->reject(function (Field $field) use ($reservedColumns) {
536
            return in_array($field->column(), $reservedColumns);
537
        });
538
539
        return $this;
540
    }
541
542
    /**
543
     * get form.
544
     *
545
     * @return Form
546
     */
547
    public function getForm()
548
    {
549
        return $this->form;
550
    }
551
552
    /**
553
     * Collect rules of all fields.
554
     *
555
     * @return array
556
     */
557
    public function getRules()
558
    {
559
        $rules = [];
560
        foreach ($this->fields() as $item) {
561
            if(!empty($item->getRules())){
562
                $rules[$item->id] = $item->getRules();
563
            }
564
        }
565
        $this->Rules = $rules;
566
        return $rules;
567
    }
568
569
    /**
570
     * Collect validationMessages of all fields.
571
     *
572
     * @return array
573
     */
574
    public function getRuleMessages()
575
    {
576
        $rules = [];
577
        foreach ($this->fields() as $item ) {
578
            foreach ($item->validationMessages as $key => $value) {
579
                $rules[$key] = $value;
580
            }
581
        }
582
        $this->RuleMessages = $rules;
583
        return $rules;
584
    }
585
586
    /**
587
     * Render form.
588
     *
589
     * @return string
590
     */
591
    public function render()
592
    {
593
        $this->removeReservedFields();
594
        $this->getRules();
595
        $this->getRuleMessages();
596
597
        $tabObj = $this->form->getTab();
598
599
        if (!$tabObj->isEmpty()) {
600
            $script = <<<'SCRIPT'
601
602
var hash = document.location.hash;
603
if (hash) {
604
    $('.nav-tabs a[href="' + hash + '"]').tab('show');
605
}
606
607
// Change hash for page-reload
608
$('.nav-tabs a').on('shown.bs.tab', function (e) {
609
    history.pushState(null,null, e.target.hash);
610
});
611
612
if ($('.has-error').length) {
613
    $('.has-error').each(function () {
614
        var tabId = '#'+$(this).closest('.tab-pane').attr('id');
615
        $('li a[href="'+tabId+'"] i').removeClass('hide');
616
    });
617
618
    var first = $('.has-error:first').closest('.tab-pane').attr('id');
619
    $('li a[href="#'+first+'"]').tab('show');
620
}
621
622
SCRIPT;
623
            Admin::script($script);
624
        }
625
626
        $data = [
627
            'form'   => $this,
628
            'tabObj' => $tabObj,
629
            'width'  => $this->width,
630
        ];
631
632
        return view($this->view, $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...
633
    }
634
635
    /**
636
     * @return string
637
     */
638
    public function renderHeaderTools()
639
    {
640
        return $this->tools->render();
641
    }
642
643
    /**
644
     * @return string
645
     */
646
    public function __toString()
647
    {
648
        return $this->render();
649
    }
650
}
651