diff --git a/src/Forms/GridField/GridField.php b/src/Forms/GridField/GridField.php index b66dc274e..5d959596d 100644 --- a/src/Forms/GridField/GridField.php +++ b/src/Forms/GridField/GridField.php @@ -105,6 +105,21 @@ class GridField extends FormField */ protected $name = ''; + /** + * A whitelist of readonly component classes allowed if performReadonlyTransform is called. + * + * @var array + */ + protected $readonlyComponents = array( + GridFieldDetailForm::class, + GridFieldDataColumns::class, + GridFieldConfig_RecordViewer::class, + GridFieldToolbarHeader::class, + GridFieldPageCount::class, + GridFieldPaginator::class, + GridState_Component::class + ); + /** * Pattern used for looking up */ @@ -193,6 +208,60 @@ class GridField extends FormField ); } + /** + * Overload the readonly components for this gridfield. + * + * @param array $components an array map of component class references to whitelist for a readonly version. + */ + public function setReadonlyComponents(array $components) + { + $this->readonlyComponents = $components; + } + + /** + * Return the readonly components + * + * @return array a map of component classes. + */ + public function getReadonlyComponents() + { + return $this->readonlyComponents; + } + + /** + * Custom Readonly transformation to remove actions which shouldn't be present for a readonly state. + * + * @return GridField + */ + public function performReadonlyTransformation() + { + $copy = clone $this; + $copy->setReadonly(true); + + // get the whitelist for allowable readonly components + $allowedComponents = $this->getReadonlyComponents(); + foreach ($this->getConfig()->getComponents() as $component) { + + // if a component doesn't exist, remove it from the readonly version. + if (!in_array(get_class($component), $allowedComponents)) { + $copy->getConfig()->removeComponent($component); + } + } + + return $copy; + } + + /** + * Disabling the gridfield should have the same affect as making it readonly (removing all action items). + * + * @return GridField + */ + public function performDisabledTransformation(){ + parent::performDisabledTransformation(); + + return $this->performReadonlyTransformation(); + } + /** * @return GridFieldConfig */ diff --git a/tests/php/Forms/GridField/GridFieldReadonlyTest.php b/tests/php/Forms/GridField/GridFieldReadonlyTest.php new file mode 100644 index 000000000..bb3d7136f --- /dev/null +++ b/tests/php/Forms/GridField/GridFieldReadonlyTest.php @@ -0,0 +1,87 @@ +getComponents('Cheerleaders'); + + $gridConfig = GridFieldConfig_RelationEditor::create(); + + // Build some commonly used components to make sure we're only allowing the correct components + $gridConfig->addComponent(new GridFieldButtonRow('before')); + $gridConfig->addComponent(new GridFieldAddNewButton('buttons-before-left')); + $gridConfig->addComponent(new GridFieldAddExistingAutocompleter('buttons-before-right')); + $gridConfig->addComponent(new GridFieldToolbarHeader()); + $gridConfig->addComponent($sort = new GridFieldSortableHeader()); + $gridConfig->addComponent($filter = new GridFieldFilterHeader()); + $gridConfig->addComponent(new GridFieldDataColumns()); + $gridConfig->addComponent(new GridFieldEditButton()); + $gridConfig->addComponent(new GridFieldDeleteAction(true)); + $gridConfig->addComponent(new GridField_ActionMenu()); + $gridConfig->addComponent(new GridFieldPageCount('toolbar-header-right')); + $gridConfig->addComponent($pagination = new GridFieldPaginator(2)); + $gridConfig->addComponent(new GridFieldDetailForm()); + $gridConfig->addComponent(new GridFieldDeleteAction()); + $gridConfig->addComponent(new VersionedGridFieldState()); + + $gridField = GridField::create( + 'Cheerleaders', + 'Cheerleaders', + $components, + $gridConfig + ); + + // Model Admin sets the value of the GridField directly to the relation, which doesn't have a forTemplate() + // function, if we rely on FormField to render into a ReadonlyField we'll get an error as HasManyRelation + // doesn't have a forTemplate() function. + $gridField->setValue($components); + $gridField->setModelClass(Cheerleader::class); + + // This function is called by $form->makeReadonly(). + $readonlyGridField = $gridField->performReadonlyTransformation(); + + // if we've made it this far, then the GridField is at least transforming correctly. + $readonlyComponents = $readonlyGridField->getReadonlyComponents(); + + // assert that all the components in the readonly version are present in the whitelist. + foreach($readonlyGridField->getConfig()->getComponents() as $component){ + $this->assertTrue(in_array(get_class($component), $readonlyComponents)); + } + } +} diff --git a/tests/php/Forms/GridField/GridFieldReadonlyTest.yml b/tests/php/Forms/GridField/GridFieldReadonlyTest.yml new file mode 100644 index 000000000..62855505e --- /dev/null +++ b/tests/php/Forms/GridField/GridFieldReadonlyTest.yml @@ -0,0 +1,27 @@ +SilverStripe\Forms\Tests\GridField\GridFieldTest\Team: + team1: + Name: Team 1 + City: Cologne + team2: + Name: Team 2 + City: Wellington + team3: + Name: Team 3 + City: Auckland + team4: + Name: Team 4 + City: Melbourne + +SilverStripe\Forms\Tests\GridField\GridFieldTest\Cheerleader: + cheerleader1: + Name: Heather + Team: =>SilverStripe\Forms\Tests\GridField\GridFieldTest\Team.team1 + cheerleader2: + Name: Bob + Team: =>SilverStripe\Forms\Tests\GridField\GridFieldTest\Team.team1 + cheerleader3: + Name: Jenny + Team: =>SilverStripe\Forms\Tests\GridField\GridFieldTest\Team.team1 + cheerleader4: + Name: Sam + Team: =>SilverStripe\Forms\Tests\GridField\GridFieldTest\Team.team1