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

SaveActions::addSaveActions()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 8
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 3
nc 3
nop 1
dl 0
loc 8
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Backpack\CRUD\app\Library\CrudPanel\Traits;
4
5
use Illuminate\Support\Arr;
6
7
trait SaveActions
8
{
9
    /**
10
     * Get the developer's preference on what save action is the default one
11
     * for the current operation.
12
     *
13
     * @return string
14
     */
15
    public function getSaveActionDefaultForCurrentOperation()
16
    {
17
        return config('backpack.crud.operations.'.$this->getCurrentOperation().'.defaultSaveAction', 'save_and_back');
0 ignored issues
show
Bug introduced by
The method getCurrentOperation() does not exist on Backpack\CRUD\app\Librar...anel\Traits\SaveActions. Did you maybe mean getCurrentSaveAction()? ( Ignorable by Annotation )

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

17
        return config('backpack.crud.operations.'.$this->/** @scrutinizer ignore-call */ getCurrentOperation().'.defaultSaveAction', 'save_and_back');

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
18
    }
19
20
    /**
21
     * Get the save action with full fallback until default.
22
     *
23
     * @return string
24
     */
25
    public function getFallBackSaveAction()
26
    {
27
        //we get the higher order in save actions array. By default it would be `save_and_back`
28
        $higherAction = $this->getSaveActionByOrder(1);
29
30
        //if there is an higher action and that action is not the backpack default higher one `save_and_back` we return it.
31
        if (! empty($higherAction) && key($higherAction) !== 'save_and_back') {
32
            return key($higherAction);
33
        }
34
35
        if ($this->hasOperationSetting('defaultSaveAction')) {
0 ignored issues
show
Bug introduced by
It seems like hasOperationSetting() 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

35
        if ($this->/** @scrutinizer ignore-call */ hasOperationSetting('defaultSaveAction')) {
Loading history...
36
            return $this->getOperationSetting('defaultSaveAction');
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

36
            return $this->/** @scrutinizer ignore-call */ getOperationSetting('defaultSaveAction');
Loading history...
37
        }
38
39
        return $this->getSaveActionDefaultForCurrentOperation();
40
    }
41
42
    /**
43
     * Gets the save action that has the desired order.
44
     *
45
     * @param  int  $order
46
     * @return array
47
     */
48
    public function getSaveActionByOrder($order)
49
    {
50
        return array_filter($this->getOperationSetting('save_actions') ?? [], function ($arr) use ($order) {
51
            return $arr['order'] == $order;
52
        });
53
    }
54
55
    /**
56
     * Allow the developer to register multiple save actions.
57
     *
58
     * @param  array  $saveActions
59
     * @return void
60
     */
61
    public function addSaveActions($saveActions)
62
    {
63
        // count vs count recursive will be different when counting single dimension vs multiple dimension arrays.
64
        // count([1,2]) = 2, count([1,[2,3]]) = 2 with recursive it's 3. so if counts are different we have a
65
        // multi dimensional array
66
        if (count($saveActions) != count($saveActions, COUNT_RECURSIVE)) {
67
            foreach ($saveActions as $saveAction) {
68
                $this->addSaveAction($saveAction);
69
            }
70
        }
71
    }
72
73
    /**
74
     * Allow developers to register save action into CRUD.
75
     *
76
     * @param  array  $saveAction
77
     * @return void
78
     */
79
    public function addSaveAction(array $saveAction)
80
    {
81
        $orderCounter = $this->getOperationSetting('save_actions') !== null ? (count($this->getOperationSetting('save_actions')) + 1) : 1;
82
        //check for some mandatory fields
83
        $saveAction['name'] ?? abort(500, 'Please define save action name.', ['developer-error-exception']);
0 ignored issues
show
Bug introduced by
Are you sure the usage of abort(500, 'Please defin...oper-error-exception')) is correct as it seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
84
        $saveAction['redirect'] = $saveAction['redirect'] ?? fn ($crud, $request, $itemId) => $request->has('_http_referrer') ? $request->get('_http_referrer') : $crud->route;
0 ignored issues
show
Unused Code introduced by
The parameter $itemId 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

84
        $saveAction['redirect'] = $saveAction['redirect'] ?? fn ($crud, $request, /** @scrutinizer ignore-unused */ $itemId) => $request->has('_http_referrer') ? $request->get('_http_referrer') : $crud->route;

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...
85
        $saveAction['visible'] = $saveAction['visible'] ?? true;
86
        $saveAction['button_text'] = $saveAction['button_text'] ?? $saveAction['name'];
87
        $saveAction['order'] = isset($saveAction['order']) ? $this->orderSaveAction($saveAction['name'], $saveAction['order']) : $orderCounter;
88
89
        $actions = $this->getOperationSetting('save_actions') ?? [];
90
91
        if (! in_array($saveAction['name'], $actions)) {
92
            $actions[$saveAction['name']] = $saveAction;
93
        }
94
95
        $this->setOperationSetting('save_actions', $actions);
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

95
        $this->/** @scrutinizer ignore-call */ 
96
               setOperationSetting('save_actions', $actions);
Loading history...
96
    }
97
98
    /**
99
     * Replaces setting order or forces some default.
100
     *
101
     * @param  string  $saveAction
102
     * @param  int  $wantedOrder
103
     * @return int
104
     */
105
    public function orderSaveAction(string $saveAction, int $wantedOrder)
106
    {
107
        $actions = $this->getOperationSetting('save_actions') ?? [];
108
        if (! empty($actions)) {
109
            $replaceOrder = isset($actions[$saveAction]) ? $actions[$saveAction]['order'] : count($actions) + 1;
110
111
            foreach ($actions as $key => $sv) {
112
                if ($wantedOrder == $sv['order']) {
113
                    $actions[$key]['order'] = $replaceOrder;
114
                }
115
                if ($key == $saveAction) {
116
                    $actions[$key]['order'] = $wantedOrder;
117
                }
118
            }
119
            $this->setOperationSetting('save_actions', $actions);
120
        }
121
122
        return $wantedOrder;
123
    }
124
125
    /**
126
     * Replace the current save actions with the ones provided.
127
     *
128
     * @param  array  $saveActions
129
     * @return void
130
     */
131
    public function replaceSaveActions($saveActions)
132
    {
133
        //we reset all save actions
134
        $this->setOperationSetting('save_actions', []);
135
136
        if (count($saveActions) != count($saveActions, COUNT_RECURSIVE)) {
137
            $this->addSaveActions($saveActions);
138
        } else {
139
            $this->addSaveAction($saveActions);
140
        }
141
    }
142
143
    /**
144
     * Alias function of replaceSaveActions() for CRUD consistency.
145
     *
146
     * @param  array  $saveActions
147
     * @return void
148
     */
149
    public function setSaveActions($saveActions)
150
    {
151
        return $this->replaceSaveActions($saveActions);
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->replaceSaveActions($saveActions) targeting Backpack\CRUD\app\Librar...s::replaceSaveActions() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
152
    }
153
154
    /**
155
     * Allow the developer to remove multiple save actions from settings.
156
     *
157
     * @param  array  $saveActions
158
     * @return void
159
     */
160
    public function removeSaveActions(array $saveActions)
161
    {
162
        foreach ($saveActions as $sv) {
163
            $this->removeSaveAction($sv);
164
        }
165
    }
166
167
    /**
168
     * Allow the developer to remove a save action from settings.
169
     *
170
     * @param  string  $saveAction
171
     * @return void
172
     */
173
    public function removeSaveAction(string $saveAction)
174
    {
175
        $actions = $this->getOperationSetting('save_actions') ?? [];
176
        if (isset($actions[$saveAction])) {
177
            $actions[$saveAction] = null;
178
        }
179
        $this->setOperationSetting('save_actions', array_filter($actions));
180
    }
181
182
    /**
183
     * Allow the developer to unset all save actions.
184
     *
185
     * @param  string  $saveAction
186
     * @return void
187
     */
188
    public function removeAllSaveActions()
189
    {
190
        $this->setOperationSetting('save_actions', []);
191
    }
192
193
    /**
194
     * Allows the developer to set save actions order. It could be ['action1','action2'] or ['action1' => 1, 'action2' => 2].
195
     *
196
     * @param  array  $saveActions
197
     * @return void
198
     */
199
    public function orderSaveActions(array $saveActions)
200
    {
201
        foreach ($saveActions as $sv => $order) {
202
            if (! is_int($order)) {
203
                $this->orderSaveAction($order, $sv + 1);
204
            } else {
205
                $this->orderSaveAction($sv, $order);
206
            }
207
        }
208
    }
209
210
    /**
211
     * Return the ordered save actions to use in the crud panel.
212
     *
213
     * @return array
214
     */
215
    public function getOrderedSaveActions()
216
    {
217
        $actions = $this->getOperationSetting('save_actions') ?? [];
218
219
        uasort($actions, function ($a, $b) {
220
            return $a['order'] <=> $b['order'];
221
        });
222
223
        return $actions;
224
    }
225
226
    /**
227
     * Returns the save actions that passed the visible callback.
228
     *
229
     * @return array
230
     */
231
    public function getVisibleSaveActions()
232
    {
233
        $actions = $this->getOrderedSaveActions();
234
        foreach ($actions as $actionName => $action) {
235
            $visible = $action['visible'];
236
            if ($visible instanceof \Closure) {
237
                $actions[$actionName]['visible'] = $visible($this);
238
            }
239
        }
240
241
        return array_filter($actions, function ($action) {
242
            return $action['visible'] == true;
243
        }, ARRAY_FILTER_USE_BOTH);
244
    }
245
246
    /**
247
     * Gets the current save action for this crud.
248
     *
249
     * @param  array  $saveOptions
250
     * @return array
251
     */
252
    public function getCurrentSaveAction($saveOptions)
253
    {
254
        //get save action from session if exists, or get the developer defined order
255
        $saveAction = session($this->getCurrentOperation().'.saveAction', $this->getFallBackSaveAction());
256
        if (isset($saveOptions[$saveAction])) {
257
            $currentAction = $saveOptions[$saveAction];
258
        } else {
259
            $currentAction = Arr::first($saveOptions);
260
        }
261
262
        return [
263
            'value' => $currentAction['name'],
264
            'label' => $currentAction['button_text'],
265
        ];
266
    }
267
268
    /**
269
     * Here we check for save action visibility and prepare the actions array for display.
270
     *
271
     * @return array
272
     */
273
    public function getSaveAction()
274
    {
275
        //get only the save actions that pass visibility callback
276
        $saveOptions = $this->getVisibleSaveActions();
277
278
        if (empty($saveOptions)) {
279
            return [];
280
        }
281
282
        //get the current action
283
        $saveCurrent = $this->getCurrentSaveAction($saveOptions);
284
285
        //get the dropdown options
286
        $dropdownOptions = [];
287
        foreach ($saveOptions as $key => $option) {
288
            if ($option['name'] != $saveCurrent['value']) {
289
                $dropdownOptions[$option['name']] = $option['button_text'];
290
            }
291
        }
292
293
        return [
294
            'active' => $saveCurrent,
295
            'options' => $dropdownOptions,
296
        ];
297
    }
298
299
    /**
300
     * Change the session variable that remembers what to do after the "Save" action.
301
     *
302
     * @param  string|null  $forceSaveAction
303
     * @return void
304
     */
305
    public function setSaveAction($forceSaveAction = null)
306
    {
307
        $saveAction = $forceSaveAction ?:
308
            $this->getRequest()->input('_save_action', $this->getFallBackSaveAction());
0 ignored issues
show
Bug introduced by
It seems like getRequest() 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

308
            $this->/** @scrutinizer ignore-call */ 
309
                   getRequest()->input('_save_action', $this->getFallBackSaveAction());
Loading history...
309
310
        $showBubble = $this->getOperationSetting('showSaveActionChange') ?? config('backpack.crud.operations.'.$this->getCurrentOperation().'.showSaveActionChange') ?? true;
311
312
        if (
313
            $showBubble &&
314
            session($this->getCurrentOperation().'.saveAction', 'save_and_back') !== $saveAction
315
        ) {
316
            \Alert::info(trans('backpack::crud.save_action_changed_notification'))->flash();
0 ignored issues
show
Bug introduced by
The type Alert was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
317
        }
318
319
        session([$this->getCurrentOperation().'.saveAction' => $saveAction]);
320
    }
321
322
    /**
323
     * Redirect to the correct URL, depending on which save action has been selected.
324
     *
325
     * @param  string  $itemId
326
     * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\RedirectResponse
327
     */
328
    public function performSaveAction($itemId = null)
329
    {
330
        $request = $this->getRequest();
331
        $saveAction = $request->input('_save_action', $this->getFallBackSaveAction());
332
        $itemId = $itemId ?: $request->input('id');
333
        $actions = $this->getOperationSetting('save_actions');
334
        $redirectUrl = $this->route;
335
336
        if (isset($actions[$saveAction])) {
337
            if ($actions[$saveAction]['redirect'] instanceof \Closure) {
338
                $redirectUrl = $actions[$saveAction]['redirect']($this, $request, $itemId);
339
            }
340
341
            //allow the save action to define default http_referrer (url for the save_and_back button)
342
            if (isset($actions[$saveAction]['referrer_url'])) {
343
                if ($actions[$saveAction]['referrer_url'] instanceof \Closure) {
344
                    $referrer_url = $actions[$saveAction]['referrer_url']($this, $request, $itemId);
345
                }
346
            }
347
        }
348
349
        // if the request is AJAX, return a JSON response
350
        if ($this->getRequest()->ajax()) {
351
            return response()->json([
352
                'success' => true,
353
                'data' => $this->entry,
354
                'redirect_url' => $redirectUrl,
355
                'referrer_url' => $referrer_url ?? false,
356
            ]);
357
        }
358
359
        if (isset($referrer_url)) {
360
            session()->flash('referrer_url_override', $referrer_url);
361
        }
362
363
        return \Redirect::to($redirectUrl);
364
    }
365
366
    /**
367
     * This functions register Backpack default save actions into CRUD.
368
     *
369
     * @return array
370
     */
371
    public function setupDefaultSaveActions()
372
    {
373
        $defaultSaveActions = [
374
            [
375
                'name' => 'save_and_back',
376
                'visible' => function ($crud) {
377
                    return $crud->hasAccess('list');
378
                },
379
                'redirect' => function ($crud, $request, $itemId = null) {
0 ignored issues
show
Unused Code introduced by
The parameter $itemId 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

379
                'redirect' => function ($crud, $request, /** @scrutinizer ignore-unused */ $itemId = null) {

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...
380
                    return $request->has('_http_referrer') ? $request->get('_http_referrer') : $crud->route;
381
                },
382
                'button_text' => trans('backpack::crud.save_action_save_and_back'),
383
            ],
384
            [
385
                'name' => 'save_and_edit',
386
                'visible' => function ($crud) {
387
                    return $crud->hasAccess('update');
388
                },
389
                'redirect' => function ($crud, $request, $itemId = null) {
390
                    $itemId = $itemId ?: $request->get('id');
391
                    $redirectUrl = $crud->route.'/'.$itemId.'/edit';
392
                    if ($request->has('_locale')) {
393
                        $redirectUrl .= '?_locale='.$request->get('_locale');
394
                    }
395
                    if ($request->has('_current_tab')) {
396
                        $redirectUrl = $redirectUrl.'#'.$request->get('_current_tab');
397
                    }
398
399
                    return $redirectUrl;
400
                },
401
                'referrer_url' => function ($crud, $request, $itemId) {
402
                    return url($crud->route.'/'.$itemId.'/edit');
403
                },
404
                'button_text' => trans('backpack::crud.save_action_save_and_edit'),
405
            ],
406
            [
407
                'name' => 'save_and_new',
408
                'visible' => function ($crud) {
409
                    return $crud->hasAccess('create');
410
                },
411
                'redirect' => function ($crud, $request, $itemId = null) {
0 ignored issues
show
Unused Code introduced by
The parameter $request 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

411
                'redirect' => function ($crud, /** @scrutinizer ignore-unused */ $request, $itemId = null) {

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...
Unused Code introduced by
The parameter $itemId 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

411
                'redirect' => function ($crud, $request, /** @scrutinizer ignore-unused */ $itemId = null) {

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...
Unused Code introduced by
The parameter $crud 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

411
                'redirect' => function (/** @scrutinizer ignore-unused */ $crud, $request, $itemId = null) {

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...
412
                    return $this->route.'/create';
413
                },
414
                'button_text' => trans('backpack::crud.save_action_save_and_new'),
415
            ],
416
        ];
417
418
        $this->addSaveActions($defaultSaveActions);
419
    }
420
}
421