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

Builder::getForm()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

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