Passed
Pull Request — master (#9)
by Sergey
02:20
created

ActionsGridFieldItemRequest::updateItemEditForm()   C

Complexity

Conditions 10
Paths 258

Size

Total Lines 69
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 1 Features 0
Metric Value
cc 10
eloc 30
c 2
b 1
f 0
nc 258
nop 1
dl 0
loc 69
rs 6.1083

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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
        // Push our actions that are otherwise ignored by SilverStripe
119
        foreach ($CMSActions as $action) {
120
            $actions->push($action);
121
        }
122
123
        // We create a Drop-Up menu afterwards because it may already exist in the $CMSActions
124
        // and we don't want to duplicate it
125
        $this->processDropUpMenu($actions);
126
127
        // Add extension hook
128
        $record->extend('onBeforeUpdateCMSActions', $actions);
129
130
        $ActionMenus = $actions->fieldByName('ActionMenus');
131
        // Re-insert ActionMenus to make sure they always follow the buttons
132
        if ($ActionMenus) {
133
            $actions->remove($ActionMenus);
134
            $actions->push($ActionMenus);
135
        }
136
137
        // We have a 4.4 setup, before that there was no RightGroup
138
        $RightGroup = $actions->fieldByName('RightGroup');
139
140
        // Insert again to make sure our actions are properly placed after apply changes
141
        if ($RightGroup) {
142
            $actions->remove($RightGroup);
143
            $actions->push($RightGroup);
144
        }
145
146
        if (self::config()->enable_save_close) {
147
            $this->addSaveAndClose($actions, $record);
148
        }
149
150
        if (self::config()->enable_save_prev_next) {
151
            $this->addSaveNextAndPrevious($actions, $record);
152
        }
153
154
        if (self::config()->enable_delete_right) {
155
            $this->moveCancelAndDelete($actions, $record);
156
        }
157
158
        // Add extension hook
159
        $record->extend('onAfterUpdateCMSActions', $actions);
160
    }
161
162
163
    /**
164
     * Collect all Drop-Up actions into a menu.
165
     * @param FieldList $actions
166
     * @return void
167
     */
168
    protected function processDropUpMenu($actions)
169
    {
170
        // The Drop-up container may already exist
171
        $dropUpContainer = $actions->fieldByName('ActionMenus.MoreOptions');
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $dropUpContainer is correct as $actions->fieldByName('ActionMenus.MoreOptions') 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...
172
        foreach ($actions as $action) {
173
            if ($action->hasMethod('getDropUp') && $action->getDropUp()) {
174
                if (!$dropUpContainer) {
175
                    $dropUpContainer = $this->createDropUpContainer($actions);
176
                }
177
                $action->getContainerFieldList()->removeByName($action->getName());
178
                $dropUpContainer->push($action);
179
            }
180
        }
181
    }
182
183
    /**
184
     * Prepares a Drop-Up menu
185
     * @param FieldList $actions
186
     * @return Tab
187
     */
188
    protected function createDropUpContainer($actions)
189
    {
190
        $rootTabSet = new TabSet('ActionMenus');
191
        $dropUpContainer = new Tab(
192
            'MoreOptions',
193
            _t(__CLASS__ . '.MoreOptions', 'More options', 'Expands a view for more buttons')
194
        );
195
        $dropUpContainer->addExtraClass('popover-actions-simulate');
196
        $rootTabSet->push($dropUpContainer);
197
        $rootTabSet->addExtraClass('ss-ui-action-tabset action-menus noborder');
198
199
        $actions->insertBefore('RightGroup', $rootTabSet);
200
        return $dropUpContainer;
201
    }
202
203
    /**
204
     * @param FieldList $actions
205
     * @param DataObject $record
206
     * @return void
207
     */
208
    public function moveCancelAndDelete(FieldList $actions, DataObject $record)
209
    {
210
        // We have a 4.4 setup, before that there was no RightGroup
211
        $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...
212
213
        // Move delete at the end
214
        $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...
215
        if ($deleteAction) {
0 ignored issues
show
introduced by
$deleteAction is of type null, thus it always evaluated to false.
Loading history...
216
            // Move at the end of the stack
217
            $actions->remove($deleteAction);
218
            $actions->push($deleteAction);
219
220
            if ($RightGroup) {
221
                // Stack position is enough to have it on the left
222
            } else {
223
                // Only necessary pre 4.4
224
                $deleteAction->addExtraClass('align-right');
225
            }
226
            // Set custom title
227
            if ($record->hasMethod('getDeleteButtonTitle')) {
228
                $deleteAction->setTitle($record->getDeleteButtonTitle());
229
            }
230
        }
231
        // Move cancel at the end
232
        $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...
233
        if ($cancelButton) {
0 ignored issues
show
introduced by
$cancelButton is of type null, thus it always evaluated to false.
Loading history...
234
            // Move at the end of the stack
235
            $actions->remove($cancelButton);
236
            $actions->push($cancelButton);
237
            if ($RightGroup) {
238
                // Stack position is enough to have it on the left
239
            } else {
240
                // Only necessary pre 4.4
241
                $cancelButton->addExtraClass('align-right');
242
            }
243
            // Set custom titlte
244
            if ($record->hasMethod('getCancelButtonTitle')) {
245
                $cancelButton->setTitle($record->getCancelButtonTitle());
246
            }
247
        }
248
    }
249
250
    /**
251
     * @param DataObject $record
252
     * @return int
253
     */
254
    public function getCustomPreviousRecordID(DataObject $record)
255
    {
256
        if ($record->hasMethod('PrevRecord')) {
257
            return $record->PrevRecord()->ID ?? 0;
258
        }
259
        return $this->owner->getPreviousRecordID();
260
    }
261
262
    /**
263
     * @param DataObject $record
264
     * @return int
265
     */
266
    public function getCustomNextRecordID(DataObject $record)
267
    {
268
        if ($record->hasMethod('NextRecord')) {
269
            return $record->NextRecord()->ID ?? 0;
270
        }
271
        return $this->owner->getNextRecordID();
272
    }
273
274
    /**
275
     * @param FieldList $actions
276
     * @param DataObject $record
277
     * @return void
278
     */
279
    public function addSaveNextAndPrevious(FieldList $actions, DataObject $record)
280
    {
281
        if (!$record->canEdit()) {
282
            return;
283
        }
284
        if (!$record->ID) {
285
            return;
286
        }
287
288
        $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...
289
290
        // If it doesn't exist, push to default group
291
        if (!$MajorActions) {
0 ignored issues
show
introduced by
$MajorActions is of type null, thus it always evaluated to false.
Loading history...
292
            $MajorActions = $actions;
293
        }
294
295
        // TODO: check why with paginator, after the first page, getPreviousRecordID/getNextRecordID tend to not work properly
296
        $getPreviousRecordID = $this->getCustomPreviousRecordID($record);
297
        $getNextRecordID = $this->getCustomNextRecordID($record);
298
299
        // Coupling for HasPrevNextUtils
300
        if (Controller::has_curr()) {
301
            $request =  Controller::curr()->getRequest();
302
            $routeParams = $request->routeParams();
303
            $routeParams['PreviousRecordID'] = $getPreviousRecordID;
304
            $routeParams['NextRecordID'] = $getNextRecordID;
305
            $request->setRouteParams($routeParams);
306
        }
307
308
        if ($getPreviousRecordID) {
309
            $doSaveAndPrev = new FormAction('doSaveAndPrev', _t('ActionsGridFieldItemRequest.SAVEANDPREVIOUS', 'Save and Previous'));
310
            $doSaveAndPrev->addExtraClass($this->getBtnClassForRecord($record));
311
            $doSaveAndPrev->addExtraClass('font-icon-angle-double-left');
312
            $doSaveAndPrev->setUseButtonTag(true);
313
            $MajorActions->push($doSaveAndPrev);
314
        }
315
        if ($getNextRecordID) {
316
            $doSaveAndNext = new FormAction('doSaveAndNext', _t('ActionsGridFieldItemRequest.SAVEANDNEXT', 'Save and Next'));
317
            $doSaveAndNext->addExtraClass($this->getBtnClassForRecord($record));
318
            $doSaveAndNext->addExtraClass('font-icon-angle-double-right');
319
            $doSaveAndNext->setUseButtonTag(true);
320
            $MajorActions->push($doSaveAndNext);
321
        }
322
    }
323
324
    /**
325
     * @param FieldList $actions
326
     * @param DataObject $record
327
     * @return void
328
     */
329
    public function addSaveAndClose(FieldList $actions, DataObject $record)
330
    {
331
        if (!$record->canEdit()) {
332
            return;
333
        }
334
        if (!$record->ID && !$record->canCreate()) {
335
            return;
336
        }
337
338
        $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...
339
340
        // If it doesn't exist, push to default group
341
        if (!$MajorActions) {
0 ignored issues
show
introduced by
$MajorActions is of type null, thus it always evaluated to false.
Loading history...
342
            $MajorActions = $actions;
343
        }
344
345
        if ($record->ID) {
346
            $label = _t('ActionsGridFieldItemRequest.SAVEANDCLOSE', 'Save and Close');
347
        } else {
348
            $label = _t('ActionsGridFieldItemRequest.CREATEANDCLOSE', 'Create and Close');
349
        }
350
        $saveAndClose = new FormAction('doSaveAndClose', $label);
351
        $saveAndClose->addExtraClass($this->getBtnClassForRecord($record));
352
        $saveAndClose->setAttribute('data-text-alternate', $label);
353
        if ($record->ID) {
354
            $saveAndClose->setAttribute('data-btn-alternate-add', 'btn-primary');
355
            $saveAndClose->setAttribute('data-btn-alternate-remove', 'btn-outline-primary');
356
        }
357
        $saveAndClose->addExtraClass('font-icon-level-up');
358
        $saveAndClose->setUseButtonTag(true);
359
        $MajorActions->push($saveAndClose);
360
    }
361
362
    /**
363
     * New and existing records have different classes
364
     *
365
     * @param DataObject $record
366
     * @return string
367
     */
368
    protected function getBtnClassForRecord(DataObject $record)
369
    {
370
        if ($record->ID) {
371
            return 'btn-outline-primary';
372
        }
373
        return 'btn-primary';
374
    }
375
376
    /**
377
     * Forward a given action to a DataObject
378
     *
379
     * Action must be declared in getCMSActions to be called
380
     *
381
     * @param string $action
382
     * @param array $data
383
     * @param Form $form
384
     * @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...
385
     */
386
    protected function forwardActionToRecord($action, $data = [], $form = null)
387
    {
388
        $controller = $this->getToplevelController();
389
390
        // We have an item request
391
        $record = null;
392
        if ($this->owner instanceof GridFieldDetailForm_ItemRequest) {
393
            $record = $this->owner->record;
394
        } elseif ($controller instanceof LeftAndMain) {
395
            if (empty($data['ClassName']) || empty($data['ID'])) {
396
                throw new Exception("Submitted data does not contain and ID and a ClassName");
397
            }
398
            $record = DataObject::get_by_id($data['ClassName'], $data['ID']);
399
        } elseif ($controller->hasMethod("getRecord")) {
400
            $record = $controller->getRecord();
401
        }
402
403
        if (!$record) {
404
            throw new Exception("No record to handle the action $action on " . get_class($controller));
405
        }
406
        $definedActions = $record->getCMSActions();
407
        // Check if the action is indeed available
408
        $clickedAction = null;
409
        if (!empty($definedActions)) {
410
            foreach ($definedActions as $definedAction) {
411
                $definedActionName = $definedAction->getName();
412
                if ($definedAction->hasMethod('actionName')) {
413
                    $definedActionName = $definedAction->actionName();
414
                }
415
                if ($definedActionName == $action) {
416
                    $clickedAction = $definedAction;
417
                }
418
            }
419
        }
420
        if (!$clickedAction) {
421
            $class = get_class($record);
422
            $availableActions = implode(',', $this->getAvailableActions($definedActions));
423
            if (!$availableActions) {
424
                $availableActions = "(no available actions, please check getCMSActions)";
425
            }
426
            return $this->owner->httpError(403, 'Action not available on ' . $class . '. It must be one of : ' . $availableActions);
427
        }
428
        $message = null;
429
        $error = false;
430
431
        // Check record BEFORE the action
432
        // It can be deleted by the action and it will return to the list
433
        $isNewRecord = $record->ID == 0;
434
435
        try {
436
            $result = $record->$action($data, $form, $controller);
437
438
            // We have a response
439
            if ($result && $result instanceof HTTPResponse) {
440
                return $result;
441
            }
442
443
            if ($result === false) {
444
                // Result returned an error (false)
445
                $error = true;
446
                $message = _t(
447
                    'ActionsGridFieldItemRequest.FAILED',
448
                    'Action {action} failed on {name}',
449
                    array(
450
                        'action' => $clickedAction->getTitle(),
451
                        'name' => $record->i18n_singular_name(),
452
                    )
453
                );
454
            } elseif (is_string($result)) {
455
                // Result is a message
456
                $message = $result;
457
            }
458
        } catch (Exception $ex) {
459
            $error = true;
460
            $message = $ex->getMessage();
461
        }
462
463
        // Build default message
464
        if (!$message) {
465
            $message = _t(
466
                'ActionsGridFieldItemRequest.DONE',
467
                'Action {action} was done on {name}',
468
                array(
469
                    'action' => $clickedAction->getTitle(),
470
                    'name' => $record->i18n_singular_name(),
471
                )
472
            );
473
        }
474
        $status = 'good';
475
        if ($error) {
476
            $status = 'bad';
477
        }
478
479
        // Progressive actions return array with json data
480
        if (method_exists($clickedAction, 'getProgressive') && $clickedAction->getProgressive()) {
481
            $response = $controller->getResponse();
482
            $response->addHeader('Content-Type', 'application/json');
483
            if ($result) {
484
                $response->setBody(json_encode($result));
485
            }
486
            return $response;
487
        }
488
489
        // We don't have a form, simply return the result
490
        if (!$form) {
491
            if ($error) {
492
                return $this->owner->httpError(403, $message);
493
            }
494
            return $message;
495
        }
496
        if (Director::is_ajax()) {
497
            $controller = $this->getToplevelController();
498
            $controller->getResponse()->addHeader('X-Status', rawurlencode($message));
499
            if (method_exists($clickedAction, 'getShouldRefresh') && $clickedAction->getShouldRefresh()) {
500
                $controller->getResponse()->addHeader('X-Reload', "true");
501
            }
502
            // 4xx status makes a red box
503
            if ($error) {
504
                $controller->getResponse()->setStatusCode(400);
505
            }
506
        } else {
507
            $form->sessionMessage($message, $status, ValidationResult::CAST_HTML);
508
        }
509
        // Redirect after action
510
        return $this->redirectAfterAction($isNewRecord, $record);
511
    }
512
513
    /**
514
     * Handles custom links
515
     *
516
     * Use CustomLink with default behaviour to trigger this
517
     *
518
     * See:
519
     * DefaultLink::getModelLink
520
     * GridFieldCustomLink::getLink
521
     *
522
     * @param HTTPRequest $request
523
     * @return HTTPResponse|DBHTMLText|string
524
     */
525
    public function doCustomLink(HTTPRequest $request)
526
    {
527
        $action = $request->getVar('CustomLink');
528
        return $this->forwardActionToRecord($action);
529
    }
530
531
    /**
532
     * Handles custom actions
533
     *
534
     * Use CustomAction class to trigger this
535
     *
536
     * Nested actions are submitted like this
537
     * [action_doCustomAction] => Array
538
     * (
539
     *   [doTestAction] => 1
540
     * )
541
     *
542
     * @param array The form data
543
     * @param Form The form object
544
     * @return HTTPResponse|DBHTMLText|string
545
     */
546
    public function doCustomAction($data, $form)
547
    {
548
        $action = key($data['action_doCustomAction']);
549
        return $this->forwardActionToRecord($action, $data, $form);
550
    }
551
552
    /**
553
     * Saves the form and goes back to list view
554
     *
555
     * @param array The form data
556
     * @param Form The form object
557
     */
558
    public function doSaveAndClose($data, $form)
559
    {
560
        $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...
561
        // Redirect after save
562
        $controller = $this->getToplevelController();
563
        $controller->getResponse()->addHeader("X-Pjax", "Content");
564
        return $controller->redirect($this->getBackLink());
565
    }
566
567
    /**
568
     * Saves the form and goes back to the next item
569
     *
570
     * @param array The form data
571
     * @param Form The form object
572
     */
573
    public function doSaveAndNext($data, $form)
574
    {
575
        $record = $this->owner->record;
576
        $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...
577
        // Redirect after save
578
        $controller = $this->getToplevelController();
579
        $controller->getResponse()->addHeader("X-Pjax", "Content");
580
581
        $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

581
        $getNextRecordID = $this->getCustomNextRecordID(/** @scrutinizer ignore-type */ $record);
Loading history...
582
        $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

582
        $class = get_class(/** @scrutinizer ignore-type */ $record);
Loading history...
583
        $next = $class::get()->byID($getNextRecordID);
584
585
        $link = $this->owner->getEditLink($getNextRecordID);
586
587
        // Link to a specific tab if set, see cms-actions.js
588
        if ($next && !empty($data['_activetab'])) {
589
            $link .= '#' . $data['_activetab'];
590
        }
591
        return $controller->redirect($link);
592
    }
593
594
    /**
595
     * Saves the form and goes to the previous item
596
     *
597
     * @param array The form data
598
     * @param Form The form object
599
     */
600
    public function doSaveAndPrev($data, $form)
601
    {
602
        $record = $this->owner->record;
603
        $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...
604
        // Redirect after save
605
        $controller = $this->getToplevelController();
606
        $controller->getResponse()->addHeader("X-Pjax", "Content");
607
608
        $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

608
        $getPreviousRecordID = $this->getCustomPreviousRecordID(/** @scrutinizer ignore-type */ $record);
Loading history...
609
        $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

609
        $class = get_class(/** @scrutinizer ignore-type */ $record);
Loading history...
610
        $prev = $class::get()->byID($getPreviousRecordID);
611
612
        $link = $this->owner->getEditLink($getPreviousRecordID);
613
614
        // Link to a specific tab if set, see cms-actions.js
615
        if ($prev && !empty($data['_activetab'])) {
616
            $link .= '#' . $data['_activetab'];
617
        }
618
        return $controller->redirect($link);
619
    }
620
621
    /**
622
     * Gets the top level controller.
623
     *
624
     * @return Controller
625
     * @todo  This had to be directly copied from {@link GridFieldDetailForm_ItemRequest}
626
     * because it is a protected method and not visible to a decorator!
627
     */
628
    protected function getToplevelController()
629
    {
630
        if ($this->owner instanceof LeftAndMain) {
631
            return $this->owner;
632
        }
633
        if (!$this->owner->hasMethod("getController")) {
634
            return Controller::curr();
635
        }
636
        $c = $this->owner->getController();
637
        while ($c && $c instanceof GridFieldDetailForm_ItemRequest) {
638
            $c = $c->getController();
639
        }
640
        return $c;
641
    }
642
643
    /**
644
     * Gets the back link
645
     *
646
     * @return string
647
     * @todo This had to be directly copied from {@link GridFieldDetailForm_ItemRequest}
648
     * because it is a protected method and not visible to a decorator!
649
     */
650
    public function getBackLink()
651
    {
652
        // TODO Coupling with CMS
653
        $backlink = '';
654
        $toplevelController = $this->getToplevelController();
655
        if ($toplevelController && $toplevelController instanceof LeftAndMain) {
656
            if ($toplevelController->hasMethod('Backlink')) {
657
                $backlink = $toplevelController->Backlink();
658
            } elseif ($this->owner->getController()->hasMethod('Breadcrumbs')) {
659
                $parents = $this->owner->getController()->Breadcrumbs(false)->items;
660
                $backlink = array_pop($parents)->Link;
661
            }
662
        }
663
        if (!$backlink) {
664
            $backlink = $toplevelController->Link();
665
        }
666
        return $backlink;
667
    }
668
669
    /**
670
     * Response object for this request after a successful save
671
     *
672
     * @param bool $isNewRecord True if this record was just created
673
     * @param DataObject $record
674
     * @return HTTPResponse|DBHTMLText|string
675
     * @todo  This had to be directly copied from {@link GridFieldDetailForm_ItemRequest}
676
     * because it is a protected method and not visible to a decorator!
677
     */
678
    protected function redirectAfterAction($isNewRecord, $record = null)
679
    {
680
        $controller = $this->getToplevelController();
681
682
        if ($controller instanceof LeftAndMain) {
683
            // CMSMain => redirect to show
684
            if ($this->owner->hasMethod("LinkPageEdit")) {
685
                return $controller->redirect($this->owner->LinkPageEdit($record->ID));
686
            }
687
            // Fallback
688
            return $controller->redirect($this->owner->Link());
689
        }
690
691
        if ($isNewRecord) {
692
            return $controller->redirect($this->owner->Link());
693
        } 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

693
        } elseif ($this->owner->gridField && $this->owner->gridField->getList()->/** @scrutinizer ignore-call */ byID($this->owner->record->ID)) {
Loading history...
694
            // Return new view, as we can't do a "virtual redirect" via the CMS Ajax
695
            // to the same URL (it assumes that its content is already current, and doesn't reload)
696
            return $this->owner->edit($controller->getRequest());
697
        } else {
698
            // Changes to the record properties might've excluded the record from
699
            // a filtered list, so return back to the main view if it can't be found
700
            $url = $controller->getRequest()->getURL();
701
            $action = $controller->getAction();
702
            $noActionURL = $url;
703
            if ($action) {
704
                $noActionURL = $controller->removeAction($url, $action);
705
            }
706
            $controller->getRequest()->addHeader('X-Pjax', 'Content');
707
            return $controller->redirect($noActionURL, 302);
708
        }
709
    }
710
}
711