Merge pull request #10331 from creative-commoners/pulls/4/gridfield-keep-state

ENH Restore gridfield state from get vars (POC)
This commit is contained in:
Guy Sartorelli 2022-07-29 11:33:19 +12:00 committed by GitHub
commit c7504aa337
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 143 additions and 13 deletions

View File

@ -4,10 +4,13 @@ namespace SilverStripe\Forms\GridField;
use InvalidArgumentException; use InvalidArgumentException;
use LogicException; use LogicException;
use SilverStripe\Control\Controller;
use SilverStripe\Control\HasRequestHandler; use SilverStripe\Control\HasRequestHandler;
use SilverStripe\Control\HTTP;
use SilverStripe\Control\HTTPRequest; use SilverStripe\Control\HTTPRequest;
use SilverStripe\Control\HTTPResponse; use SilverStripe\Control\HTTPResponse;
use SilverStripe\Control\HTTPResponse_Exception; use SilverStripe\Control\HTTPResponse_Exception;
use SilverStripe\Control\NullHTTPRequest;
use SilverStripe\Control\RequestHandler; use SilverStripe\Control\RequestHandler;
use SilverStripe\Core\Convert; use SilverStripe\Core\Convert;
use SilverStripe\Core\Injector\Injector; use SilverStripe\Core\Injector\Injector;
@ -45,6 +48,8 @@ use SilverStripe\View\HTML;
*/ */
class GridField extends FormField class GridField extends FormField
{ {
use GridFieldStateAware;
/** /**
* @var array * @var array
*/ */
@ -435,6 +440,8 @@ class GridField extends FormField
{ {
$this->state = new GridState($this); $this->state = new GridState($this);
$this->addStateFromRequest();
$data = $this->state->getData(); $data = $this->state->getData();
foreach ($this->getComponents() as $item) { 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. * Returns the whole gridfield rendered with all the attached components.
* *

View File

@ -481,7 +481,7 @@ class GridFieldDetailForm_ItemRequest extends RequestHandler
$backlink = $toplevelController->Link(); $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); $this->extend('updateBreadcrumbs', $items);
return $items; return $items;
} }

View File

@ -61,6 +61,7 @@ class GridFieldEditButton extends AbstractGridFieldComponent implements GridFiel
/** /**
* @inheritdoc * @inheritdoc
* @param bool $addState DEPRECATED: Should be removed in major release
*/ */
public function getUrl($gridField, $record, $columnName, $addState = true) public function getUrl($gridField, $record, $columnName, $addState = true)
{ {
@ -70,11 +71,7 @@ class GridFieldEditButton extends AbstractGridFieldComponent implements GridFiel
'edit' 'edit'
); );
if ($addState) { return $gridField->addAllStateToUrl($link, $addState);
$link = $this->getStateManager()->addStateToURL($gridField, $link);
}
return $link;
} }
/** /**

View File

@ -44,7 +44,8 @@ class GridFieldViewButton extends AbstractGridFieldComponent implements GridFiel
*/ */
public function getUrl($gridField, $record, $columnName) 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) public function augmentColumns($field, &$columns)

View File

@ -341,10 +341,11 @@ class GridFieldDetailFormTest extends FunctionalTest
); );
$this->assertEquals( $this->assertEquals(
sprintf( sprintf(
'GridFieldDetailFormTest_GroupController/Form/field/testfield/item/%d/ItemEditForm/field/People' '/GridFieldDetailFormTest_GroupController/Form/field/testfield/item/%d/ItemEditForm/field/People'
. '/item/%d/edit', . '/item/%d/edit%s',
$group->ID, $group->ID,
$person->ID $person->ID,
'?gridState-People-1=%7B%22GridFieldAddRelation%22%3Anull%7D'
), ),
(string)$personEditLink[0]['href'] (string)$personEditLink[0]['href']
); );
@ -359,11 +360,12 @@ class GridFieldDetailFormTest extends FunctionalTest
); );
$this->assertEquals( $this->assertEquals(
sprintf( sprintf(
'GridFieldDetailFormTest_GroupController/Form/field/testfield/item/%d/ItemEditForm/field/People' '/GridFieldDetailFormTest_GroupController/Form/field/testfield/item/%d/ItemEditForm/field/People'
. '/item/%d/ItemEditForm/field/Categories/item/%d/edit', . '/item/%d/ItemEditForm/field/Categories/item/%d/edit%s',
$group->ID, $group->ID,
$person->ID, $person->ID,
$category->ID $category->ID,
'?gridState-Categories-2=%7B%22GridFieldAddRelation%22%3Anull%7D'
), ),
(string)$categoryEditLink[0]['href'] (string)$categoryEditLink[0]['href']
); );

View File

@ -4,6 +4,8 @@ namespace SilverStripe\Forms\Tests\GridField;
use InvalidArgumentException; use InvalidArgumentException;
use LogicException; use LogicException;
use SilverStripe\Control\Controller;
use SilverStripe\Control\HTTPRequest;
use SilverStripe\Dev\CSSContentParser; use SilverStripe\Dev\CSSContentParser;
use SilverStripe\Dev\SapphireTest; use SilverStripe\Dev\SapphireTest;
use SilverStripe\Forms\FieldList; use SilverStripe\Forms\FieldList;
@ -659,4 +661,69 @@ class GridFieldTest extends SapphireTest
$gridfieldOutput = $gridField->FieldHolder(); $gridfieldOutput = $gridField->FieldHolder();
$this->assertStringNotContainsString('<p class="message ' . ValidationResult::TYPE_ERROR . '">', $gridfieldOutput); $this->assertStringNotContainsString('<p class="message ' . ValidationResult::TYPE_ERROR . '">', $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'
);
}
} }