Scrutinizer GitHub App not installed

We could not synchronize checks via GitHub's checks API since Scrutinizer's GitHub App is not installed for this repository.

Install GitHub App

Passed
Pull Request — main (#4988)
by Pedro
26:05 queued 11:05
created

CrudField::setAllAttributeValues()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Backpack\CRUD\app\Library\CrudPanel;
4
5
use Backpack\CRUD\app\Library\CrudPanel\Traits\Support\MacroableWithAttributes;
6
7
/**
8
 * Adds fluent syntax to Backpack CRUD Fields.
9
 *
10
 * In addition to the existing:
11
 * - CRUD::addField(['name' => 'price', 'type' => 'number']);
12
 *
13
 * Developers can also do:
14
 * - CRUD::field('price')->type('number');
15
 *
16
 * And if the developer uses CrudField as Field in their CrudController:
17
 * - Field::name('price')->type('number');
18
 *
19
 * @method self type(string $value)
20
 * @method self label(string $value)
21
 * @method self tab(string $value)
22
 * @method self prefix(string $value)
23
 * @method self suffix(string $value)
24
 * @method self default(mixed $value)
25
 * @method self hint(string $value)
26
 * @method self attributes(array $value)
27
 * @method self wrapper(array $value)
28
 * @method self fake(bool $value)
29
 * @method self store_in(string $value)
30
 * @method self validationRules(string $value)
31
 * @method self validationMessages(array $value)
32
 * @method self entity(string $value)
33
 * @method self addMorphOption(string $key, string $label, array $options)
34
 * @method self morphTypeField(array $value)
35
 * @method self morphIdField(array $value)
36
 * @method self upload(bool $value)
37
 */
38
class CrudField
39
{
40
    use MacroableWithAttributes;
0 ignored issues
show
Bug introduced by
The trait Backpack\CRUD\app\Librar...MacroableWithAttributes requires the property $name which is not provided by Backpack\CRUD\app\Library\CrudPanel\CrudField.
Loading history...
41
42
    protected $attributes;
43
44
    public function __construct($name)
45
    {
46
        if (empty($name)) {
47
            abort(500, 'Field name can\'t be empty.');
48
        }
49
50
        $field = $this->crud()->firstFieldWhere('name', $name);
51
52
        // if field exists
53
        if ((bool) $field) {
54
            // use all existing attributes
55
            $this->setAllAttributeValues($field);
0 ignored issues
show
Bug introduced by
$field of type boolean is incompatible with the type array expected by parameter $array of Backpack\CRUD\app\Librar...setAllAttributeValues(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

55
            $this->setAllAttributeValues(/** @scrutinizer ignore-type */ $field);
Loading history...
56
        } else {
57
            // it means we're creating the field now,
58
            // so at the very least set the name attribute
59
            $this->setAttributeValue('name', $name);
60
        }
61
62
        $this->save();
63
    }
64
65
    public function crud()
66
    {
67
        return app()->make('crud');
68
    }
69
70
    /**
71
     * Create a CrudField object with the parameter as its name.
72
     *
73
     * @param  string  $name  Name of the column in the db, or model attribute.
74
     * @return CrudField
75
     */
76
    public static function name($name)
77
    {
78
        return new static($name);
79
    }
80
81
    /**
82
     * When defining the entity, make sure Backpack guesses the relationship attributes if needed.
83
     *
84
     * @param  string|bool  $entity
85
     * @return self
86
     */
87
    public function entity($entity)
88
    {
89
        $this->attributes['entity'] = $entity;
90
91
        if ($entity !== false) {
92
            $this->attributes = $this->crud()->makeSureFieldHasRelationshipAttributes($this->attributes);
93
        }
94
95
        return $this->save();
96
    }
97
98
    /**
99
     * Remove the current field from the current operation.
100
     *
101
     * @return void
102
     */
103
    public function remove()
104
    {
105
        $this->crud()->removeField($this->attributes['name']);
106
    }
107
108
    /**
109
     * Remove an attribute from the current field definition array.
110
     *
111
     * @param  string  $attribute  Name of the attribute being removed.
112
     * @return CrudField
113
     */
114
    public function forget($attribute)
115
    {
116
        $this->crud()->removeFieldAttribute($this->attributes['name'], $attribute);
117
118
        return $this;
119
    }
120
121
    /**
122
     * Move the current field after another field.
123
     *
124
     * @param  string  $destinationField  Name of the destination field.
125
     * @return CrudField
126
     */
127
    public function after($destinationField)
128
    {
129
        $this->crud()->removeField($this->attributes['name']);
130
        $this->crud()->addField($this->attributes)->afterField($destinationField);
131
132
        return $this;
133
    }
134
135
    /**
136
     * Move the current field before another field.
137
     *
138
     * @param  string  $destinationField  Name of the destination field.
139
     * @return CrudField
140
     */
141
    public function before($destinationField)
142
    {
143
        $this->crud()->removeField($this->attributes['name']);
144
        $this->crud()->addField($this->attributes)->beforeField($destinationField);
145
146
        return $this;
147
    }
148
149
    /**
150
     * Make the current field the first one in the fields list.
151
     *
152
     * @return CrudField
153
     */
154
    public function makeFirst()
155
    {
156
        $this->crud()->removeField($this->attributes['name']);
157
        $this->crud()->addField($this->attributes)->makeFirstField();
158
159
        return $this;
160
    }
161
162
    /**
163
     * Make the current field the last one in the fields list.
164
     *
165
     * @return CrudField
166
     */
167
    public function makeLast()
168
    {
169
        $this->crud()->removeField($this->attributes['name']);
170
        $this->crud()->addField($this->attributes);
171
172
        return $this;
173
    }
174
175
    // -------------------
176
    // CONVENIENCE METHODS
177
    // -------------------
178
    // These methods don't do exactly what advertised by their name.
179
    // They exist because the original syntax was too long.
180
181
    /**
182
     * Set the wrapper width at this many number of columns.
183
     * For example, to set a field wrapper to span across 6 columns, you can do both:
184
     * ->wrapper(['class' => 'form-group col-md-6'])
185
     * ->size(6).
186
     *
187
     * @param  int  $numberOfColumns  How many columns should this field span across (1-12)?
188
     * @return CrudField
189
     */
190
    public function size($numberOfColumns)
191
    {
192
        $this->attributes['wrapper']['class'] = 'form-group col-md-'.$numberOfColumns;
193
194
        return $this->save();
195
    }
196
197
    /**
198
     * Set an event to a certain closure. Will overwrite if existing.
199
     *
200
     * @param  string  $event  Name of Eloquent Model event
201
     * @param  \Closure  $closure  The function aka callback aka closure to run.
202
     * @return CrudField
203
     */
204
    public function on(string $event, \Closure $closure)
205
    {
206
        $this->attributes['events'][$event] = $closure;
207
208
        return $this->save();
209
    }
210
211
    /**
212
     * When subfields are defined, pass them through the guessing function
213
     * so that they have label, relationship attributes, etc.
214
     *
215
     * @param  array  $subfields  Subfield definition array
216
     * @return self
217
     */
218
    public function subfields($subfields)
219
    {
220
        $this->attributes['subfields'] = $subfields;
221
        $this->attributes = $this->crud()->makeSureFieldHasNecessaryAttributes($this->attributes);
222
        $this->callRegisteredAttributeMacros();
223
224
        return $this->save();
225
    }
226
227
    /**
228
     * Mark the field has having upload functionality, so that the form would become multipart.
229
     *
230
     * @param  bool  $upload
231
     * @return self
232
     */
233
    public function upload($upload = true)
234
    {
235
        $this->attributes['upload'] = $upload;
236
237
        return $this->save();
238
    }
239
240
    /**
241
     * Save the validation rules on the CrudPanel per field basis.
242
     *
243
     * @param  string  $rules  the field rules: required|min:1|max:5
244
     * @return self
245
     */
246
    public function validationRules(string $rules)
247
    {
248
        $this->attributes['validationRules'] = $rules;
249
        $this->crud()->setValidationFromArray([$this->attributes['name'] => $rules]);
250
251
        return $this;
252
    }
253
254
    /**
255
     * Save the validation messages on the CrudPanel per field basis.
256
     *
257
     * @param  array  $messages  the messages for field rules: [required => please input something, min => the minimum allowed is 1]
258
     * @return self
259
     */
260
    public function validationMessages(array $messages)
261
    {
262
        $this->attributes['validationMessages'] = $messages;
263
264
        // append the field name to the rule name of validationMessages array.
265
        // eg: ['required => 'This field is required']
266
        // will be transformed into: ['field_name.required' => 'This field is required]
267
        $this->crud()->setValidationFromArray([], array_merge(...array_map(function ($rule, $message) {
268
            return [$this->attributes['name'].'.'.$rule => $message];
269
        }, array_keys($messages), $messages)));
270
271
        return $this;
272
    }
273
274
    /**
275
     * This function is responsible for setting up the morph fields structure.
276
     * Developer can define the morph structure as follows:
277
     *  'morphOptions => [
278
     *       ['nameOnAMorphMap', 'label', [options]],
279
     *       ['App\Models\Model'], // display the name of the model
280
     *       ['App\Models\Model', 'label', ['data_source' => backpack_url('smt')]
281
     *  ]
282
     * OR
283
     * ->addMorphOption('App\Models\Model', 'label', ['data_source' => backpack_url('smt')]).
284
     *
285
     * @param  string  $key  - the morph option key, usually a \Model\Class or a string for the morphMap
286
     * @param  string|null  $label  - the displayed text for this option
287
     * @param  array  $options  - options for the corresponding morphable_id field (usually ajax options)
288
     * @return self
289
     *
290
     * @throws \Exception
291
     */
292
    public function addMorphOption(string $key, $label = null, array $options = [])
293
    {
294
        $this->crud()->addMorphOption($this->attributes['name'], $key, $label, $options);
295
296
        return $this;
297
    }
298
299
    /**
300
     * Allow developer to configure the morph type field.
301
     *
302
     * @param  array  $configs
303
     * @return self
304
     *
305
     * @throws \Exception
306
     */
307
    public function morphTypeField(array $configs)
308
    {
309
        $morphField = $this->crud()->fields()[$this->attributes['name']];
310
311
        if (empty($morphField) || ($morphField['relation_type'] ?? '') !== 'MorphTo') {
312
            throw new \Exception('Trying to configure the morphType on a non-morphTo field. Check if field and relation name matches.');
313
        }
314
        [$morphTypeField, $morphIdField] = $morphField['subfields'];
315
316
        $morphTypeField = array_merge($morphTypeField, $configs);
317
318
        $morphField['subfields'] = [$morphTypeField, $morphIdField];
319
320
        $this->crud()->modifyField($this->attributes['name'], $morphField);
321
322
        return $this;
323
    }
324
325
    /**
326
     * Allow developer to configure the morph type id selector.
327
     *
328
     * @param  array  $configs
329
     * @return self
330
     *
331
     * @throws \Exception
332
     */
333
    public function morphIdField(array $configs)
334
    {
335
        $morphField = $this->crud()->fields()[$this->attributes['name']];
336
337
        if (empty($morphField) || ($morphField['relation_type'] ?? '') !== 'MorphTo') {
338
            throw new \Exception('Trying to configure the morphType on a non-morphTo field. Check if field and relation name matches.');
339
        }
340
341
        [$morphTypeField, $morphIdField] = $morphField['subfields'];
342
343
        $morphIdField = array_merge($morphIdField, $configs);
344
345
        $morphField['subfields'] = [$morphTypeField, $morphIdField];
346
347
        $this->crud()->modifyField($this->attributes['name'], $morphField);
348
349
        return $this;
350
    }
351
352
    public function getAttributes()
353
    {
354
        return $this->attributes;
355
    }
356
    // ---------------
357
    // PRIVATE METHODS
358
    // ---------------
359
360
    /**
361
     * Set the value for a certain attribute on the CrudField object.
362
     *
363
     * @param  string  $attribute  Name of the attribute.
364
     * @param  mixed  $value  Value of that attribute.
365
     */
366
    private function setAttributeValue($attribute, $value)
367
    {
368
        $this->attributes[$attribute] = $value;
369
    }
370
371
    /**
372
     * Replace all field attributes on the CrudField object
373
     * with the given array of attribute-value pairs.
374
     *
375
     * @param  array  $array  Array of attributes and their values.
376
     */
377
    private function setAllAttributeValues($array)
378
    {
379
        $this->attributes = $array;
380
    }
381
382
    /**
383
     * Update the global CrudPanel object with the current field attributes.
384
     *
385
     * @return CrudField
386
     */
387
    private function save()
388
    {
389
        $key = $this->attributes['name'];
390
391
        if ($this->crud()->hasFieldWhere('name', $key)) {
392
            $this->crud()->modifyField($key, $this->attributes);
393
        } else {
394
            $this->crud()->addField($this->attributes);
395
        }
396
397
        return $this;
398
    }
399
400
    // -----------------
401
    // DEBUGGING METHODS
402
    // -----------------
403
404
    /**
405
     * Dump the current object to the screen,
406
     * so that the developer can see its contents.
407
     *
408
     * @codeCoverageIgnore
409
     *
410
     * @return CrudField
411
     */
412
    public function dump()
413
    {
414
        dump($this);
415
416
        return $this;
417
    }
418
419
    /**
420
     * Dump and die. Duumps the current object to the screen,
421
     * so that the developer can see its contents, then stops
422
     * the execution.
423
     *
424
     * @codeCoverageIgnore
425
     *
426
     * @return CrudField
427
     */
428
    public function dd()
429
    {
430
        dd($this);
431
432
        return $this;
433
    }
434
435
    // -------------
436
    // MAGIC METHODS
437
    // -------------
438
439
    /**
440
     * If a developer calls a method that doesn't exist, assume they want:
441
     * - the CrudField object to have an attribute with that value;
442
     * - that field be updated inside the global CrudPanel object;.
443
     *
444
     * Eg: type('number') will set the "type" attribute to "number"
445
     *
446
     * @param  string  $method  The method being called that doesn't exist.
447
     * @param  array  $parameters  The arguments when that method was called.
448
     * @return CrudField
449
     */
450
    public function __call($method, $parameters)
451
    {
452
        if (static::hasMacro($method)) {
453
            return $this->macroCall($method, $parameters);
0 ignored issues
show
Bug introduced by
The method macroCall() does not exist on Backpack\CRUD\app\Library\CrudPanel\CrudField. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

453
            return $this->/** @scrutinizer ignore-call */ macroCall($method, $parameters);
Loading history...
454
        }
455
456
        $this->setAttributeValue($method, $parameters[0]);
457
458
        return $this->save();
459
    }
460
}
461