Completed
Push — master ( 227500...2b3681 )
by Thomas
15s queued 13s
created

ActionsGridFieldItemRequest::moveCancelAndDelete()   B

Complexity

Conditions 7
Paths 25

Size

Total Lines 38
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 1
Metric Value
cc 7
eloc 19
c 2
b 0
f 1
nc 25
nop 2
dl 0
loc 38
rs 8.8333
1
<?php
2
3
namespace LeKoala\CmsActions;
4
5
use Exception;
6
use SilverStripe\Forms\Form;
7
use SilverStripe\ORM\DataObject;
8
use SilverStripe\Forms\FieldList;
9
use SilverStripe\Control\Director;
10
use SilverStripe\Forms\FormAction;
11
use SilverStripe\Admin\LeftAndMain;
12
use SilverStripe\ORM\DataExtension;
13
use SilverStripe\Control\Controller;
14
use SilverStripe\Control\HTTPRequest;
15
use SilverStripe\Control\HTTPResponse;
16
use SilverStripe\Core\Config\Configurable;
17
use SilverStripe\ORM\ValidationResult;
18
use SilverStripe\Forms\GridField\GridFieldDetailForm_ItemRequest;
19
use SilverStripe\Forms\Tab;
20
use SilverStripe\Forms\TabSet;
21
22
/**
23
 * Decorates GridDetailForm_ItemRequest to use new form actions and buttons.
24
 * This is also applied to LeftAndMain to allow actions on pages
25
 *
26
 * This is a lightweight version of BetterButtons that use default getCMSActions functionnality
27
 * on DataObjects
28
 *
29
 * @link https://github.com/unclecheese/silverstripe-gridfield-betterbuttons
30
 * @link https://github.com/unclecheese/silverstripe-gridfield-betterbuttons/blob/master/src/Extensions/GridFieldBetterButtonsItemRequest.php
31
 * @property \SilverStripe\Forms\GridField\GridFieldDetailForm_ItemRequest|\SilverStripe\Admin\LeftAndMain $owner
32
 */
33
class ActionsGridFieldItemRequest extends DataExtension
34
{
35
    use Configurable;
36
37
    /**
38
     * @config
39
     * @var boolean
40
     */
41
    private static $enable_save_prev_next = true;
42
43
    /**
44
     * @config
45
     * @var boolean
46
     */
47
    private static $enable_save_close = true;
48
49
    /**
50
     * @config
51
     * @var boolean
52
     */
53
    private static $enable_delete_right = true;
54
55
    /**
56
     * @config
57
     * @var boolean
58
     */
59
    private static $enable_utils_prev_next = false;
0 ignored issues
show
introduced by
The private property $enable_utils_prev_next is not used, and could be removed.
Loading history...
60
61
    /**
62
     * @var array Allowed controller actions
63
     */
64
    private static $allowed_actions = array(
0 ignored issues
show
introduced by
The private property $allowed_actions is not used, and could be removed.
Loading history...
65
        'doSaveAndClose',
66
        'doSaveAndNext',
67
        'doSaveAndPrev',
68
        'doCustomAction', // For CustomAction
69
        'doCustomLink', // For CustomLink
70
    );
71
72
    /**
73
     * @return array
74
     */
75
    protected function getAvailableActions($actions)
76
    {
77
        $list = [];
78
        foreach ($actions as $action) {
79
            $list[] = $action->getName();
80
        }
81
        return $list;
82
    }
83
84
    /**
85
     * Updates the detail form to include new form actions and buttons
86
     *
87
     * Reorganize things a bit
88
     *
89
     * @param Form The ItemEditForm object
0 ignored issues
show
Bug introduced by
The type LeKoala\CmsActions\The 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...
90
     */
91
    public function updateItemEditForm($form)
92
    {
93
        $itemRequest = $this->owner;
94
        $record = $itemRequest->record;
95
        if (!$record) {
96
            $record = $form->getRecord();
97
        }
98
        if (!$record) {
99
            return;
100
        }
101
102
        // We get the actions as defined on our record
103
        $CMSActions = $record->getCMSActions();
104
105
        // We can the actions from the GridFieldDetailForm_ItemRequest
106
        // It sets the Save and Delete buttons + Right Group
107
        $actions = $form->Actions();
108
109
        // The default button group that contains the Save or Create action
110
        // @link https://docs.silverstripe.org/en/4/developer_guides/customising_the_admin_interface/how_tos/extend_cms_interface/#extending-the-cms-actions
111
        $MajorActions = $actions->fieldByName('MajorActions');
112
113
        // If it doesn't exist, push to default group
114
        if (!$MajorActions) {
115
            $MajorActions = $actions;
0 ignored issues
show
Unused Code introduced by
The assignment to $MajorActions is dead and can be removed.
Loading history...
116
        }
117
118
        // The Drop-up container may already exist
119
        $dropUpContainer = $actions->fieldByName('ActionMenus.MoreOptions');
120
121
        // Push our actions that are otherwise ignored by SilverStripe
122
        foreach ($CMSActions as $action) {
123
            if ($action->getDropUp()) {
124
                if (!$dropUpContainer) {
125
                    $dropUpContainer = $this->createDropUpContainer($actions);
126
                }
127
                $dropUpContainer->push($action);
128
            } else {
129
                $actions->push($action);
130
            }
131
        }
132
133
        // Add extension hook
134
        $record->extend('onBeforeUpdateCMSActions', $actions);
135
136
        $ActionMenus = $actions->fieldByName('ActionMenus');
137
        // Re-insert ActionMenus to make sure they lways follow the buttons
138
        if ($ActionMenus) {
139
            $actions->remove($ActionMenus);
140
            $actions->push($ActionMenus);
141
        }
142
143
        // We have a 4.4 setup, before that there was no RightGroup
144
        $RightGroup = $actions->fieldByName('RightGroup');
145
146
        // Insert again to make sure our actions are properly placed after apply changes
147
        if ($RightGroup) {
148
            $actions->remove($RightGroup);
149
            $actions->push($RightGroup);
150
        }
151
152
        if (self::config()->enable_save_close) {
153
            $this->addSaveAndClose($actions, $record);
154
        }
155
156
        if (self::config()->enable_save_prev_next) {
157
            $this->addSaveNextAndPrevious($actions, $record);
158
        }
159
160
        if (self::config()->enable_delete_right) {
161
            $this->moveCancelAndDelete($actions, $record);
162
        }
163
164
        // Add extension hook
165
        $record->extend('onAfterUpdateCMSActions', $actions);
166
    }
167
168
    /**
169
     * Prepares a Drop-Up menu
170
     * @param FieldList $actions
171
     * @return Tab
172
     */
173
    protected function createDropUpContainer($actions)
174
    {
175
        $rootTabSet = new TabSet('ActionMenus');
176
        $dropUpContainer = new Tab(
177
            'MoreOptions',
178
            _t(__CLASS__ . '.MoreOptions', 'More options', 'Expands a view for more buttons')
179
        );
180
        $dropUpContainer->addExtraClass('popover-actions-simulate');
181
        $rootTabSet->push($dropUpContainer);
182
        $rootTabSet->addExtraClass('ss-ui-action-tabset action-menus noborder');
183
184
        $actions->insertBefore('RightGroup', $rootTabSet);
185
        return $dropUpContainer;
186
    }
187
188
    /**
189
     * @param FieldList $actions
190
     * @param DataObject $record
191
     * @return void
192
     */
193
    public function moveCancelAndDelete(FieldList $actions, DataObject $record)
194
    {
195
        // We have a 4.4 setup, before that there was no RightGroup
196
        $RightGroup = $actions->fieldByName('RightGroup');
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $RightGroup is correct as $actions->fieldByName('RightGroup') targeting SilverStripe\Forms\FieldList::fieldByName() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

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

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

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

Loading history...
197
198
        // Move delete at the end
199
        $deleteAction = $actions->fieldByName('action_doDelete');
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $deleteAction is correct as $actions->fieldByName('action_doDelete') targeting SilverStripe\Forms\FieldList::fieldByName() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

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

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

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

Loading history...
200
        if ($deleteAction) {
0 ignored issues
show
introduced by
$deleteAction is of type null, thus it always evaluated to false.
Loading history...
201
            // Move at the end of the stack
202
            $actions->remove($deleteAction);
203
            $actions->push($deleteAction);
204
205
            if ($RightGroup) {
206
                // Stack position is enough to have it on the left
207
            } else {
208
                // Only necessary pre 4.4
209
                $deleteAction->addExtraClass('align-right');
210
            }
211
            // Set custom title
212
            if ($record->hasMethod('getDeleteButtonTitle')) {
213
                $deleteAction->setTitle($record->getDeleteButtonTitle());
214
            }
215
        }
216
        // Move cancel at the end
217
        $cancelButton = $actions->fieldByName('cancelbutton');
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $cancelButton is correct as $actions->fieldByName('cancelbutton') targeting SilverStripe\Forms\FieldList::fieldByName() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

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

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

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

Loading history...
218
        if ($cancelButton) {
0 ignored issues
show
introduced by
$cancelButton is of type null, thus it always evaluated to false.
Loading history...
219
            // Move at the end of the stack
220
            $actions->remove($cancelButton);
221
            $actions->push($cancelButton);
222
            if ($RightGroup) {
223
                // Stack position is enough to have it on the left
224
            } else {
225
                // Only necessary pre 4.4
226
                $cancelButton->addExtraClass('align-right');
227
            }
228
            // Set custom titlte
229
            if ($record->hasMethod('getCancelButtonTitle')) {
230
                $cancelButton->setTitle($record->getCancelButtonTitle());
231
            }
232
        }
233
    }
234
235
    /**
236
     * @param DataObject $record
237
     * @return int
238
     */
239
    public function getCustomPreviousRecordID(DataObject $record)
240
    {
241
        if ($record->hasMethod('PrevRecord')) {
242
            return $record->PrevRecord()->ID ?? 0;
243
        }
244
        return $this->owner->getPreviousRecordID();
245
    }
246
247
    /**
248
     * @param DataObject $record
249
     * @return int
250
     */
251
    public function getCustomNextRecordID(DataObject $record)
252
    {
253
        if ($record->hasMethod('NextRecord')) {
254
            return $record->NextRecord()->ID ?? 0;
255
        }
256
        return $this->owner->getNextRecordID();
257
    }
258
259
    /**
260
     * @param FieldList $actions
261
     * @param DataObject $record
262
     * @return void
263
     */
264
    public function addSaveNextAndPrevious(FieldList $actions, DataObject $record)
265
    {
266
        if (!$record->canEdit()) {
267
            return;
268
        }
269
        if (!$record->ID) {
270
            return;
271
        }
272
273
        $MajorActions = $actions->fieldByName('MajorActions');
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $MajorActions is correct as $actions->fieldByName('MajorActions') targeting SilverStripe\Forms\FieldList::fieldByName() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

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

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

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

Loading history...
274
275
        // If it doesn't exist, push to default group
276
        if (!$MajorActions) {
0 ignored issues
show
introduced by
$MajorActions is of type null, thus it always evaluated to false.
Loading history...
277
            $MajorActions = $actions;
278
        }
279
280
        // TODO: check why with paginator, after the first page, getPreviousRecordID/getNextRecordID tend to not work properly
281
        $getPreviousRecordID = $this->getCustomPreviousRecordID($record);
282
        $getNextRecordID = $this->getCustomNextRecordID($record);
283
284
        // Coupling for HasPrevNextUtils
285
        if (Controller::has_curr()) {
286
            $request =  Controller::curr()->getRequest();
287
            $routeParams = $request->routeParams();
288
            $routeParams['PreviousRecordID'] = $getPreviousRecordID;
289
            $routeParams['NextRecordID'] = $getNextRecordID;
290
            $request->setRouteParams($routeParams);
291
        }
292
293
        if ($getPreviousRecordID) {
294
            $doSaveAndPrev = new FormAction('doSaveAndPrev', _t('ActionsGridFieldItemRequest.SAVEANDPREVIOUS', 'Save and Previous'));
295
            $doSaveAndPrev->addExtraClass($this->getBtnClassForRecord($record));
296
            $doSaveAndPrev->addExtraClass('font-icon-angle-double-left');
297
            $doSaveAndPrev->setUseButtonTag(true);
298
            $MajorActions->push($doSaveAndPrev);
299
        }
300
        if ($getNextRecordID) {
301
            $doSaveAndNext = new FormAction('doSaveAndNext', _t('ActionsGridFieldItemRequest.SAVEANDNEXT', 'Save and Next'));
302
            $doSaveAndNext->addExtraClass($this->getBtnClassForRecord($record));
303
            $doSaveAndNext->addExtraClass('font-icon-angle-double-right');
304
            $doSaveAndNext->setUseButtonTag(true);
305
            $MajorActions->push($doSaveAndNext);
306
        }
307
    }
308
309
    /**
310
     * @param FieldList $actions
311
     * @param DataObject $record
312
     * @return void
313
     */
314
    public function addSaveAndClose(FieldList $actions, DataObject $record)
315
    {
316
        if (!$record->canEdit()) {
317
            return;
318
        }
319
        if (!$record->ID && !$record->canCreate()) {
320
            return;
321
        }
322
323
        $MajorActions = $actions->fieldByName('MajorActions');
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $MajorActions is correct as $actions->fieldByName('MajorActions') targeting SilverStripe\Forms\FieldList::fieldByName() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

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

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

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

Loading history...
324
325
        // If it doesn't exist, push to default group
326
        if (!$MajorActions) {
0 ignored issues
show
introduced by
$MajorActions is of type null, thus it always evaluated to false.
Loading history...
327
            $MajorActions = $actions;
328
        }
329
330
        if ($record->ID) {
331
            $label = _t('ActionsGridFieldItemRequest.SAVEANDCLOSE', 'Save and Close');
332
        } else {
333
            $label = _t('ActionsGridFieldItemRequest.CREATEANDCLOSE', 'Create and Close');
334
        }
335
        $saveAndClose = new FormAction('doSaveAndClose', $label);
336
        $saveAndClose->addExtraClass($this->getBtnClassForRecord($record));
337
        $saveAndClose->setAttribute('data-text-alternate', $label);
338
        if ($record->ID) {
339
            $saveAndClose->setAttribute('data-btn-alternate-add', 'btn-primary');
340
            $saveAndClose->setAttribute('data-btn-alternate-remove', 'btn-outline-primary');
341
        }
342
        $saveAndClose->addExtraClass('font-icon-level-up');
343
        $saveAndClose->setUseButtonTag(true);
344
        $MajorActions->push($saveAndClose);
345
    }
346
347
    /**
348
     * New and existing records have different classes
349
     *
350
     * @param DataObject $record
351
     * @return string
352
     */
353
    protected function getBtnClassForRecord(DataObject $record)
354
    {
355
        if ($record->ID) {
356
            return 'btn-outline-primary';
357
        }
358
        return 'btn-primary';
359
    }
360
361
    /**
362
     * Forward a given action to a DataObject
363
     *
364
     * Action must be declared in getCMSActions to be called
365
     *
366
     * @param string $action
367
     * @param array $data
368
     * @param Form $form
369
     * @return HTTPResponse|DBHTMLText|string
0 ignored issues
show
Bug introduced by
The type LeKoala\CmsActions\DBHTMLText 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...
370
     */
371
    protected function forwardActionToRecord($action, $data = [], $form = null)
372
    {
373
        $controller = $this->getToplevelController();
374
375
        // We have an item request
376
        $record = null;
377
        if ($this->owner instanceof GridFieldDetailForm_ItemRequest) {
378
            $record = $this->owner->record;
379
        } elseif ($controller instanceof LeftAndMain) {
380
            if (empty($data['ClassName']) || empty($data['ID'])) {
381
                throw new Exception("Submitted data does not contain and ID and a ClassName");
382
            }
383
            $record = DataObject::get_by_id($data['ClassName'], $data['ID']);
384
        } elseif ($controller->hasMethod("getRecord")) {
385
            $record = $controller->getRecord();
386
        }
387
388
        if (!$record) {
389
            throw new Exception("No record to handle the action $action on " . get_class($controller));
390
        }
391
        $definedActions = $record->getCMSActions();
392
        // Check if the action is indeed available
393
        $clickedAction = null;
394
        if (!empty($definedActions)) {
395
            foreach ($definedActions as $definedAction) {
396
                $definedActionName = $definedAction->getName();
397
                if ($definedAction->hasMethod('actionName')) {
398
                    $definedActionName = $definedAction->actionName();
399
                }
400
                if ($definedActionName == $action) {
401
                    $clickedAction = $definedAction;
402
                }
403
            }
404
        }
405
        if (!$clickedAction) {
406
            $class = get_class($record);
407
            $availableActions = implode(',', $this->getAvailableActions($definedActions));
408
            if (!$availableActions) {
409
                $availableActions = "(no available actions, please check getCMSActions)";
410
            }
411
            return $this->owner->httpError(403, 'Action not available on ' . $class . '. It must be one of : ' . $availableActions);
412
        }
413
        $message = null;
414
        $error = false;
415
416
        // Check record BEFORE the action
417
        // It can be deleted by the action and it will return to the list
418
        $isNewRecord = $record->ID == 0;
419
420
        try {
421
            $result = $record->$action($data, $form, $controller);
422
423
            // We have a response
424
            if ($result && $result instanceof HTTPResponse) {
425
                return $result;
426
            }
427
428
            if ($result === false) {
429
                // Result returned an error (false)
430
                $error = true;
431
                $message = _t(
432
                    'ActionsGridFieldItemRequest.FAILED',
433
                    'Action {action} failed on {name}',
434
                    array(
435
                        'action' => $clickedAction->getTitle(),
436
                        'name' => $record->i18n_singular_name(),
437
                    )
438
                );
439
            } elseif (is_string($result)) {
440
                // Result is a message
441
                $message = $result;
442
            }
443
        } catch (Exception $ex) {
444
            $error = true;
445
            $message = $ex->getMessage();
446
        }
447
448
        // Build default message
449
        if (!$message) {
450
            $message = _t(
451
                'ActionsGridFieldItemRequest.DONE',
452
                'Action {action} was done on {name}',
453
                array(
454
                    'action' => $clickedAction->getTitle(),
455
                    'name' => $record->i18n_singular_name(),
456
                )
457
            );
458
        }
459
        $status = 'good';
460
        if ($error) {
461
            $status = 'bad';
462
        }
463
464
        // Progressive actions return array with json data
465
        if (method_exists($clickedAction, 'getProgressive') && $clickedAction->getProgressive()) {
466
            $response = $controller->getResponse();
467
            $response->addHeader('Content-Type', 'application/json');
468
            if ($result) {
469
                $response->setBody(json_encode($result));
470
            }
471
            return $response;
472
        }
473
474
        // We don't have a form, simply return the result
475
        if (!$form) {
476
            if ($error) {
477
                return $this->owner->httpError(403, $message);
478
            }
479
            return $message;
480
        }
481
        if (Director::is_ajax()) {
482
            $controller = $this->getToplevelController();
483
            $controller->getResponse()->addHeader('X-Status', rawurlencode($message));
484
            if (method_exists($clickedAction, 'getShouldRefresh') && $clickedAction->getShouldRefresh()) {
485
                $controller->getResponse()->addHeader('X-Reload', "true");
486
            }
487
            // 4xx status makes a red box
488
            if ($error) {
489
                $controller->getResponse()->setStatusCode(400);
490
            }
491
        } else {
492
            $form->sessionMessage($message, $status, ValidationResult::CAST_HTML);
493
        }
494
        // Redirect after action
495
        return $this->redirectAfterAction($isNewRecord, $record);
496
    }
497
498
    /**
499
     * Handles custom links
500
     *
501
     * Use CustomLink with default behaviour to trigger this
502
     *
503
     * See:
504
     * DefaultLink::getModelLink
505
     * GridFieldCustomLink::getLink
506
     *
507
     * @param HTTPRequest $request
508
     * @return HTTPResponse|DBHTMLText|string
509
     */
510
    public function doCustomLink(HTTPRequest $request)
511
    {
512
        $action = $request->getVar('CustomLink');
513
        return $this->forwardActionToRecord($action);
514
    }
515
516
    /**
517
     * Handles custom actions
518
     *
519
     * Use CustomAction class to trigger this
520
     *
521
     * Nested actions are submitted like this
522
     * [action_doCustomAction] => Array
523
     * (
524
     *   [doTestAction] => 1
525
     * )
526
     *
527
     * @param array The form data
528
     * @param Form The form object
529
     * @return HTTPResponse|DBHTMLText|string
530
     */
531
    public function doCustomAction($data, $form)
532
    {
533
        $action = key($data['action_doCustomAction']);
534
        return $this->forwardActionToRecord($action, $data, $form);
535
    }
536
537
    /**
538
     * Saves the form and goes back to list view
539
     *
540
     * @param array The form data
541
     * @param Form The form object
542
     */
543
    public function doSaveAndClose($data, $form)
544
    {
545
        $result = $this->owner->doSave($data, $form);
0 ignored issues
show
Unused Code introduced by
The assignment to $result is dead and can be removed.
Loading history...
546
        // Redirect after save
547
        $controller = $this->getToplevelController();
548
        $controller->getResponse()->addHeader("X-Pjax", "Content");
549
        return $controller->redirect($this->getBackLink());
550
    }
551
552
    /**
553
     * Saves the form and goes back to the next item
554
     *
555
     * @param array The form data
556
     * @param Form The form object
557
     */
558
    public function doSaveAndNext($data, $form)
559
    {
560
        $record = $this->owner->record;
561
        $result = $this->owner->doSave($data, $form);
0 ignored issues
show
Unused Code introduced by
The assignment to $result is dead and can be removed.
Loading history...
562
        // Redirect after save
563
        $controller = $this->getToplevelController();
564
        $controller->getResponse()->addHeader("X-Pjax", "Content");
565
566
        $getNextRecordID = $this->getCustomNextRecordID($record);
0 ignored issues
show
Bug introduced by
It seems like $record can also be of type null; however, parameter $record of LeKoala\CmsActions\Actio...getCustomNextRecordID() does only seem to accept SilverStripe\ORM\DataObject, 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

566
        $getNextRecordID = $this->getCustomNextRecordID(/** @scrutinizer ignore-type */ $record);
Loading history...
567
        $class = get_class($record);
0 ignored issues
show
Bug introduced by
It seems like $record can also be of type null; however, parameter $object of get_class() does only seem to accept object, 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

567
        $class = get_class(/** @scrutinizer ignore-type */ $record);
Loading history...
568
        $next = $class::get()->byID($getNextRecordID);
569
570
        $link = $this->owner->getEditLink($getNextRecordID);
571
572
        // Link to a specific tab if set, see cms-actions.js
573
        if ($next && !empty($data['_activetab'])) {
574
            $link .= '#' . $data['_activetab'];
575
        }
576
        return $controller->redirect($link);
577
    }
578
579
    /**
580
     * Saves the form and goes to the previous item
581
     *
582
     * @param array The form data
583
     * @param Form The form object
584
     */
585
    public function doSaveAndPrev($data, $form)
586
    {
587
        $record = $this->owner->record;
588
        $result = $this->owner->doSave($data, $form);
0 ignored issues
show
Unused Code introduced by
The assignment to $result is dead and can be removed.
Loading history...
589
        // Redirect after save
590
        $controller = $this->getToplevelController();
591
        $controller->getResponse()->addHeader("X-Pjax", "Content");
592
593
        $getPreviousRecordID = $this->getCustomPreviousRecordID($record);
0 ignored issues
show
Bug introduced by
It seems like $record can also be of type null; however, parameter $record of LeKoala\CmsActions\Actio...ustomPreviousRecordID() does only seem to accept SilverStripe\ORM\DataObject, 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

593
        $getPreviousRecordID = $this->getCustomPreviousRecordID(/** @scrutinizer ignore-type */ $record);
Loading history...
594
        $class = get_class($record);
0 ignored issues
show
Bug introduced by
It seems like $record can also be of type null; however, parameter $object of get_class() does only seem to accept object, 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

594
        $class = get_class(/** @scrutinizer ignore-type */ $record);
Loading history...
595
        $prev = $class::get()->byID($getPreviousRecordID);
596
597
        $link = $this->owner->getEditLink($getPreviousRecordID);
598
599
        // Link to a specific tab if set, see cms-actions.js
600
        if ($prev && !empty($data['_activetab'])) {
601
            $link .= '#' . $data['_activetab'];
602
        }
603
        return $controller->redirect($link);
604
    }
605
606
    /**
607
     * Gets the top level controller.
608
     *
609
     * @return Controller
610
     * @todo  This had to be directly copied from {@link GridFieldDetailForm_ItemRequest}
611
     * because it is a protected method and not visible to a decorator!
612
     */
613
    protected function getToplevelController()
614
    {
615
        if ($this->owner instanceof LeftAndMain) {
616
            return $this->owner;
617
        }
618
        if (!$this->owner->hasMethod("getController")) {
619
            return Controller::curr();
620
        }
621
        $c = $this->owner->getController();
622
        while ($c && $c instanceof GridFieldDetailForm_ItemRequest) {
623
            $c = $c->getController();
624
        }
625
        return $c;
626
    }
627
628
    /**
629
     * Gets the back link
630
     *
631
     * @return string
632
     * @todo This had to be directly copied from {@link GridFieldDetailForm_ItemRequest}
633
     * because it is a protected method and not visible to a decorator!
634
     */
635
    public function getBackLink()
636
    {
637
        // TODO Coupling with CMS
638
        $backlink = '';
639
        $toplevelController = $this->getToplevelController();
640
        if ($toplevelController && $toplevelController instanceof LeftAndMain) {
641
            if ($toplevelController->hasMethod('Backlink')) {
642
                $backlink = $toplevelController->Backlink();
643
            } elseif ($this->owner->getController()->hasMethod('Breadcrumbs')) {
644
                $parents = $this->owner->getController()->Breadcrumbs(false)->items;
645
                $backlink = array_pop($parents)->Link;
646
            }
647
        }
648
        if (!$backlink) {
649
            $backlink = $toplevelController->Link();
650
        }
651
        return $backlink;
652
    }
653
654
    /**
655
     * Response object for this request after a successful save
656
     *
657
     * @param bool $isNewRecord True if this record was just created
658
     * @param DataObject $record
659
     * @return HTTPResponse|DBHTMLText|string
660
     * @todo  This had to be directly copied from {@link GridFieldDetailForm_ItemRequest}
661
     * because it is a protected method and not visible to a decorator!
662
     */
663
    protected function redirectAfterAction($isNewRecord, $record = null)
664
    {
665
        $controller = $this->getToplevelController();
666
667
        if ($controller instanceof LeftAndMain) {
668
            // CMSMain => redirect to show
669
            if ($this->owner->hasMethod("LinkPageEdit")) {
670
                return $controller->redirect($this->owner->LinkPageEdit($record->ID));
671
            }
672
            // Fallback
673
            return $controller->redirect($this->owner->Link());
674
        }
675
676
        if ($isNewRecord) {
677
            return $controller->redirect($this->owner->Link());
678
        } elseif ($this->owner->gridField && $this->owner->gridField->getList()->byID($this->owner->record->ID)) {
0 ignored issues
show
Bug introduced by
The method byID() does not exist on SilverStripe\ORM\SS_List. It seems like you code against a sub-type of said class. However, the method does not exist in SilverStripe\ORM\Sortable or SilverStripe\ORM\Limitable. Are you sure you never get one of those? ( Ignorable by Annotation )

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

678
        } elseif ($this->owner->gridField && $this->owner->gridField->getList()->/** @scrutinizer ignore-call */ byID($this->owner->record->ID)) {
Loading history...
679
            // Return new view, as we can't do a "virtual redirect" via the CMS Ajax
680
            // to the same URL (it assumes that its content is already current, and doesn't reload)
681
            return $this->owner->edit($controller->getRequest());
682
        } else {
683
            // Changes to the record properties might've excluded the record from
684
            // a filtered list, so return back to the main view if it can't be found
685
            $url = $controller->getRequest()->getURL();
686
            $action = $controller->getAction();
687
            $noActionURL = $url;
688
            if ($action) {
689
                $noActionURL = $controller->removeAction($url, $action);
690
            }
691
            $controller->getRequest()->addHeader('X-Pjax', 'Content');
692
            return $controller->redirect($noActionURL, 302);
693
        }
694
    }
695
}
696