diff --git a/src/Forms/GridField/GridField.php b/src/Forms/GridField/GridField.php index c26169456..8bb84a3cd 100644 --- a/src/Forms/GridField/GridField.php +++ b/src/Forms/GridField/GridField.php @@ -4,10 +4,13 @@ namespace SilverStripe\Forms\GridField; use InvalidArgumentException; use LogicException; +use SilverStripe\Control\Controller; use SilverStripe\Control\HasRequestHandler; +use SilverStripe\Control\HTTP; use SilverStripe\Control\HTTPRequest; use SilverStripe\Control\HTTPResponse; use SilverStripe\Control\HTTPResponse_Exception; +use SilverStripe\Control\NullHTTPRequest; use SilverStripe\Control\RequestHandler; use SilverStripe\Core\Convert; use SilverStripe\Core\Injector\Injector; @@ -45,6 +48,8 @@ use SilverStripe\View\HTML; */ class GridField extends FormField { + use GridFieldStateAware; + /** * @var array */ @@ -435,6 +440,8 @@ class GridField extends FormField { $this->state = new GridState($this); + $this->addStateFromRequest(); + $data = $this->state->getData(); foreach ($this->getComponents() as $item) { @@ -444,6 +451,56 @@ class GridField extends FormField } } + /** + * Adds state for this gridfield from the request variables. + * + * If there is state already set on this GridField, that takes precedent + * over state from the request. + */ + private function addStateFromRequest(): void + { + $request = $this->getRequest(); + if (($request instanceof NullHTTPRequest) && Controller::has_curr()) { + $request = Controller::curr()->getRequest(); + } + + $stateStr = $this->getStateManager()->getStateFromRequest($this, $request); + if ($stateStr) { + $oldState = $this->getState(false); + // Create a dummy state so that we can merge the current state with the request state. + $newState = new GridState($this, $stateStr); + // Put the current state on top of the request state. + $newState->setValue($oldState->Value()); + $this->state = $newState; + } + } + + /** + * Add GET and POST parameters pertaining to other gridfield's state to the URL. + * Also add this gridfield's own state to the URL. + */ + public function addAllStateToUrl(string $link): string + { + $request = $this->getRequest(); + if ($request->param('Action')) { + $requestVars = $request->requestVars(); + $params = []; + foreach ($requestVars as $key => $val) { + // Get gridfield states that are for other gridfields + if (stripos($key, 'gridState') === 0 + && $key !== $this->getStateManager()->getStateKey($this) + ) { + $params[$key] = $val; + } + } + foreach ($params as $key => $val) { + $link = HTTP::setGetVar($key, $val, $link); + } + } + + return $this->getStateManager()->addStateToURL($this, $link); + } + /** * Returns the whole gridfield rendered with all the attached components. * diff --git a/src/Forms/GridField/GridFieldDetailForm_ItemRequest.php b/src/Forms/GridField/GridFieldDetailForm_ItemRequest.php index 02b96b8be..1bc42369b 100644 --- a/src/Forms/GridField/GridFieldDetailForm_ItemRequest.php +++ b/src/Forms/GridField/GridFieldDetailForm_ItemRequest.php @@ -481,7 +481,7 @@ class GridFieldDetailForm_ItemRequest extends RequestHandler $backlink = $toplevelController->Link(); } - return $backlink; + return $this->gridField->addAllStateToUrl($backlink); } /** @@ -817,6 +817,12 @@ class GridFieldDetailForm_ItemRequest extends RequestHandler ])); } + foreach ($items as $item) { + if ($item->Link) { + $item->Link = $this->gridField->addAllStateToUrl($item->Link); + } + } + $this->extend('updateBreadcrumbs', $items); return $items; } diff --git a/src/Forms/GridField/GridFieldEditButton.php b/src/Forms/GridField/GridFieldEditButton.php index fa81af45c..5c52c45d8 100644 --- a/src/Forms/GridField/GridFieldEditButton.php +++ b/src/Forms/GridField/GridFieldEditButton.php @@ -61,6 +61,7 @@ class GridFieldEditButton extends AbstractGridFieldComponent implements GridFiel /** * @inheritdoc + * @param bool $addState DEPRECATED: Should be removed in major release */ public function getUrl($gridField, $record, $columnName, $addState = true) { @@ -70,11 +71,7 @@ class GridFieldEditButton extends AbstractGridFieldComponent implements GridFiel 'edit' ); - if ($addState) { - $link = $this->getStateManager()->addStateToURL($gridField, $link); - } - - return $link; + return $gridField->addAllStateToUrl($link, $addState); } /** diff --git a/src/Forms/GridField/GridFieldViewButton.php b/src/Forms/GridField/GridFieldViewButton.php index ca8e45f1f..ea4129eb2 100644 --- a/src/Forms/GridField/GridFieldViewButton.php +++ b/src/Forms/GridField/GridFieldViewButton.php @@ -44,7 +44,8 @@ class GridFieldViewButton extends AbstractGridFieldComponent implements GridFiel */ public function getUrl($gridField, $record, $columnName) { - return Controller::join_links($gridField->Link('item'), $record->ID, 'view'); + $link = Controller::join_links($gridField->Link('item'), $record->ID, 'view'); + return $gridField->addAllStateToUrl($link); } public function augmentColumns($field, &$columns) diff --git a/tests/php/Forms/GridField/GridFieldDetailFormTest.php b/tests/php/Forms/GridField/GridFieldDetailFormTest.php index 318711e67..37027c628 100644 --- a/tests/php/Forms/GridField/GridFieldDetailFormTest.php +++ b/tests/php/Forms/GridField/GridFieldDetailFormTest.php @@ -341,10 +341,11 @@ class GridFieldDetailFormTest extends FunctionalTest ); $this->assertEquals( sprintf( - 'GridFieldDetailFormTest_GroupController/Form/field/testfield/item/%d/ItemEditForm/field/People' - . '/item/%d/edit', + '/GridFieldDetailFormTest_GroupController/Form/field/testfield/item/%d/ItemEditForm/field/People' + . '/item/%d/edit%s', $group->ID, - $person->ID + $person->ID, + '?gridState-People-1=%7B%22GridFieldAddRelation%22%3Anull%7D' ), (string)$personEditLink[0]['href'] ); @@ -359,11 +360,12 @@ class GridFieldDetailFormTest extends FunctionalTest ); $this->assertEquals( sprintf( - 'GridFieldDetailFormTest_GroupController/Form/field/testfield/item/%d/ItemEditForm/field/People' - . '/item/%d/ItemEditForm/field/Categories/item/%d/edit', + '/GridFieldDetailFormTest_GroupController/Form/field/testfield/item/%d/ItemEditForm/field/People' + . '/item/%d/ItemEditForm/field/Categories/item/%d/edit%s', $group->ID, $person->ID, - $category->ID + $category->ID, + '?gridState-Categories-2=%7B%22GridFieldAddRelation%22%3Anull%7D' ), (string)$categoryEditLink[0]['href'] ); diff --git a/tests/php/Forms/GridField/GridFieldTest.php b/tests/php/Forms/GridField/GridFieldTest.php index 1f70e55c1..e8694df32 100644 --- a/tests/php/Forms/GridField/GridFieldTest.php +++ b/tests/php/Forms/GridField/GridFieldTest.php @@ -4,6 +4,8 @@ namespace SilverStripe\Forms\Tests\GridField; use InvalidArgumentException; use LogicException; +use SilverStripe\Control\Controller; +use SilverStripe\Control\HTTPRequest; use SilverStripe\Dev\CSSContentParser; use SilverStripe\Dev\SapphireTest; use SilverStripe\Forms\FieldList; @@ -659,4 +661,69 @@ class GridFieldTest extends SapphireTest $gridfieldOutput = $gridField->FieldHolder(); $this->assertStringNotContainsString('

', $gridfieldOutput); } + + public function testAddRequestToURL() + { + $gridField = new GridField('testfield', 'testfield'); + $link = Controller::join_links('class-name', 'item', '1'); + + // The actual URL path here is arbitrary + $request = new HTTPRequest( + 'POST', + 'admin/gridfield', + [ + 'gridState-Test-0' => [ + 'State' => [ + 'Column' => 'Name' + ], + ] + ], + [ + 'action_gridFieldAlterAction?StateID=1', + 'ActionState' => json_encode([ + 'grid' => $gridField->getName(), + 'actionName' => 'edit', + 'args' => [], + ]), + 'gridState-Test-1' => [ + 'State' => [ + 'Column' => 'Name' + ], + ] + ] + ); + + $request->setRouteParams(['Action' => 'edit']); + $gridField->setRequest($request); + + $this->assertEquals( + $gridField->addAllStateToUrl($link), + '/class-name/item/1?gridState-Test-0%5BState%5D%5BColumn%5D=Name&gridState-Test-1%5BState%5D%5BColumn%5D=Name' + ); + // The actual URL path here is arbitrary + $request = new HTTPRequest( + 'GET', + 'admin/gridfield', + [ + 'action_gridFieldAlterAction?StateID=1', + 'ActionState' => json_encode([ + 'grid' => $gridField->getName(), + 'actionName' => 'edit', + 'args' => [], + ]), + 'gridState-Test' => [ + 'State' => [ + 'Column' => 'Name' + ], + ] + ] + ); + $request->setRouteParams(['Action' => 'edit']); + $gridField->setRequest($request); + + $this->assertEquals( + $gridField->addAllStateToUrl($link), + '/class-name/item/1?gridState-Test%5BState%5D%5BColumn%5D=Name' + ); + } }