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 (#5693)
by
unknown
12:53
created

Buttons::removeButton()   A

Complexity

Conditions 3
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 2
nc 1
nop 2
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Backpack\CRUD\app\Library\CrudPanel\Traits;
4
5
use Backpack\CRUD\app\Library\CrudPanel\CrudButton;
6
use Illuminate\Support\Collection;
7
8
trait Buttons
9
{
10
    // ------------
11
    // BUTTONS
12
    // ------------
13
14
    /**
15
     * Order the CRUD buttons. If certain button names are missing from the given order array
16
     * they will be pushed to the end of the button collection.
17
     *
18
     * @param  string  $stack  Stack where the buttons belongs. Options: top, line, bottom.
19
     * @param  array  $order  Ordered names of the buttons. ['update', 'delete', 'show']
20
     * @param  bool  $abortIfNotExist  If true, an exception will be thrown if a button name is not found.
21
     */
22
    public function orderButtons(string $stack, array $order, bool $abortIfNotExist = true): void
23
    {
24
        $newButtons = collect([]);
0 ignored issues
show
Bug introduced by
array() of type array is incompatible with the type Illuminate\Contracts\Support\Arrayable expected by parameter $value of collect(). ( Ignorable by Annotation )

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

24
        $newButtons = collect(/** @scrutinizer ignore-type */ []);
Loading history...
25
        $otherButtons = collect([]);
26
27
        // we get the buttons that belong to the specified stack
28
        $stackButtons = $this->buttons()->reject(function ($item) use ($stack, $otherButtons) {
29
            if ($item->stack != $stack) {
30
                // if the button does not belong to this stack we just add it for merging later
31
                $otherButtons->push($item);
32
33
                return true;
34
            }
35
36
            return false;
37
        });
38
39
        // we parse the ordered buttons
40
        collect($order)->each(function ($btnKey) use ($abortIfNotExist, $newButtons, $stackButtons) {
0 ignored issues
show
Bug introduced by
$order of type array is incompatible with the type Illuminate\Contracts\Support\Arrayable expected by parameter $value of collect(). ( Ignorable by Annotation )

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

40
        collect(/** @scrutinizer ignore-type */ $order)->each(function ($btnKey) use ($abortIfNotExist, $newButtons, $stackButtons) {
Loading history...
41
            if (!$button = $stackButtons->where('name', $btnKey)->first()) {
42
                if ($abortIfNotExist) {
43
                    abort(500, 'Button name [«' . $btnKey . '»] not found.', ['developer-error-exception']);
44
                }
45
            }
46
            $newButtons->push($button);
47
        });
48
49
        // if the ordered buttons are less than the total number of buttons in the stack
50
        // we add the remaining buttons to the end of the ordered ones
51
        if (count($newButtons) < count($stackButtons)) {
52
            foreach ($stackButtons as $button) {
53
                if (! $newButtons->where('name', $button->name)->first()) {
54
                    $newButtons->push($button);
55
                }
56
            }
57
        }
58
59
        $this->setOperationSetting('buttons', $newButtons->merge($otherButtons));
0 ignored issues
show
Bug introduced by
It seems like setOperationSetting() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

59
        $this->/** @scrutinizer ignore-call */ 
60
               setOperationSetting('buttons', $newButtons->merge($otherButtons));
Loading history...
60
    }
61
62
    /**
63
     * Add a button to the CRUD table view.
64
     *
65
     * @param  string  $stack  Where should the button be visible? Options: top, line, bottom.
66
     * @param  string  $name  The name of the button. Unique.
67
     * @param  string  $type  Type of button: view or model_function.
68
     * @param  string  $content  The HTML for the button.
69
     * @param  bool|string  $position  Position on the stack: beginning or end. If false, the position will be
70
     *                                 'beginning' for the line stack or 'end' otherwise.
71
     * @param  bool  $replaceExisting  True if a button with the same name on the given stack should be replaced.
72
     * @return \Backpack\CRUD\app\Library\CrudPanel\CrudButton The new CRUD button.
73
     */
74
    public function addButton($stack, $name, $type, $content, $position = false, $replaceExisting = true)
75
    {
76
        if ($replaceExisting) {
77
            $this->removeButton($name, $stack);
78
        }
79
80
        return new CrudButton($name, $stack, $type, $content, $position);
81
    }
82
83
    public function addCrudButton(CrudButton $crudButton)
84
    {
85
        $this->setOperationSetting('buttons', $this->buttons()->push($crudButton));
86
    }
87
88
    public function addButtonFromModelFunction($stack, $name, $model_function_name, $position = false)
89
    {
90
        $this->addButton($stack, $name, 'model_function', $model_function_name, $position);
91
    }
92
93
    public function addButtonFromView($stack, $name, $view, $position = false)
94
    {
95
        $view = 'crud::buttons.'.$view;
96
97
        $this->addButton($stack, $name, 'view', $view, $position);
98
    }
99
100
    /**
101
     * @return Collection
102
     */
103
    public function buttons()
104
    {
105
        return $this->getOperationSetting('buttons') ?? collect();
0 ignored issues
show
Bug introduced by
It seems like getOperationSetting() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

105
        return $this->/** @scrutinizer ignore-call */ getOperationSetting('buttons') ?? collect();
Loading history...
106
    }
107
108
    /**
109
     * Modify the attributes of a button.
110
     *
111
     * @param  string  $name  The button name.
112
     * @param  array  $modifications  The attributes and their new values.
113
     * @return CrudButton The button that has suffered the changes, for daisychaining methods.
114
     */
115
    public function modifyButton($name, $modifications = null)
116
    {
117
        /**
118
         * @var CrudButton|null
119
         */
120
        $button = $this->buttons()->firstWhere('name', $name);
121
122
        if (! $button) {
123
            abort(500, 'CRUD Button "'.$name.'" not found. Please ensure the button exists before you modify it.', ['developer-error-exception']);
124
        }
125
126
        if (is_array($modifications)) {
127
            foreach ($modifications as $key => $value) {
128
                $button->{$key} = $value;
129
            }
130
        }
131
132
        return $button;
133
    }
134
135
    /**
136
     * Remove a button from the CRUD panel.
137
     *
138
     * @param  string  $name  Button name.
139
     * @param  string  $stack  Optional stack name.
140
     */
141
    public function removeButton($name, $stack = null)
142
    {
143
        $this->setOperationSetting('buttons', $this->buttons()->reject(function ($button) use ($name, $stack) {
144
            return $stack == null ? $button->name == $name : ($button->stack == $stack) && ($button->name == $name);
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $stack of type null|string against null; this is ambiguous if the string can be empty. Consider using a strict comparison === instead.
Loading history...
145
        }));
146
    }
147
148
    /**
149
     * @param  array  $names  Button names
150
     * @param  string|null  $stack  Optional stack name.
151
     */
152
    public function removeButtons($names, $stack = null)
153
    {
154
        if (! empty($names)) {
155
            foreach ($names as $name) {
156
                $this->removeButton($name, $stack);
157
            }
158
        }
159
    }
160
161
    public function removeAllButtons()
162
    {
163
        $this->setOperationSetting('buttons', collect());
164
    }
165
166
    public function removeAllButtonsFromStack($stack)
167
    {
168
        $this->setOperationSetting('buttons', $this->buttons()->reject(function ($button) use ($stack) {
169
            return $button->stack == $stack;
170
        }));
171
    }
172
173
    public function removeButtonFromStack($name, $stack)
174
    {
175
        $this->setOperationSetting('buttons', $this->buttons()->reject(function ($button) use ($name, $stack) {
176
            return $button->name == $name && $button->stack == $stack;
177
        }));
178
    }
179
180
    /**
181
     * Move the most recently added button before or after the given target button. Default is before.
182
     *
183
     * @param  string|array  $target  The target button name or array.
184
     * @param  string|array  $where  Move 'before' or 'after' the target.
185
     * @param  string|array  $destination  The destination button name or array.
186
     */
187
    public function moveButton($target, $where, $destination)
188
    {
189
        $targetButton = $this->firstButtonWhere('name', $target);
0 ignored issues
show
Bug introduced by
It seems like $target can also be of type array; however, parameter $value of Backpack\CRUD\app\Librar...ons::firstButtonWhere() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

189
        $targetButton = $this->firstButtonWhere('name', /** @scrutinizer ignore-type */ $target);
Loading history...
190
191
        $destinationButton = $this->firstButtonWhere('name', $destination);
192
        $destinationKey = $this->getButtonKey($destination);
193
        $newDestinationKey = ($where == 'before' ? $destinationKey : $destinationKey + 1);
194
195
        $newButtons = $this->buttons()->filter(function ($value, $key) use ($target) {
0 ignored issues
show
Unused Code introduced by
The parameter $key is not used and could be removed. ( Ignorable by Annotation )

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

195
        $newButtons = $this->buttons()->filter(function ($value, /** @scrutinizer ignore-unused */ $key) use ($target) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
196
            return $value->name != $target;
197
        });
198
199
        if (! $targetButton) {
200
            return;
201
        }
202
203
        if (! $destinationButton) {
204
            return;
205
        }
206
207
        $firstSlice = $newButtons->slice(0, $newDestinationKey);
0 ignored issues
show
Bug introduced by
It seems like $newDestinationKey can also be of type string; however, parameter $length of Illuminate\Support\Collection::slice() does only seem to accept integer|null, maybe add an additional type check? ( Ignorable by Annotation )

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

207
        $firstSlice = $newButtons->slice(0, /** @scrutinizer ignore-type */ $newDestinationKey);
Loading history...
208
        $lastSlice = $newButtons->slice($newDestinationKey, null);
0 ignored issues
show
Bug introduced by
It seems like $newDestinationKey can also be of type string; however, parameter $offset of Illuminate\Support\Collection::slice() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

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

208
        $lastSlice = $newButtons->slice(/** @scrutinizer ignore-type */ $newDestinationKey, null);
Loading history...
209
210
        $newButtons = $firstSlice->push($targetButton);
0 ignored issues
show
Bug introduced by
$targetButton of type true is incompatible with the type Illuminate\Support\TValue expected by parameter $values of Illuminate\Support\Collection::push(). ( Ignorable by Annotation )

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

210
        $newButtons = $firstSlice->push(/** @scrutinizer ignore-type */ $targetButton);
Loading history...
211
212
        $lastSlice->each(function ($item, $key) use ($newButtons) {
0 ignored issues
show
Unused Code introduced by
The parameter $key is not used and could be removed. ( Ignorable by Annotation )

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

212
        $lastSlice->each(function ($item, /** @scrutinizer ignore-unused */ $key) use ($newButtons) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
213
            $newButtons->push($item);
214
        });
215
216
        $this->setOperationSetting('buttons', $newButtons);
217
    }
218
219
    /**
220
     * Check if a button exists, by any given attribute.
221
     *
222
     * @param  string  $attribute  Attribute name on that button definition array.
223
     * @param  string  $value  Value of that attribute on that button definition array.
224
     * @return bool
225
     */
226
    public function hasButtonWhere($attribute, $value)
227
    {
228
        return $this->buttons()->contains($attribute, $value);
229
    }
230
231
    /**
232
     * Get the first button where a given attribute has the given value.
233
     *
234
     * @param  string  $attribute  Attribute name on that button definition array.
235
     * @param  string  $value  Value of that attribute on that button definition array.
236
     * @return bool
237
     */
238
    public function firstButtonWhere($attribute, $value)
239
    {
240
        return $this->buttons()->firstWhere($attribute, $value);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->buttons()-...ere($attribute, $value) also could return the type Illuminate\Support\Traits\TValue which is incompatible with the documented return type boolean.
Loading history...
241
    }
242
243
    /**
244
     * Get button key from its name.
245
     *
246
     * @param  string  $buttonName  Button name.
247
     * @return string
248
     */
249
    public function getButtonKey($name)
250
    {
251
        $array = $this->buttons()->toArray();
252
253
        foreach ($array as $key => $value) {
254
            if ((is_object($value) ? $value->name : $value['name']) === $name) {
255
                return $key;
256
            }
257
        }
258
    }
259
260
    /**
261
     * Return the buttons for a given stack.
262
     */
263
    public function getButtonsForStack(string $stack): Collection
264
    {
265
        return $this->buttons()->where('stack', $stack);
266
    }
267
268
    /**
269
     * Add a new button to the current CRUD operation.
270
     */
271
    public function button(string|array $nameOrAttributes): CrudButton
272
    {
273
        return new CrudButton($nameOrAttributes);
274
    }
275
276
    /**
277
     *  Reorganize a collection by putting certain elements at the beginning
278
     *
279
     * @param string       $stack
280
     * @param array|string $startButtons
281
     * @param bool         $abortIfNotExist
282
     */
283
    public function buttonsStartWith(string $stack, array|string $startButtons, bool $abortIfNotExist = true): void
284
    {
285
        $startButtons = is_array($startButtons)
0 ignored issues
show
introduced by
The condition is_array($startButtons) is always true.
Loading history...
286
            ? $startButtons
287
            : [$startButtons];
288
289
        $stackButtons = $this->buttons()
290
            ->where('stack', $stack)
291
            ->pluck('name')
292
            ->toArray();
293
294
        $startItems = [];
295
296
        foreach ($startButtons as $btnKey) {
297
            if (!in_array($btnKey, $stackButtons)) {
298
                if($abortIfNotExist) {
299
                    abort(500, 'Button name [«' . $btnKey . '»] not found.', ['developer-error-exception']);
300
                }
301
            }
302
            else {
303
                $startItems[] = $btnKey;
304
            }
305
        }
306
307
        $remainingItems = array_diff($stackButtons, $startItems);
308
        $orderedButtons = [...$startItems, ...$remainingItems];
309
310
        $this->orderButtons($stack, $orderedButtons);
311
    }
312
313
    /**
314
     * Réorganise une collection en mettant certains éléments à la fin
315
     *
316
     * @param string       $stack
317
     * @param array|string $endButtons
318
     * @param bool         $abortIfNotExist
319
     */
320
    public
321
    function buttonsEndWith(string $stack, array|string $endButtons, bool $abortIfNotExist = true): void
322
    {
323
        $endButtons = is_array($endButtons)
0 ignored issues
show
introduced by
The condition is_array($endButtons) is always true.
Loading history...
324
            ? $endButtons
325
            : [$endButtons];
326
327
        $stackButtons = $this->buttons()
328
            ->where('stack', $stack)
329
            ->pluck('name')
330
            ->toArray();
331
332
        $endItems = [];
333
334
        foreach ($endButtons as $btnKey) {
335
            if (!in_array($btnKey, $stackButtons)) {
336
                if($abortIfNotExist) {
337
                    abort(500, 'Button name [«' . $btnKey . '»] not found.', ['developer-error-exception']);
338
                }
339
            }
340
            else {
341
                $endItems[] = $btnKey;
342
            }
343
        }
344
345
        $remainingItems = array_diff($stackButtons, $endItems);
346
        $orderedButtons = [...$remainingItems, ...$endItems];
347
348
        $this->orderButtons($stack, $orderedButtons);
349
    }
350
351
}
352