Completed
Push — master ( 77fd36...f39186 )
by Song
02:52
created

Builder::setAction()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 4
rs 10
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
     * Form title.
92
     *
93
     * @var string
94
     */
95
    protected $title;
96
97
    /**
98
     * Builder constructor.
99
     *
100
     * @param Form $form
101
     */
102
    public function __construct(Form $form)
103
    {
104
        $this->form = $form;
105
106
        $this->fields = new Collection();
107
108
        $this->setupTools();
109
    }
110
111
    /**
112
     * Setup grid tools.
113
     */
114
    public function setupTools()
115
    {
116
        $this->tools = new Tools($this);
117
    }
118
119
    /**
120
     * @return Tools
121
     */
122
    public function getTools()
123
    {
124
        return $this->tools;
125
    }
126
127
    /**
128
     * Set the builder mode.
129
     *
130
     * @param string $mode
131
     *
132
     * @return void
133
     */
134
    public function setMode($mode = 'create')
135
    {
136
        $this->mode = $mode;
137
    }
138
139
    /**
140
     * Returns builder is $mode.
141
     *
142
     * @param $mode
143
     *
144
     * @return bool
145
     */
146
    public function isMode($mode)
147
    {
148
        return $this->mode == $mode;
149
    }
150
151
    /**
152
     * Set resource Id.
153
     *
154
     * @param $id
155
     *
156
     * @return void
157
     */
158
    public function setResourceId($id)
159
    {
160
        $this->id = $id;
161
    }
162
163
    /**
164
     * Get Resource id.
165
     *
166
     * @return mixed
167
     */
168
    public function getResourceId()
169
    {
170
        return $this->id;
171
    }
172
173
    /**
174
     * @return string
175
     */
176
    public function getResource($slice = null)
177
    {
178
        if ($this->mode == self::MODE_CREATE) {
179
            return $this->form->resource(-1);
180
        }
181
        if ($slice !== null) {
182
            return $this->form->resource($slice);
183
        }
184
185
        return $this->form->resource();
186
    }
187
188
    /**
189
     * @param int $field
190
     * @param int $label
191
     *
192
     * @return $this
193
     */
194
    public function setWidth($field = 8, $label = 2)
195
    {
196
        $this->width = [
197
            'label' => $label,
198
            'field' => $field,
199
        ];
200
201
        return $this;
202
    }
203
204
    /**
205
     * Set form action.
206
     *
207
     * @param string $action
208
     */
209
    public function setAction($action)
210
    {
211
        $this->action = $action;
212
    }
213
214
    /**
215
     * Get Form action.
216
     *
217
     * @return string
218
     */
219
    public function getAction()
220
    {
221
        if ($this->action) {
222
            return $this->action;
223
        }
224
225
        if ($this->isMode(static::MODE_EDIT)) {
226
            return $this->form->resource().'/'.$this->id;
227
        }
228
229
        if ($this->isMode(static::MODE_CREATE)) {
230
            return $this->form->resource(-1);
231
        }
232
233
        return '';
234
    }
235
236
    /**
237
     * Set view for this form.
238
     *
239
     * @param string $view
240
     *
241
     * @return $this
242
     */
243
    public function setView($view)
244
    {
245
        $this->view = $view;
246
247
        return $this;
248
    }
249
250
    /**
251
     * Set title for form.
252
     *
253
     * @param string $title
254
     *
255
     * @return $this
256
     */
257
    public function setTitle($title)
258
    {
259
        $this->title = $title;
260
261
        return $this;
262
    }
263
264
    /**
265
     * Get fields of this builder.
266
     *
267
     * @return Collection
268
     */
269
    public function fields()
270
    {
271
        return $this->fields;
272
    }
273
274
    /**
275
     * Get specify field.
276
     *
277
     * @param string $name
278
     *
279
     * @return mixed
280
     */
281
    public function field($name)
282
    {
283
        return $this->fields()->first(function (Field $field) use ($name) {
284
            return $field->column() == $name;
285
        });
286
    }
287
288
    /**
289
     * If the parant form has rows.
290
     *
291
     * @return bool
292
     */
293
    public function hasRows()
294
    {
295
        return !empty($this->form->rows);
296
    }
297
298
    /**
299
     * Get field rows of form.
300
     *
301
     * @return array
302
     */
303
    public function getRows()
304
    {
305
        return $this->form->rows;
306
    }
307
308
    /**
309
     * @return array
310
     */
311
    public function getHiddenFields()
312
    {
313
        return $this->hiddenFields;
314
    }
315
316
    /**
317
     * @param Field $field
318
     *
319
     * @return void
320
     */
321
    public function addHiddenField(Field $field)
322
    {
323
        $this->hiddenFields[] = $field;
324
    }
325
326
    /**
327
     * Add or get options.
328
     *
329
     * @param array $options
330
     *
331
     * @return array|null
332
     */
333
    public function options($options = [])
334
    {
335
        if (empty($options)) {
336
            return $this->options;
337
        }
338
339
        $this->options = array_merge($this->options, $options);
340
    }
341
342
    /**
343
     * Get or set option.
344
     *
345
     * @param string $option
346
     * @param mixed  $value
347
     *
348
     * @return $this
349
     */
350
    public function option($option, $value = null)
351
    {
352
        if (func_num_args() == 1) {
353
            return array_get($this->options, $option);
354
        }
355
356
        $this->options[$option] = $value;
357
358
        return $this;
359
    }
360
361
    /**
362
     * @return string
363
     */
364
    public function title()
365
    {
366
        if ($this->title) {
367
            return $this->title;
368
        }
369
370
        if ($this->mode == static::MODE_CREATE) {
371
            return trans('admin.create');
372
        }
373
374
        if ($this->mode == static::MODE_EDIT) {
375
            return trans('admin.edit');
376
        }
377
378
        if ($this->mode == static::MODE_VIEW) {
379
            return trans('admin.view');
380
        }
381
382
        return '';
383
    }
384
385
    /**
386
     * Determine if form fields has files.
387
     *
388
     * @return bool
389
     */
390
    public function hasFile()
391
    {
392
        foreach ($this->fields() as $field) {
393
            if ($field instanceof Field\File) {
394
                return true;
395
            }
396
        }
397
398
        return false;
399
    }
400
401
    /**
402
     * Add field for store redirect url after update or store.
403
     *
404
     * @return void
405
     */
406
    protected function addRedirectUrlField()
407
    {
408
        $previous = URL::previous();
409
410
        if (!$previous || $previous == URL::current()) {
411
            return;
412
        }
413
414
        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...
415
            $this->addHiddenField((new Form\Field\Hidden(static::PREVIOUS_URL_KEY))->value($previous));
416
        }
417
    }
418
419
    /**
420
     * Open up a new HTML form.
421
     *
422
     * @param array $options
423
     *
424
     * @return string
425
     */
426
    public function open($options = [])
427
    {
428
        $attributes = [];
429
430
        if ($this->mode == self::MODE_EDIT) {
431
            $this->addHiddenField((new Form\Field\Hidden('_method'))->value('PUT'));
432
        }
433
434
        $this->addRedirectUrlField();
435
436
        $attributes['action'] = $this->getAction();
437
        $attributes['method'] = array_get($options, 'method', 'post');
438
        $attributes['accept-charset'] = 'UTF-8';
439
440
        $attributes['class'] = array_get($options, 'class');
441
442
        if ($this->hasFile()) {
443
            $attributes['enctype'] = 'multipart/form-data';
444
        }
445
446
        $html = [];
447
        foreach ($attributes as $name => $value) {
448
            $html[] = "$name=\"$value\"";
449
        }
450
451
        return '<form '.implode(' ', $html).' pjax-container>';
452
    }
453
454
    /**
455
     * Close the current form.
456
     *
457
     * @return string
458
     */
459
    public function close()
460
    {
461
        $this->form = null;
462
        $this->fields = null;
463
464
        return '</form>';
465
    }
466
467
    /**
468
     * Submit button of form..
469
     *
470
     * @return string
471
     */
472
    public function submitButton()
473
    {
474
        if ($this->mode == self::MODE_VIEW) {
475
            return '';
476
        }
477
478
        if (!$this->options['enableSubmit']) {
479
            return '';
480
        }
481
482
        if ($this->mode == self::MODE_EDIT) {
483
            $text = trans('admin.save');
484
        } else {
485
            $text = trans('admin.submit');
486
        }
487
488
        return <<<EOT
489
<div class="btn-group pull-right">
490
    <button type="submit" class="btn btn-info pull-right" data-loading-text="<i class='fa fa-spinner fa-spin '></i> $text">$text</button>
491
</div>
492
EOT;
493
    }
494
495
    /**
496
     * Reset button of form.
497
     *
498
     * @return string
499
     */
500
    public function resetButton()
501
    {
502
        if (!$this->options['enableReset']) {
503
            return '';
504
        }
505
506
        $text = trans('admin.reset');
507
508
        return <<<EOT
509
<div class="btn-group pull-left">
510
    <button type="reset" class="btn btn-warning">$text</button>
511
</div>
512
EOT;
513
    }
514
515
    /**
516
     * Remove reserved fields like `id` `created_at` `updated_at` in form fields.
517
     *
518
     * @return void
519
     */
520
    protected function removeReservedFields()
521
    {
522
        if (!$this->isMode(static::MODE_CREATE)) {
523
            return;
524
        }
525
526
        $reservedColumns = [
527
            $this->form->model()->getKeyName(),
528
            $this->form->model()->getCreatedAtColumn(),
529
            $this->form->model()->getUpdatedAtColumn(),
530
        ];
531
532
        $this->fields = $this->fields()->reject(function (Field $field) use ($reservedColumns) {
533
            return in_array($field->column(), $reservedColumns);
534
        });
535
    }
536
537
    /**
538
     * Render form.
539
     *
540
     * @return string
541
     */
542
    public function render()
543
    {
544
        $this->removeReservedFields();
545
546
        $tabObj = $this->form->getTab();
547
548
        if (!$tabObj->isEmpty()) {
549
            $script = <<<'SCRIPT'
550
551
var hash = document.location.hash;
552
if (hash) {
553
    $('.nav-tabs a[href="' + hash + '"]').tab('show');
554
}
555
556
// Change hash for page-reload
557
$('.nav-tabs a').on('shown.bs.tab', function (e) {
558
    history.pushState(null,null, e.target.hash);
559
});
560
561
if ($('.has-error').length) {
562
    $('.has-error').each(function () {
563
        var tabId = '#'+$(this).closest('.tab-pane').attr('id');
564
        $('li a[href="'+tabId+'"] i').removeClass('hide');
565
    });
566
567
    var first = $('.has-error:first').closest('.tab-pane').attr('id');
568
    $('li a[href="#'+first+'"]').tab('show');
569
}
570
571
SCRIPT;
572
            Admin::script($script);
573
        }
574
575
        $data = [
576
            'form'   => $this,
577
            'tabObj' => $tabObj,
578
            'width'  => $this->width,
579
        ];
580
581
        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...
582
    }
583
584
    /**
585
     * @return string
586
     */
587
    public function renderHeaderTools()
588
    {
589
        return $this->tools->render();
590
    }
591
592
    /**
593
     * @return string
594
     */
595
    public function __toString()
596
    {
597
        return $this->render();
598
    }
599
}
600