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
Push — add-crudbutton-position-method ( e96e5e )
by Cristian
11:36
created

CrudButton::makeLast()   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 0
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\ViewNamespaces;
6
use Illuminate\Contracts\Support\Arrayable;
7
use Illuminate\Support\Traits\Conditionable;
8
9
/**
10
 * Adds fluent syntax to Backpack CRUD Buttons.
11
 *
12
 * In addition to the existing:
13
 * - CRUD::addButton('top', 'create', 'view', 'crud::buttons.create');
14
 *
15
 * Developers can also do:
16
 * - CRUD::button('create')->stack('top')->view('crud::buttons.create');
17
 *
18
 * And if the developer uses CrudButton as Button in their CrudController:
19
 * - Button::name('create')->stack('top')->view('crud::butons.create');
20
 */
21
class CrudButton implements Arrayable
22
{
23
    use Conditionable;
24
25
    public $stack;
26
27
    public $name;
28
29
    public $type;
30
31
    public $content;
32
33
    public $position;
34
35
    public $meta = [];
36
37
    public function __construct($nameOrAttributes, $stack = null, $type = null, $content = null, $position = null, $meta = [])
38
    {
39
        // in case an array was passed as name
40
        // assume it's an array that includes [$name, $stack, $type, $content]
41
        if (is_array($nameOrAttributes)) {
42
            extract($nameOrAttributes);
43
        }
44
45
        $this->name = $nameOrAttributes ?? 'button_'.rand(1, 999999999);
46
        $this->stack = $stack ?? 'top';
47
        $this->type = $type ?? 'view';
48
        $this->content = $content;
49
        $this->meta = $meta;
50
51
        // if no position was passed, the defaults are:
52
        // - 'beginning' for the 'line' stack
53
        // - 'end' for all other stacks
54
        $this->position = $position ?? ($this->stack == 'line' ? 'beginning' : 'end');
55
56
        return $this->save();
57
    }
58
59
    // ------
60
    // MAKERS
61
    // ------
62
63
    /**
64
     * Add a new button to the default stack.
65
     *
66
     * @param  string|array  $nameOrAttributes  Button name or array that contains name, stack, type and content.
67
     */
68
    public static function name($nameOrAttributes)
69
    {
70
        return new static($nameOrAttributes);
71
    }
72
73
    /**
74
     * Add a new button to the default stack.
75
     *
76
     * @param  string|array  $nameOrAttributes  Button name or array that contains name, stack, type and content.
77
     */
78
    public static function add($nameOrAttributes)
79
    {
80
        return new static($nameOrAttributes);
81
    }
82
83
    /**
84
     * This method allows one to create a button without attaching it to any 'real'
85
     * button stack, by moving it to a 'hidden' stack.
86
     *
87
     * It exists for one reason: so that developers can add buttons to a custom array, without
88
     * adding them to one of the button stacks.
89
     *
90
     * Ex: when developers need to pass multiple buttons as contents of the
91
     * div button. But they don't want them added to the before_content of after_content
92
     * stacks. So what they do is basically add them to a 'hidden' stack, that nobody will ever see.
93
     *
94
     * @param  string|array  $nameOrAttributes  Button name or array that contains name, stack, type and content.
95
     * @return CrudButton
96
     */
97
    public static function make($nameOrAttributes)
98
    {
99
        $button = static::add($nameOrAttributes);
100
        $button->stack('hidden');
101
102
        return $button;
103
    }
104
105
    // -------
106
    // SETTERS
107
    // -------
108
109
    /**
110
     * Set the button stack (where the button will be shown).
111
     *
112
     * @param  string  $stack  The name of the stack where the button should be moved.
113
     * @return CrudButton
114
     */
115
    public function stack($stack)
116
    {
117
        $this->stack = $stack;
118
119
        return $this->save();
120
    }
121
122
    /**
123
     * Sets the button type (view or model_function).
124
     *
125
     * @param  string  $type  The type of button - view or model_function.
126
     * @return CrudButton
127
     */
128
    public function type($type)
129
    {
130
        $this->type = $type;
131
132
        return $this->save();
133
    }
134
135
    /**
136
     * Sets the content of the button.
137
     * For the view button type, set it to the view path, including namespace.
138
     * For the model_function button type, set it to the name of the method on the model.
139
     *
140
     * @param  string  $content  Path to view or name of method on Model.
141
     * @return CrudButton
142
     */
143
    public function content($content)
144
    {
145
        $this->content = $content;
146
147
        return $this->save();
148
    }
149
150
    /**
151
     * Sets the namespace and path of the view for this button.
152
     * Sets the button type as 'view'.
153
     *
154
     * @param  string  $value  Path to view file.
155
     * @return CrudButton
156
     */
157
    public function view($value)
158
    {
159
        $this->content = $value;
160
        $this->type = 'view';
161
162
        return $this->save();
163
    }
164
165
    /**
166
     * Set the button position. Defines where the button will be shown
167
     * in regard to other buttons in the same stack.
168
     *
169
     * @param  string  $stack  'beginning' or 'end'
170
     * @return CrudButton
171
     */
172
    public function position($position)
173
    {
174
        switch ($position) {
175
            case 'beginning':
176
                $this->makeFirst();
177
                break;
178
179
            case 'end':
180
                $this->makeLast();
181
                break;
182
183
            default:
184
                abort(500, "Unknown button position - please use 'beginning' or 'end'.");
185
                break;
186
        }
187
188
        return $this->save();
189
    }
190
191
    /**
192
     * Sets the meta that will be available in the view.
193
     *
194
     * @param  array  $value  Array of metadata that will be available in the view.
195
     * @return CrudButton
196
     */
197
    public function meta($value)
198
    {
199
        $this->meta = $value;
200
201
        return $this->save();
202
    }
203
204
    /**
205
     * Sets the name of the method on the model that contains the HTML for this button.
206
     * Sets the button type as 'model_function'.
207
     *
208
     * @param  string  $value  Name of the method on the model.
209
     * @return CrudButton
210
     */
211
    public function modelFunction($value)
212
    {
213
        $this->content = $value;
214
        $this->type = 'model_function';
215
        $this->stack = 'line';
216
217
        return $this->save();
218
    }
219
220
    /**
221
     * Sets the name of the method on the model that contains the HTML for this button.
222
     * Sets the button type as 'model_function'.
223
     * Alias of the modelFunction() method.
224
     *
225
     * @param  string  $value  Name of the method on the model.
226
     * @return CrudButton
227
     */
228
    public function model_function($value)
229
    {
230
        return $this->modelFunction($value);
231
    }
232
233
    /**
234
     * Unserts an property that is set on the current button.
235
     * Possible properties: name, stack, type, content.
236
     *
237
     * @param  string  $property  Name of the property that should be cleared.
238
     * @return CrudButton
239
     */
240
    public function forget($property)
241
    {
242
        $this->{$property} = null;
243
244
        return $this->save();
245
    }
246
247
    // --------------
248
    // SETTER ALIASES
249
    // --------------
250
251
    /**
252
     * Moves the button to a certain button stack.
253
     * Alias of stack().
254
     *
255
     * @param  string  $stack  The name of the stack where the button should be moved.
256
     * @return self
257
     */
258
    public function to($stack)
259
    {
260
        return $this->stack($stack);
261
    }
262
263
    /**
264
     * Moves the button to a certain button stack.
265
     * Alias of stack().
266
     *
267
     * @param  string  $stack  The name of the stack where the button should be moved.
268
     * @return self
269
     */
270
    public function group($stack)
271
    {
272
        return $this->stack($stack);
273
    }
274
275
    /**
276
     * Moves the button to a certain button stack.
277
     * Alias of stack().
278
     *
279
     * @param  string  $stack  The name of the stack where the button should be moved.
280
     * @return self
281
     */
282
    public function section($stack)
283
    {
284
        return $this->stack($stack);
285
    }
286
287
    // -------
288
    // GETTERS
289
    // -------
290
291
    /**
292
     * Get the end result that should be displayed to the user.
293
     * The HTML itself of the button.
294
     *
295
     * @param  object|null  $entry  The eloquent Model for the current entry or null if no current entry.
296
     * @return \Illuminate\Contracts\View\View
297
     */
298
    public function getHtml($entry = null)
299
    {
300
        $button = $this;
301
        $crud = $this->crud();
302
303
        if ($this->type == 'model_function') {
304
            if (is_null($entry)) {
305
                return $crud->model->{$button->content}($crud);
306
            }
307
308
            return $entry->{$button->content}($crud);
309
        }
310
311
        if ($this->type == 'view') {
312
            return view($button->getFinalViewPath(), compact('button', 'crud', 'entry'));
313
        }
314
315
        abort(500, 'Unknown button type');
316
    }
317
318
    /**
319
     * Get an array of full paths to the filter view, consisting of:
320
     * - the path given in the button definition
321
     * - fallback view paths as configured in backpack/config/crud.php.
322
     *
323
     * @return array
324
     */
325
    private function getViewPathsWithFallbacks()
326
    {
327
        $type = $this->name;
328
        $paths = array_map(function ($item) use ($type) {
329
            return $item.'.'.$type;
330
        }, ViewNamespaces::getFor('buttons'));
331
332
        return array_merge([$this->content], $paths);
333
    }
334
335
    private function getFinalViewPath()
336
    {
337
        foreach ($this->getViewPathsWithFallbacks() as $path) {
338
            if (view()->exists($path)) {
339
                return $path;
340
            }
341
        }
342
343
        abort(500, 'Button view and fallbacks do not exist for '.$this->name.' button.');
344
    }
345
346
    /**
347
     * Get the key for this button in the global buttons collection.
348
     *
349
     * @return int
350
     */
351
    public function getKey()
352
    {
353
        return $this->crud()->getButtonKey($this->name);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->crud()->getButtonKey($this->name) returns the type string which is incompatible with the documented return type integer.
Loading history...
354
    }
355
356
    // -----
357
    // ORDER
358
    // -----
359
    // Manipulate the button collection (inside the global CrudPanel object).
360
361
    /**
362
     * Move this button to be the first in the buttons list.
363
     *
364
     * @return CrudButton
365
     */
366
    public function makeFirst()
367
    {
368
        return $this->before($this->collection()->first()->name);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->before($th...ction()->first()->name) returns the type Backpack\CRUD\app\Library\CrudPanel\CrudFilter which is incompatible with the documented return type Backpack\CRUD\app\Library\CrudPanel\CrudButton.
Loading history...
369
    }
370
371
    /**
372
     * Move this button to be the last one in the buttons list.
373
     *
374
     * @return CrudButton
375
     */
376
    public function makeLast()
377
    {
378
        return $this->after($this->collection()->last()->name);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->after($thi...ection()->last()->name) returns the type Backpack\CRUD\app\Library\CrudPanel\CrudFilter which is incompatible with the documented return type Backpack\CRUD\app\Library\CrudPanel\CrudButton.
Loading history...
379
    }
380
381
    /**
382
     * Move the current filter after another filter.
383
     *
384
     * @param  string  $destination  Name of the destination filter.
385
     * @return CrudFilter
386
     */
387
    public function after($destination)
388
    {
389
        $this->crud()->moveButton($this->name, 'after', $destination);
390
391
        return $this;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this returns the type Backpack\CRUD\app\Library\CrudPanel\CrudButton which is incompatible with the documented return type Backpack\CRUD\app\Library\CrudPanel\CrudFilter.
Loading history...
392
    }
393
394
    /**
395
     * Move the current field before another field.
396
     *
397
     * @param  string  $destination  Name of the destination field.
398
     * @return CrudFilter
399
     */
400
    public function before($destination)
401
    {
402
        $this->crud()->moveButton($this->name, 'before', $destination);
403
404
        return $this;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this returns the type Backpack\CRUD\app\Library\CrudPanel\CrudButton which is incompatible with the documented return type Backpack\CRUD\app\Library\CrudPanel\CrudFilter.
Loading history...
405
    }
406
407
    /**
408
     * Remove the button from the global button collection.
409
     *
410
     * @return void
411
     */
412
    public function remove()
413
    {
414
        $this->crud()->removeButton($this->getKey());
415
    }
416
417
    // --------------
418
    // GLOBAL OBJECTS
419
    // --------------
420
    // Access to the objects stored in Laravel's service container.
421
422
    /**
423
     * Access the global collection when all buttons are stored.
424
     *
425
     * @return \Illuminate\Support\Collection
426
     */
427
    public function collection()
428
    {
429
        return $this->crud()->buttons();
430
    }
431
432
    /**
433
     * Access the global CrudPanel object.
434
     *
435
     * @return \Backpack\CRUD\app\Library\CrudPanel\CrudPanel
436
     */
437
    public function crud()
438
    {
439
        return app('crud');
440
    }
441
442
    // -----------------
443
    // DEBUGGING METHODS
444
    // -----------------
445
446
    /**
447
     * Dump the current object to the screen,
448
     * so that the developer can see its contents.
449
     *
450
     * @codeCoverageIgnore
451
     *
452
     * @return CrudButton
453
     */
454
    public function dump()
455
    {
456
        dump($this);
457
458
        return $this;
459
    }
460
461
    /**
462
     * Dump and die. Duumps the current object to the screen,
463
     * so that the developer can see its contents, then stops
464
     * the execution.
465
     *
466
     * @codeCoverageIgnore
467
     *
468
     * @return CrudButton
469
     */
470
    public function dd()
471
    {
472
        dd($this);
473
474
        return $this;
475
    }
476
477
    // ---------------
478
    // PRIVATE METHODS
479
    // ---------------
480
481
    /**
482
     * Update the global CrudPanel object with the current button.
483
     *
484
     * @return CrudButton
485
     */
486
    private function save()
487
    {
488
        if ($this->collection()->isEmpty()) {
489
            $this->crud()->addCrudButton($this);
490
491
            return $this;
492
        }
493
494
        $itemExists = $this->collection()->contains('name', $this->name);
495
496
        if (! $itemExists) {
497
            $this->crud()->addCrudButton($this);
498
            if ($this->position == 'beginning') {
499
                $this->before($this->collection()->first()->name);
500
            } else {
501
                $this->after($this->collection()->last()->name);
502
            }
503
504
            // clear the custom position, so that the next daisy chained method
505
            // doesn't move it yet again
506
            $this->position = null;
507
        } else {
508
            $this->crud()->modifyButton($this->name, $this->toArray());
509
        }
510
511
        return $this;
512
    }
513
514
    public function toArray()
515
    {
516
        return (array) $this;
517
    }
518
}
519