mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
Merge pull request #9655 from sminnee/pulls/9647-find-lost-records
NEW: Add GridFieldDetailForm::setRedirectMissingRecords()
This commit is contained in:
commit
196752566f
@ -3,8 +3,11 @@
|
||||
namespace SilverStripe\Forms\GridField;
|
||||
|
||||
use Closure;
|
||||
use SilverStripe\Control\Director;
|
||||
use SilverStripe\Control\HTTPRequest;
|
||||
use SilverStripe\Control\HTTPResponse;
|
||||
use SilverStripe\Control\HTTPResponse_Exception;
|
||||
use SilverStripe\Control\HTTPStreamResponse;
|
||||
use SilverStripe\Control\RequestHandler;
|
||||
use SilverStripe\Core\ClassInfo;
|
||||
use SilverStripe\Core\Extensible;
|
||||
@ -12,6 +15,7 @@ use SilverStripe\Core\Injector\Injectable;
|
||||
use SilverStripe\Core\Injector\Injector;
|
||||
use SilverStripe\Forms\FieldList;
|
||||
use SilverStripe\Forms\Validator;
|
||||
use SilverStripe\ORM\DataList;
|
||||
use SilverStripe\ORM\DataObject;
|
||||
use SilverStripe\ORM\Filterable;
|
||||
|
||||
@ -68,6 +72,12 @@ class GridFieldDetailForm implements GridField_URLHandler
|
||||
*/
|
||||
protected $itemRequestClass;
|
||||
|
||||
/**
|
||||
* If true, will redirect to missing records if they are found elsewhere
|
||||
* @var bool
|
||||
*/
|
||||
protected $redirectMissingRecords = false;
|
||||
|
||||
/**
|
||||
* @var callable With two parameters: $form and $component
|
||||
*/
|
||||
@ -113,6 +123,17 @@ class GridFieldDetailForm implements GridField_URLHandler
|
||||
$requestHandler = $gridField->getForm()->getController();
|
||||
$record = $this->getRecordFromRequest($gridField, $request);
|
||||
if (!$record) {
|
||||
// Look for the record elsewhere in the CMS
|
||||
$redirectDest = $this->getLostRecordRedirection($gridField, $request);
|
||||
// Don't allow infinite redirections
|
||||
if ($redirectDest) {
|
||||
// Mark the remainder of the URL as parsed to trigger an immediate redirection
|
||||
while (!$request->allParsed()) {
|
||||
$request->shift();
|
||||
}
|
||||
return (new HTTPResponse())->redirect($redirectDest);
|
||||
}
|
||||
|
||||
return $requestHandler->httpError(404, 'That record was not found');
|
||||
}
|
||||
$handler = $this->getItemRequestHandler($gridField, $record, $requestHandler);
|
||||
@ -148,6 +169,50 @@ class GridFieldDetailForm implements GridField_URLHandler
|
||||
return $record;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try and find another URL at which the given record can be edited.
|
||||
* If redirectMissingRecords is true and the record has a CMSEditLink method, that value will be returned.
|
||||
* This only works when the list passed to the GridField is a {@link DataList}.
|
||||
*
|
||||
* @param $gridField The current GridField
|
||||
* @param $id The ID of the DataObject to open
|
||||
*/
|
||||
public function getLostRecordRedirection(GridField $gridField, HTTPRequest $request, ?int $id = null): ?string
|
||||
{
|
||||
|
||||
if (!$this->redirectMissingRecords) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// If not supplied, look up the ID from the request
|
||||
if ($id === null && is_numeric($request->param('ID'))) {
|
||||
$id = (int)$request->param('ID');
|
||||
}
|
||||
|
||||
if (!$id) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$list = $gridField->getList();
|
||||
if (!$list instanceof DataList) {
|
||||
throw new \LogicException('List is not of type DataList, cannot determine redirection target');
|
||||
}
|
||||
|
||||
$existing = DataObject::get($list->dataClass())->byID($id);
|
||||
if ($existing && $existing->hasMethod('CMSEditLink')) {
|
||||
$link = $existing->CMSEditLink();
|
||||
}
|
||||
|
||||
if ($link && $link == $request->getURL()) {
|
||||
throw new \LogicException(sprintf(
|
||||
'Infinite redirection to "%s" detected in GridFieldDetailForm->getLostRecordRedirection()',
|
||||
$link
|
||||
));
|
||||
}
|
||||
|
||||
return $link;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a request handler for the given record
|
||||
*
|
||||
@ -209,6 +274,28 @@ class GridFieldDetailForm implements GridField_URLHandler
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable redirection to missing records.
|
||||
*
|
||||
* If a GridField shows a filtered list, and the DataObject is not in the list but exists in the
|
||||
* database, and the DataObject has a CMSEditLink method, then the system will redirect to the
|
||||
* URL returned by that method.
|
||||
*/
|
||||
public function setRedirectMissingRecords(bool $redirectMissingRecords): self
|
||||
{
|
||||
$this->redirectMissingRecords = $redirectMissingRecords;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the status of redirection to missing records.
|
||||
* @see setRedirectMissingRecordssetRedirectMissingRecords
|
||||
*/
|
||||
public function getRedirectMissingRecords(): bool
|
||||
{
|
||||
return $this->redirectMissingRecords;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
|
@ -623,6 +623,11 @@ class GridFieldDetailForm_ItemRequest extends RequestHandler
|
||||
// to the same URL (it assumes that its content is already current, and doesn't reload)
|
||||
return $this->edit($controller->getRequest());
|
||||
} else {
|
||||
// We might be able to redirect to open the record in a different view
|
||||
if ($redirectDest = $this->component->getLostRecordRedirection($this->gridField, $controller->getRequest(), $this->record->ID)) {
|
||||
return $controller->redirect($redirectDest, 302);
|
||||
}
|
||||
|
||||
// Changes to the record properties might've excluded the record from
|
||||
// a filtered list, so return back to the main view if it can't be found
|
||||
$url = $controller->getRequest()->getURL();
|
||||
|
@ -207,7 +207,7 @@ class GridFieldDetailFormTest extends FunctionalTest
|
||||
);
|
||||
$this->assertFalse($response->isError());
|
||||
|
||||
$person = Person::get()->sort('FirstName')->First();
|
||||
$person = $this->objFromFixture(Person::class, 'jane');
|
||||
$favouriteGroup = $person->FavouriteGroups()->first();
|
||||
|
||||
$this->assertInstanceOf(PeopleGroup::class, $favouriteGroup);
|
||||
@ -248,7 +248,7 @@ class GridFieldDetailFormTest extends FunctionalTest
|
||||
]
|
||||
);
|
||||
$this->assertFalse($response->isError());
|
||||
$person = Person::get()->sort('FirstName')->First();
|
||||
$person = $this->objFromFixture(Person::class, 'jane');
|
||||
$category = $person->Categories()->filter(['Name' => 'Updated Category'])->First();
|
||||
$this->assertEquals(
|
||||
[
|
||||
@ -271,7 +271,7 @@ class GridFieldDetailFormTest extends FunctionalTest
|
||||
);
|
||||
$this->assertFalse($response->isError());
|
||||
|
||||
$person = Person::get()->sort('FirstName')->First();
|
||||
$person = $this->objFromFixture(Person::class, 'jane');
|
||||
$category = $person->Categories()->filter(['Name' => 'Updated Category'])->First();
|
||||
$this->assertEquals(
|
||||
[
|
||||
@ -405,4 +405,34 @@ class GridFieldDetailFormTest extends FunctionalTest
|
||||
$this->assertEquals($group->Name, (string) $title[0]);
|
||||
$this->assertEquals($group->ID, (string) $id[0]['value']);
|
||||
}
|
||||
|
||||
public function testRedirectMissingRecords()
|
||||
{
|
||||
$origAutoFollow = $this->autoFollowRedirection;
|
||||
$this->autoFollowRedirection = false;
|
||||
|
||||
// GridField is filtered people in "My Group", which does't include "jack"
|
||||
$included = $this->objFromFixture(Person::class, 'joe');
|
||||
$excluded = $this->objFromFixture(Person::class, 'jack');
|
||||
|
||||
$response = $this->get(sprintf(
|
||||
'GridFieldDetailFormTest_Controller/Form/field/testfield/item/%d/edit',
|
||||
$included->ID
|
||||
));
|
||||
$this->assertFalse(
|
||||
$response->isRedirect(),
|
||||
'Existing records are not redirected'
|
||||
);
|
||||
|
||||
$response = $this->get(sprintf(
|
||||
'GridFieldDetailFormTest_Controller/Form/field/testfield/item/%d/edit',
|
||||
$excluded->ID
|
||||
));
|
||||
$this->assertTrue(
|
||||
$response->isRedirect(),
|
||||
'Non-existing records are redirected'
|
||||
);
|
||||
|
||||
$this->autoFollowRedirection = $origAutoFollow;
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,9 @@ SilverStripe\Forms\Tests\GridField\GridFieldDetailFormTest\Person:
|
||||
jane:
|
||||
FirstName: Jane
|
||||
Surname: Doe
|
||||
jack:
|
||||
FirstName: Jack
|
||||
Surname: Doe
|
||||
|
||||
SilverStripe\Forms\Tests\GridField\GridFieldDetailFormTest\PeopleGroup:
|
||||
group:
|
||||
|
@ -31,7 +31,7 @@ class CategoryController extends Controller implements TestOnly
|
||||
public function Form()
|
||||
{
|
||||
// GridField lists categories for a specific person
|
||||
$person = Person::get()->sort('FirstName')->First();
|
||||
$person = Person::get()->filter('FirstName', 'Jane')->First();
|
||||
$detailFields = singleton(Category::class)->getCMSFields();
|
||||
$detailFields->addFieldsToTab(
|
||||
'Root.Main',
|
||||
|
@ -69,4 +69,9 @@ class Person extends DataObject implements TestOnly
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function CMSEditLink()
|
||||
{
|
||||
return sprintf('my-admin/%d', $this->ID);
|
||||
}
|
||||
}
|
||||
|
@ -48,7 +48,9 @@ class TestController extends Controller implements TestOnly
|
||||
$field->getConfig()->addComponent(new GridFieldViewButton());
|
||||
$field->getConfig()->addComponent(new GridFieldEditButton());
|
||||
/** @skipUpgrade */
|
||||
$field->getConfig()->addComponent($gridFieldForm = new GridFieldDetailForm($this, 'Form'));
|
||||
$gridFieldForm = new GridFieldDetailForm($this, 'Form');
|
||||
$gridFieldForm->setRedirectMissingRecords(true);
|
||||
$field->getConfig()->addComponent($gridFieldForm);
|
||||
$field->getConfig()->addComponent(new GridFieldEditButton());
|
||||
/** @skipUpgrade */
|
||||
return new Form($this, 'Form', new FieldList($field), new FieldList());
|
||||
|
Loading…
Reference in New Issue
Block a user