diff --git a/_vendor_patches/silverstripe/framework/0001-my.patch b/_vendor_patches/silverstripe/framework/0001-my.patch new file mode 100644 index 00000000..a143e631 --- /dev/null +++ b/_vendor_patches/silverstripe/framework/0001-my.patch @@ -0,0 +1,851 @@ +diff --git a/docs/en/02_Developer_Guides/03_Forms/Field_types/04_GridField.md b/docs/en/02_Developer_Guides/03_Forms/Field_types/04_GridField.md +index 6d7681b1c91..6c4d0ada51c 100644 +--- a/docs/en/02_Developer_Guides/03_Forms/Field_types/04_GridField.md ++++ b/docs/en/02_Developer_Guides/03_Forms/Field_types/04_GridField.md +@@ -13,7 +13,7 @@ tabular data in a format that is easy to view and modify. It can be thought of a + ```php + use SilverStripe\Forms\GridField\GridField; + +-$field = new GridField($name, $title, $list); ++$field = GridField::create($name, $title, $list); + ``` + + [hint] +@@ -45,7 +45,7 @@ class Page extends SiteTree + $fields = parent::getCMSFields(); + + $fields->addFieldToTab('Root.Pages', +- new GridField('Pages', 'All pages', SiteTree::get()) ++ GridField::create('Pages', 'All pages', SiteTree::get()) + ); + + return $fields; +@@ -81,7 +81,7 @@ class Page extends SiteTree + $fields = parent::getCMSFields(); + + $fields->addFieldToTab('Root.Pages', +- $grid = new GridField('Pages', 'All pages', SiteTree::get()) ++ $grid = GridField::create('Pages', 'All pages', SiteTree::get()) + ); + + // GridField configuration +@@ -115,7 +115,7 @@ use SilverStripe\Forms\GridField\GridFieldDataColumns; + $config = GridFieldConfig::create(); + + // add a component +-$config->addComponent(new GridFieldDataColumns()); ++$config->addComponent(GridFieldDataColumns::create()); + + // Update the GridField with our custom configuration + $gridField->setConfig($config); +@@ -128,7 +128,7 @@ before another component by passing the second parameter. + use SilverStripe\Forms\GridField\GridFieldFilterHeader; + use SilverStripe\Forms\GridField\GridFieldDataColumns; + +-$config->addComponent(new GridFieldFilterHeader(), GridFieldDataColumns::class); ++$config->addComponent(GridFieldFilterHeader::create(), GridFieldDataColumns::class); + ``` + + We can add multiple components in one call. +@@ -136,8 +136,8 @@ We can add multiple components in one call. + + ```php + $config->addComponents( +- new GridFieldDataColumns(), +- new GridFieldToolbarHeader() ++ GridFieldDataColumns::create(), ++ GridFieldToolbarHeader::create() + ); + ``` + +@@ -191,12 +191,12 @@ $config = GridFieldConfig_Base::create(); + $gridField->setConfig($config); + + // Is the same as adding the following components.. +-// .. new GridFieldToolbarHeader() +-// .. new GridFieldSortableHeader() +-// .. new GridFieldFilterHeader() +-// .. new GridFieldDataColumns() +-// .. new GridFieldPageCount('toolbar-header-right') +-// .. new GridFieldPaginator($itemsPerPage) ++// .. GridFieldToolbarHeader::create() ++// .. GridFieldSortableHeader::create() ++// .. GridFieldFilterHeader::create() ++// .. GridFieldDataColumns::create() ++// .. GridFieldPageCount::create('toolbar-header-right') ++// .. GridFieldPaginator::create($itemsPerPage) + ``` + + ### GridFieldConfig_RecordViewer +@@ -223,8 +223,8 @@ $config = GridFieldConfig_RecordViewer::create(); + $gridField->setConfig($config); + + // Same as GridFieldConfig_Base with the addition of +-// .. new GridFieldViewButton(), +-// .. new GridFieldDetailForm() ++// .. GridFieldViewButton::create(), ++// .. GridFieldDetailForm::create() + ``` + + ### GridFieldConfig_RecordEditor +@@ -248,9 +248,9 @@ $config = GridFieldConfig_RecordEditor::create(); + $gridField->setConfig($config); + + // Same as GridFieldConfig_RecordViewer with the addition of +-// .. new GridFieldAddNewButton(), +-// .. new GridFieldEditButton(), +-// .. new GridFieldDeleteAction() ++// .. GridFieldAddNewButton::create(), ++// .. GridFieldEditButton::create(), ++// .. GridFieldDeleteAction::create() + ``` + + ### GridFieldConfig_RelationEditor +@@ -287,9 +287,9 @@ $config = GridFieldConfig::create(); + $config->addComponent(); + + $config->addComponents( +- new GridFieldDataColumns(), +- new GridFieldEditButton(), +- new GridField_ActionMenu() ++ GridFieldDataColumns::create(), ++ GridFieldEditButton::create(), ++ GridField_ActionMenu::create() + ); + + // Update the GridField with our custom configuration +@@ -308,8 +308,8 @@ The `GridFieldDetailForm` component drives the record viewing and editing form. + use SilverStripe\Forms\GridField\GridFieldDetailForm; + + $form = $gridField->getConfig()->getComponentByType(GridFieldDetailForm::class); +-$form->setFields(new FieldList( +- new TextField('Title') ++$form->setFields(FieldList::create( ++ TextField::create('Title') + )); + ``` + +@@ -369,13 +369,13 @@ class Player extends DataObject + $teamFields->addFieldToTab( + 'Root.Main', + // The "ManyMany[]" convention +- new TextField('ManyMany[Position]', 'Current Position') ++ TextField::create('ManyMany[Position]', 'Current Position') + ); + + $config = GridFieldConfig_RelationEditor::create(); + $config->getComponentByType(GridFieldDetailForm::class)->setFields($teamFields); + +- $gridField = new GridField('Teams', 'Teams', $this->Teams(), $config); ++ $gridField = GridField::create('Teams', 'Teams', $this->Teams(), $config); + $fields->findOrMakeTab('Root.Teams')->replaceField('Teams', $gridField); + } + +@@ -405,8 +405,8 @@ bottom right of the table. + use SilverStripe\Forms\GridField\GridFieldButtonRow; + use SilverStripe\Forms\GridField\GridFieldPrintButton; + +-$config->addComponent(new GridFieldButtonRow('after')); +-$config->addComponent(new GridFieldPrintButton('buttons-after-right')); ++$config->addComponent(GridFieldButtonRow::create('after')); ++$config->addComponent(GridFieldPrintButton::create('buttons-after-right')); + ``` + + ### Creating your own Fragments +@@ -417,12 +417,13 @@ create an area rendered before the table wrapped in a simple `
`. + + + ```php ++use SilverStripe\Forms\GridField\AbstractGridFieldComponent; + use SilverStripe\Forms\GridField\GridField_HTMLProvider; + +-class MyAreaComponent implements GridField_HTMLProvider ++class MyAreaComponent extends AbstractGridFieldComponent implements GridField_HTMLProvider + { + +- public function getHTMLFragments( $gridField) ++ public function getHTMLFragments($gridField) + { + return [ + 'before' => '
$DefineFragment(my-area)
' +@@ -442,12 +443,13 @@ Now you can add other components into this area by returning them as an array fr + + + ```php ++use SilverStripe\Forms\GridField\AbstractGridFieldComponent; + use SilverStripe\Forms\GridField\GridField_HTMLProvider; + +-class MyShareLinkComponent implements GridField_HTMLProvider ++class MyShareLinkComponent extends AbstractGridFieldComponent implements GridField_HTMLProvider + { + +- public function getHTMLFragments( $gridField) ++ public function getHTMLFragments($gridField) + { + return [ + 'my-area' => '...' +@@ -461,7 +463,7 @@ Your new area can also be used by existing components, e.g. the [GridFieldPrintB + + + ```php +-new GridFieldPrintButton('my-area'); ++GridFieldPrintButton::create('my-area'); + ``` + + ## Creating a Custom GridFieldComponent +diff --git a/docs/en/02_Developer_Guides/03_Forms/How_Tos/03_Create_a_GridFieldComponent.md b/docs/en/02_Developer_Guides/03_Forms/How_Tos/03_Create_a_GridFieldComponent.md +index 0e4637f3593..892ebb504b1 100644 +--- a/docs/en/02_Developer_Guides/03_Forms/How_Tos/03_Create_a_GridFieldComponent.md ++++ b/docs/en/02_Developer_Guides/03_Forms/How_Tos/03_Create_a_GridFieldComponent.md +@@ -3,7 +3,9 @@ title: Create a GridField Component + summary: Customise your GridField with a variety of add-ons. + icon: table + --- +-A single component often uses a number of interfaces. ++A single component often uses a number of interfaces. It is good practice for your custom ++components to subclass the `AbstractGridFieldComponent` class to ensure they behave the same ++way as built-in components (e.g. are `Injectable`). + + ### GridField_HTMLProvider + +@@ -50,4 +52,4 @@ has a list of URL's that it can handle and the GridField passes request on to UR + Examples: + + - A pop-up form for editing a record's details. +- - JSON formatted data used for javascript control of the gridfield. +\ No newline at end of file ++ - JSON formatted data used for javascript control of the gridfield. +diff --git a/docs/en/02_Developer_Guides/03_Forms/How_Tos/04_Create_a_GridField_ActionProvider.md b/docs/en/02_Developer_Guides/03_Forms/How_Tos/04_Create_a_GridField_ActionProvider.md +index 096d3444ef1..34f752f7e3a 100644 +--- a/docs/en/02_Developer_Guides/03_Forms/How_Tos/04_Create_a_GridField_ActionProvider.md ++++ b/docs/en/02_Developer_Guides/03_Forms/How_Tos/04_Create_a_GridField_ActionProvider.md +@@ -32,13 +32,14 @@ below: + + + ```php ++use SilverStripe\Forms\GridField\AbstractGridFieldComponent; + use SilverStripe\Forms\GridField\GridField_ColumnProvider; + use SilverStripe\Forms\GridField\GridField_ActionProvider; + use SilverStripe\Forms\GridField\GridField_FormAction; + use SilverStripe\Forms\GridField\GridField; + use SilverStripe\Control\Controller; + +-class GridFieldCustomAction implements GridField_ColumnProvider, GridField_ActionProvider ++class GridFieldCustomAction extends AbstractGridFieldComponent implements GridField_ColumnProvider, GridField_ActionProvider + { + + public function augmentColumns($gridField, &$columns) +@@ -114,12 +115,12 @@ manipulating the `GridFieldConfig` instance if required. + ```php + // option 1: creating a new GridField with the CustomAction + $config = GridFieldConfig::create(); +-$config->addComponent(new GridFieldCustomAction()); ++$config->addComponent(GridFieldCustomAction::create()); + +-$gridField = new GridField('Teams', 'Teams', $this->Teams(), $config); ++$gridField = GridField::create('Teams', 'Teams', $this->Teams(), $config); + + // option 2: adding the CustomAction to an existing GridField +-$gridField->getConfig()->addComponent(new GridFieldCustomAction()); ++$gridField->getConfig()->addComponent(GridFieldCustomAction::create()); + ``` + + For documentation on adding a Component to a `GridField` created by `ModelAdmin` +@@ -177,13 +178,14 @@ For an action to be included in the action menu dropdown, which appears on each + ## Basic GridFieldCustomAction boilerplate implementing GridField_ActionMenuItem + + ```php ++use SilverStripe\Forms\GridField\AbstractGridFieldComponent; + use SilverStripe\Forms\GridField\GridField_ColumnProvider; + use SilverStripe\Forms\GridField\GridField_ActionProvider; + use SilverStripe\Forms\GridField\GridField_ActionMenuItem; + use SilverStripe\Forms\GridField\GridField_FormAction; + use SilverStripe\Control\Controller; + +-class GridFieldCustomAction implements GridField_ColumnProvider, GridField_ActionProvider, GridField_ActionMenuItem ++class GridFieldCustomAction extends AbstractGridFieldComponent implements GridField_ColumnProvider, GridField_ActionProvider, GridField_ActionMenuItem + { + + public function getTitle($gridField, $record, $columnName) +diff --git a/docs/en/02_Developer_Guides/15_Customising_the_Admin_Interface/01_ModelAdmin.md b/docs/en/02_Developer_Guides/15_Customising_the_Admin_Interface/01_ModelAdmin.md +index 8e39eae62b1..bf2e1907f6c 100644 +--- a/docs/en/02_Developer_Guides/15_Customising_the_Admin_Interface/01_ModelAdmin.md ++++ b/docs/en/02_Developer_Guides/15_Customising_the_Admin_Interface/01_ModelAdmin.md +@@ -299,7 +299,7 @@ class MyAdmin extends ModelAdmin + $context = parent::getSearchContext(); + + if($this->modelClass == 'Product') { +- $context->getFields()->push(new CheckboxField('q[ExpensiveOnly]', 'Only expensive stuff')); ++ $context->getFields()->push(CheckboxField::create('q[ExpensiveOnly]', 'Only expensive stuff')); + } + + return $context; +@@ -362,7 +362,7 @@ class MyAdmin extends ModelAdmin + { + $config = parent::getGridFieldConfig(); + +- $config->addComponent(new GridFieldFilterHeader()); ++ $config->addComponent(GridFieldFilterHeader::create()); + + return $config; + } +@@ -397,7 +397,7 @@ class MyAdmin extends ModelAdmin + + // modify the list view. + if ($this->modelClass === Product::class) { +- $config->addComponent(new GridFieldFilterHeader()); ++ $config->addComponent(GridFieldFilterHeader::create()); + } + + return $config; +@@ -425,7 +425,7 @@ class ModelAdminExtension extends Extension + { + public function updateGridFieldConfig(GridFieldConfig &$config) + { +- $config->addComponent(new GridFieldFilterHeader()); ++ $config->addComponent(GridFieldFilterHeader::create()); + } + } + ``` +@@ -470,7 +470,7 @@ class MyAdmin extends ModelAdmin + $gridField = $form->Fields()->fieldByName($gridFieldName); + + // modify the list view. +- $gridField->getConfig()->addComponent(new GridFieldFilterHeader()); ++ $gridField->getConfig()->addComponent(GridFieldFilterHeader::create()); + + return $form; + } +diff --git a/docs/en/02_Developer_Guides/15_Customising_the_Admin_Interface/How_Tos/Customise_CMS_Menu.md b/docs/en/02_Developer_Guides/15_Customising_the_Admin_Interface/How_Tos/Customise_CMS_Menu.md +index 921c89a5c4d..51077720126 100644 +--- a/docs/en/02_Developer_Guides/15_Customising_the_Admin_Interface/How_Tos/Customise_CMS_Menu.md ++++ b/docs/en/02_Developer_Guides/15_Customising_the_Admin_Interface/How_Tos/Customise_CMS_Menu.md +@@ -142,7 +142,7 @@ SilverStripe\Forms\GridField\GridFieldDetailForm_ItemRequest: + You can also override this for a specific `GridField` instance when using the `GridFieldConfig_RecordEditor` constructor: + + ```php +-$grid = new GridField( ++$grid = GridField::create( + "pages", + "All Pages", + SiteTree::get(), +diff --git a/src/Forms/GridField/AbstractGridFieldComponent.php b/src/Forms/GridField/AbstractGridFieldComponent.php +new file mode 100644 +index 00000000000..5842e57feb4 +--- /dev/null ++++ b/src/Forms/GridField/AbstractGridFieldComponent.php +@@ -0,0 +1,10 @@ ++getComponentByType(GridFieldViewButton::class)) { +- $copyConfig->addComponent(new GridFieldViewButton); ++ $copyConfig->addComponent(GridFieldViewButton::create()); + } + + return $copy; +@@ -295,7 +295,7 @@ public function setConfig(GridFieldConfig $config) + $this->config = $config; + + if (!$this->config->getComponentByType(GridState_Component::class)) { +- $this->config->addComponent(new GridState_Component()); ++ $this->config->addComponent(GridState_Component::create()); + } + + return $this; +@@ -440,7 +440,7 @@ private function initState(): void + public function FieldHolder($properties = []) + { + $this->extend('onBeforeRenderHolder', $this, $properties); +- ++ + $columns = $this->getColumns(); + + $list = $this->getManipulatedList(); +@@ -655,7 +655,7 @@ public function FieldHolder($properties = []) + $tableAttributes, + $header . "\n" . $footer . "\n" . $body + ); +- ++ + $message = Convert::raw2xml($this->getMessage()); + if (is_array($message)) { + $message = $message['message']; +diff --git a/src/Forms/GridField/GridFieldAddExistingAutocompleter.php b/src/Forms/GridField/GridFieldAddExistingAutocompleter.php +index afec2e03c59..5637cee6b12 100644 +--- a/src/Forms/GridField/GridFieldAddExistingAutocompleter.php ++++ b/src/Forms/GridField/GridFieldAddExistingAutocompleter.php +@@ -32,7 +32,7 @@ + * For easier setup, have a look at a sample configuration in + * {@link GridFieldConfig_RelationEditor}. + */ +-class GridFieldAddExistingAutocompleter implements GridField_HTMLProvider, GridField_ActionProvider, GridField_DataManipulator, GridField_URLHandler ++class GridFieldAddExistingAutocompleter extends AbstractGridFieldComponent implements GridField_HTMLProvider, GridField_ActionProvider, GridField_DataManipulator, GridField_URLHandler + { + + /** +diff --git a/src/Forms/GridField/GridFieldAddNewButton.php b/src/Forms/GridField/GridFieldAddNewButton.php +index 24f7cdd9c34..dffcabdcd08 100644 +--- a/src/Forms/GridField/GridFieldAddNewButton.php ++++ b/src/Forms/GridField/GridFieldAddNewButton.php +@@ -15,7 +15,7 @@ + * Only returns a button if {@link DataObject->canCreate()} for this record + * returns true. + */ +-class GridFieldAddNewButton implements GridField_HTMLProvider ++class GridFieldAddNewButton extends AbstractGridFieldComponent implements GridField_HTMLProvider + { + + protected $targetFragment; +diff --git a/src/Forms/GridField/GridFieldButtonRow.php b/src/Forms/GridField/GridFieldButtonRow.php +index c62f5f8b2c4..32855478b26 100644 +--- a/src/Forms/GridField/GridFieldButtonRow.php ++++ b/src/Forms/GridField/GridFieldButtonRow.php +@@ -14,7 +14,7 @@ + * This row provides two new HTML fragment spaces: 'toolbar-header-left' and + * 'toolbar-header-right'. + */ +-class GridFieldButtonRow implements GridField_HTMLProvider ++class GridFieldButtonRow extends AbstractGridFieldComponent implements GridField_HTMLProvider + { + + protected $targetFragment; +diff --git a/src/Forms/GridField/GridFieldConfig_Base.php b/src/Forms/GridField/GridFieldConfig_Base.php +index 026bab57a0f..ea080390fc9 100644 +--- a/src/Forms/GridField/GridFieldConfig_Base.php ++++ b/src/Forms/GridField/GridFieldConfig_Base.php +@@ -15,13 +15,13 @@ class GridFieldConfig_Base extends GridFieldConfig + public function __construct($itemsPerPage = null) + { + parent::__construct(); +- $this->addComponent(new GridFieldToolbarHeader()); +- $this->addComponent(new GridFieldButtonRow('before')); +- $this->addComponent($sort = new GridFieldSortableHeader()); +- $this->addComponent($filter = new GridFieldFilterHeader()); +- $this->addComponent(new GridFieldDataColumns()); +- $this->addComponent(new GridFieldPageCount('toolbar-header-right')); +- $this->addComponent($pagination = new GridFieldPaginator($itemsPerPage)); ++ $this->addComponent(GridFieldToolbarHeader::create()); ++ $this->addComponent(GridFieldButtonRow::create('before')); ++ $this->addComponent($sort = GridFieldSortableHeader::create()); ++ $this->addComponent($filter = GridFieldFilterHeader::create()); ++ $this->addComponent(GridFieldDataColumns::create()); ++ $this->addComponent(GridFieldPageCount::create('toolbar-header-right')); ++ $this->addComponent($pagination = GridFieldPaginator::create($itemsPerPage)); + + $sort->setThrowExceptionOnBadDataType(false); + $filter->setThrowExceptionOnBadDataType(false); +diff --git a/src/Forms/GridField/GridFieldConfig_RecordEditor.php b/src/Forms/GridField/GridFieldConfig_RecordEditor.php +index 28d7b6749fd..bcb3079d95f 100644 +--- a/src/Forms/GridField/GridFieldConfig_RecordEditor.php ++++ b/src/Forms/GridField/GridFieldConfig_RecordEditor.php +@@ -17,18 +17,18 @@ public function __construct($itemsPerPage = null, $showPagination = null, $showA + { + parent::__construct(); + +- $this->addComponent(new GridFieldButtonRow('before')); +- $this->addComponent(new GridFieldAddNewButton('buttons-before-left')); +- $this->addComponent(new GridFieldToolbarHeader()); +- $this->addComponent($sort = new GridFieldSortableHeader()); +- $this->addComponent($filter = new GridFieldFilterHeader()); +- $this->addComponent(new GridFieldDataColumns()); +- $this->addComponent(new GridFieldEditButton()); +- $this->addComponent(new GridFieldDeleteAction()); +- $this->addComponent(new GridField_ActionMenu()); +- $this->addComponent(new GridFieldPageCount('toolbar-header-right')); +- $this->addComponent($pagination = new GridFieldPaginator($itemsPerPage)); +- $this->addComponent(new GridFieldDetailForm(null, $showPagination, $showAdd)); ++ $this->addComponent(GridFieldButtonRow::create('before')); ++ $this->addComponent(GridFieldAddNewButton::create('buttons-before-left')); ++ $this->addComponent(GridFieldToolbarHeader::create()); ++ $this->addComponent($sort = GridFieldSortableHeader::create()); ++ $this->addComponent($filter = GridFieldFilterHeader::create()); ++ $this->addComponent(GridFieldDataColumns::create()); ++ $this->addComponent(GridFieldEditButton::create()); ++ $this->addComponent(GridFieldDeleteAction::create()); ++ $this->addComponent(GridField_ActionMenu::create()); ++ $this->addComponent(GridFieldPageCount::create('toolbar-header-right')); ++ $this->addComponent($pagination = GridFieldPaginator::create($itemsPerPage)); ++ $this->addComponent(GridFieldDetailForm::create(null, $showPagination, $showAdd)); + + $sort->setThrowExceptionOnBadDataType(false); + $filter->setThrowExceptionOnBadDataType(false); +diff --git a/src/Forms/GridField/GridFieldConfig_RecordViewer.php b/src/Forms/GridField/GridFieldConfig_RecordViewer.php +index fdaa911394e..aae4d471fef 100644 +--- a/src/Forms/GridField/GridFieldConfig_RecordViewer.php ++++ b/src/Forms/GridField/GridFieldConfig_RecordViewer.php +@@ -12,8 +12,8 @@ public function __construct($itemsPerPage = null) + { + parent::__construct($itemsPerPage); + +- $this->addComponent(new GridFieldViewButton()); +- $this->addComponent(new GridFieldDetailForm()); ++ $this->addComponent(GridFieldViewButton::create()); ++ $this->addComponent(GridFieldDetailForm::create()); + $this->removeComponentsByType(GridFieldFilterHeader::class); + + $this->extend('updateConfig'); +diff --git a/src/Forms/GridField/GridFieldConfig_RelationEditor.php b/src/Forms/GridField/GridFieldConfig_RelationEditor.php +index 83cc4000474..2cb243f51b5 100644 +--- a/src/Forms/GridField/GridFieldConfig_RelationEditor.php ++++ b/src/Forms/GridField/GridFieldConfig_RelationEditor.php +@@ -29,19 +29,19 @@ public function __construct($itemsPerPage = null) + { + parent::__construct(); + +- $this->addComponent(new GridFieldButtonRow('before')); +- $this->addComponent(new GridFieldAddNewButton('buttons-before-left')); +- $this->addComponent(new GridFieldAddExistingAutocompleter('buttons-before-right')); +- $this->addComponent(new GridFieldToolbarHeader()); +- $this->addComponent($sort = new GridFieldSortableHeader()); +- $this->addComponent($filter = new GridFieldFilterHeader()); +- $this->addComponent(new GridFieldDataColumns()); +- $this->addComponent(new GridFieldEditButton()); +- $this->addComponent(new GridFieldDeleteAction(true)); +- $this->addComponent(new GridField_ActionMenu()); +- $this->addComponent(new GridFieldPageCount('toolbar-header-right')); +- $this->addComponent($pagination = new GridFieldPaginator($itemsPerPage)); +- $this->addComponent(new GridFieldDetailForm()); ++ $this->addComponent(GridFieldButtonRow::create('before')); ++ $this->addComponent(GridFieldAddNewButton::create('buttons-before-left')); ++ $this->addComponent(GridFieldAddExistingAutocompleter::create('buttons-before-right')); ++ $this->addComponent(GridFieldToolbarHeader::create()); ++ $this->addComponent($sort = GridFieldSortableHeader::create()); ++ $this->addComponent($filter = GridFieldFilterHeader::create()); ++ $this->addComponent(GridFieldDataColumns::create()); ++ $this->addComponent(GridFieldEditButton::create()); ++ $this->addComponent(GridFieldDeleteAction::create(true)); ++ $this->addComponent(GridField_ActionMenu::create()); ++ $this->addComponent(GridFieldPageCount::create('toolbar-header-right')); ++ $this->addComponent($pagination = GridFieldPaginator::create($itemsPerPage)); ++ $this->addComponent(GridFieldDetailForm::create()); + + $sort->setThrowExceptionOnBadDataType(false); + $filter->setThrowExceptionOnBadDataType(false); +diff --git a/src/Forms/GridField/GridFieldDataColumns.php b/src/Forms/GridField/GridFieldDataColumns.php +index a56a285d3bc..39ee1ecfe43 100644 +--- a/src/Forms/GridField/GridFieldDataColumns.php ++++ b/src/Forms/GridField/GridFieldDataColumns.php +@@ -9,7 +9,7 @@ + /** + * @see GridField + */ +-class GridFieldDataColumns implements GridField_ColumnProvider ++class GridFieldDataColumns extends AbstractGridFieldComponent implements GridField_ColumnProvider + { + + /** +diff --git a/src/Forms/GridField/GridFieldDeleteAction.php b/src/Forms/GridField/GridFieldDeleteAction.php +index 5f714c17703..e5bc0434991 100644 +--- a/src/Forms/GridField/GridFieldDeleteAction.php ++++ b/src/Forms/GridField/GridFieldDeleteAction.php +@@ -16,13 +16,13 @@ + * Use the {@link $removeRelation} property set in the constructor. + * + * +- * $action = new GridFieldDeleteAction(); // delete objects permanently ++ * $action = GridFieldDeleteAction::create(); // delete objects permanently + * + * // removes the relation to object instead of deleting +- * $action = new GridFieldDeleteAction(true); ++ * $action = GridFieldDeleteAction::create(true); + * + */ +-class GridFieldDeleteAction implements GridField_ColumnProvider, GridField_ActionProvider, GridField_ActionMenuItem ++class GridFieldDeleteAction extends AbstractGridFieldComponent implements GridField_ColumnProvider, GridField_ActionProvider, GridField_ActionMenuItem + { + + /** +diff --git a/src/Forms/GridField/GridFieldDetailForm.php b/src/Forms/GridField/GridFieldDetailForm.php +index a6dae5aba63..0497dc564f6 100644 +--- a/src/Forms/GridField/GridFieldDetailForm.php ++++ b/src/Forms/GridField/GridFieldDetailForm.php +@@ -11,7 +11,6 @@ + use SilverStripe\Control\RequestHandler; + use SilverStripe\Core\ClassInfo; + use SilverStripe\Core\Extensible; +-use SilverStripe\Core\Injector\Injectable; + use SilverStripe\Core\Injector\Injector; + use SilverStripe\Forms\FieldList; + use SilverStripe\Forms\Validator; +@@ -32,10 +31,10 @@ + * - /field//item/ + * - /field//item//edit + */ +-class GridFieldDetailForm implements GridField_URLHandler ++class GridFieldDetailForm extends AbstractGridFieldComponent implements GridField_URLHandler + { + +- use Extensible, Injectable, GridFieldStateAware; ++ use Extensible, GridFieldStateAware; + + /** + * @var string +diff --git a/src/Forms/GridField/GridFieldEditButton.php b/src/Forms/GridField/GridFieldEditButton.php +index 41a5b606bc8..aac826507af 100644 +--- a/src/Forms/GridField/GridFieldEditButton.php ++++ b/src/Forms/GridField/GridFieldEditButton.php +@@ -3,7 +3,6 @@ + namespace SilverStripe\Forms\GridField; + + use SilverStripe\Control\Controller; +-use SilverStripe\Core\Injector\Injectable; + use SilverStripe\ORM\DataObject; + use SilverStripe\View\ArrayData; + use SilverStripe\View\SSViewer; +@@ -18,9 +17,9 @@ + * The default routing applies to the {@link GridFieldDetailForm} component, + * which has to be added separately to the {@link GridField} configuration. + */ +-class GridFieldEditButton implements GridField_ColumnProvider, GridField_ActionProvider, GridField_ActionMenuLink ++class GridFieldEditButton extends AbstractGridFieldComponent implements GridField_ColumnProvider, GridField_ActionProvider, GridField_ActionMenuLink + { +- use Injectable, GridFieldStateAware; ++ use GridFieldStateAware; + + /** + * HTML classes to be added to GridField edit buttons +diff --git a/src/Forms/GridField/GridFieldExportButton.php b/src/Forms/GridField/GridFieldExportButton.php +index 35be2269e33..1954eb00628 100644 +--- a/src/Forms/GridField/GridFieldExportButton.php ++++ b/src/Forms/GridField/GridFieldExportButton.php +@@ -12,7 +12,7 @@ + /** + * Adds an "Export list" button to the bottom of a {@link GridField}. + */ +-class GridFieldExportButton implements GridField_HTMLProvider, GridField_ActionProvider, GridField_URLHandler ++class GridFieldExportButton extends AbstractGridFieldComponent implements GridField_HTMLProvider, GridField_ActionProvider, GridField_URLHandler + { + /** + * @var array Map of a property name on the exported objects, with values being the column title in the CSV file. +diff --git a/src/Forms/GridField/GridFieldFilterHeader.php b/src/Forms/GridField/GridFieldFilterHeader.php +index 3d58882124f..9bd3bf37a98 100755 +--- a/src/Forms/GridField/GridFieldFilterHeader.php ++++ b/src/Forms/GridField/GridFieldFilterHeader.php +@@ -26,7 +26,7 @@ + * + * @see GridField + */ +-class GridFieldFilterHeader implements GridField_URLHandler, GridField_HTMLProvider, GridField_DataManipulator, GridField_ActionProvider, GridField_StateProvider ++class GridFieldFilterHeader extends AbstractGridFieldComponent implements GridField_URLHandler, GridField_HTMLProvider, GridField_DataManipulator, GridField_ActionProvider, GridField_StateProvider + { + /** + * See {@link setThrowExceptionOnBadDataType()} +diff --git a/src/Forms/GridField/GridFieldFooter.php b/src/Forms/GridField/GridFieldFooter.php +index bb6ace848fd..0cec8cc97d7 100644 +--- a/src/Forms/GridField/GridFieldFooter.php ++++ b/src/Forms/GridField/GridFieldFooter.php +@@ -18,7 +18,7 @@ + * The purpose of this class is to have a footer that can round off + * {@link GridField} without having to use pagination. + */ +-class GridFieldFooter implements GridField_HTMLProvider ++class GridFieldFooter extends AbstractGridFieldComponent implements GridField_HTMLProvider + { + + /** +diff --git a/src/Forms/GridField/GridFieldImportButton.php b/src/Forms/GridField/GridFieldImportButton.php +index e3ce0322181..61865a2dae0 100644 +--- a/src/Forms/GridField/GridFieldImportButton.php ++++ b/src/Forms/GridField/GridFieldImportButton.php +@@ -2,15 +2,12 @@ + + namespace SilverStripe\Forms\GridField; + +-use SilverStripe\Core\Injector\Injectable; + use SilverStripe\Forms\Form; + use SilverStripe\View\ArrayData; + use SilverStripe\View\SSViewer; + +-class GridFieldImportButton implements GridField_HTMLProvider ++class GridFieldImportButton extends AbstractGridFieldComponent implements GridField_HTMLProvider + { +- use Injectable; +- + /** + * Fragment to write the button to + */ +diff --git a/src/Forms/GridField/GridFieldLazyLoader.php b/src/Forms/GridField/GridFieldLazyLoader.php +index 63a761f6e35..e117116cb76 100755 +--- a/src/Forms/GridField/GridFieldLazyLoader.php ++++ b/src/Forms/GridField/GridFieldLazyLoader.php +@@ -14,7 +14,7 @@ + * + * @see GridField + */ +-class GridFieldLazyLoader implements GridField_DataManipulator, GridField_HTMLProvider ++class GridFieldLazyLoader extends AbstractGridFieldComponent implements GridField_DataManipulator, GridField_HTMLProvider + { + + /** +diff --git a/src/Forms/GridField/GridFieldLevelup.php b/src/Forms/GridField/GridFieldLevelup.php +index 7cdc015ddaa..d43838a02a5 100644 +--- a/src/Forms/GridField/GridFieldLevelup.php ++++ b/src/Forms/GridField/GridFieldLevelup.php +@@ -2,7 +2,6 @@ + + namespace SilverStripe\Forms\GridField; + +-use SilverStripe\Core\Injector\Injectable; + use SilverStripe\ORM\DataObject; + use SilverStripe\ORM\FieldType\DBField; + use SilverStripe\ORM\Hierarchy\Hierarchy; +@@ -15,10 +14,8 @@ + * hierarchical data. Requires the managed record to have a "getParent()" + * method or has_one relationship called "Parent". + */ +-class GridFieldLevelup implements GridField_HTMLProvider ++class GridFieldLevelup extends AbstractGridFieldComponent implements GridField_HTMLProvider + { +- use Injectable; +- + /** + * @var integer - the record id of the level up to + */ +diff --git a/src/Forms/GridField/GridFieldPageCount.php b/src/Forms/GridField/GridFieldPageCount.php +index b82d3046511..bebbadcd0a0 100755 +--- a/src/Forms/GridField/GridFieldPageCount.php ++++ b/src/Forms/GridField/GridFieldPageCount.php +@@ -12,7 +12,7 @@ + * + * Depends on {@link GridFieldPaginator} being added to the {@link GridField}. + */ +-class GridFieldPageCount implements GridField_HTMLProvider ++class GridFieldPageCount extends AbstractGridFieldComponent implements GridField_HTMLProvider + { + use Configurable; + +diff --git a/src/Forms/GridField/GridFieldPaginator.php b/src/Forms/GridField/GridFieldPaginator.php +index 8573c0efd7f..d6eb208ef06 100755 +--- a/src/Forms/GridField/GridFieldPaginator.php ++++ b/src/Forms/GridField/GridFieldPaginator.php +@@ -14,7 +14,7 @@ + * GridFieldPaginator paginates the {@link GridField} list and adds controls + * to the bottom of the {@link GridField}. + */ +-class GridFieldPaginator implements GridField_HTMLProvider, GridField_DataManipulator, GridField_ActionProvider, GridField_StateProvider ++class GridFieldPaginator extends AbstractGridFieldComponent implements GridField_HTMLProvider, GridField_DataManipulator, GridField_ActionProvider, GridField_StateProvider + { + use Configurable; + +diff --git a/src/Forms/GridField/GridFieldPrintButton.php b/src/Forms/GridField/GridFieldPrintButton.php +index cbec6c3aec5..1ec2be669f6 100644 +--- a/src/Forms/GridField/GridFieldPrintButton.php ++++ b/src/Forms/GridField/GridFieldPrintButton.php +@@ -16,7 +16,7 @@ + /** + * Adds an "Print" button to the bottom or top of a GridField. + */ +-class GridFieldPrintButton implements GridField_HTMLProvider, GridField_ActionProvider, GridField_URLHandler ++class GridFieldPrintButton extends AbstractGridFieldComponent implements GridField_HTMLProvider, GridField_ActionProvider, GridField_URLHandler + { + use Extensible; + +diff --git a/src/Forms/GridField/GridFieldSortableHeader.php b/src/Forms/GridField/GridFieldSortableHeader.php +index fa97d8239ba..7255cc8b584 100644 +--- a/src/Forms/GridField/GridFieldSortableHeader.php ++++ b/src/Forms/GridField/GridFieldSortableHeader.php +@@ -18,7 +18,7 @@ + * + * @see GridField + */ +-class GridFieldSortableHeader implements GridField_HTMLProvider, GridField_DataManipulator, GridField_ActionProvider, GridField_StateProvider ++class GridFieldSortableHeader extends AbstractGridFieldComponent implements GridField_HTMLProvider, GridField_DataManipulator, GridField_ActionProvider, GridField_StateProvider + { + + /** +diff --git a/src/Forms/GridField/GridFieldToolbarHeader.php b/src/Forms/GridField/GridFieldToolbarHeader.php +index 513c5677e10..8171139e30f 100644 +--- a/src/Forms/GridField/GridFieldToolbarHeader.php ++++ b/src/Forms/GridField/GridFieldToolbarHeader.php +@@ -10,7 +10,7 @@ + * + * The header serves to display the name of the data the GridField is showing. + */ +-class GridFieldToolbarHeader implements GridField_HTMLProvider ++class GridFieldToolbarHeader extends AbstractGridFieldComponent implements GridField_HTMLProvider + { + + /** +diff --git a/src/Forms/GridField/GridFieldViewButton.php b/src/Forms/GridField/GridFieldViewButton.php +index e99b40033d0..9848f7a25cc 100644 +--- a/src/Forms/GridField/GridFieldViewButton.php ++++ b/src/Forms/GridField/GridFieldViewButton.php +@@ -11,7 +11,7 @@ + * disabled by default and intended for use in readonly {@link GridField} + * instances. + */ +-class GridFieldViewButton implements GridField_ColumnProvider, GridField_ActionMenuLink ++class GridFieldViewButton extends AbstractGridFieldComponent implements GridField_ColumnProvider, GridField_ActionMenuLink + { + /** + * @inheritdoc +diff --git a/src/Forms/GridField/GridField_ActionMenu.php b/src/Forms/GridField/GridField_ActionMenu.php +index 23b180e4c82..caf535b573c 100644 +--- a/src/Forms/GridField/GridField_ActionMenu.php ++++ b/src/Forms/GridField/GridField_ActionMenu.php +@@ -8,7 +8,7 @@ + /** + * Groups exiting actions in the Actions column in to a menu + */ +-class GridField_ActionMenu implements GridField_ColumnProvider, GridField_ActionProvider ++class GridField_ActionMenu extends AbstractGridFieldComponent implements GridField_ColumnProvider, GridField_ActionProvider + { + public function augmentColumns($gridField, &$columns) + { +diff --git a/src/Forms/GridField/GridState_Component.php b/src/Forms/GridField/GridState_Component.php +index 2b749345c72..b1f67272f3b 100644 +--- a/src/Forms/GridField/GridState_Component.php ++++ b/src/Forms/GridField/GridState_Component.php +@@ -5,7 +5,7 @@ + /** + * @see GridState + */ +-class GridState_Component implements GridField_HTMLProvider ++class GridState_Component extends AbstractGridFieldComponent implements GridField_HTMLProvider + { + + public function getHTMLFragments($gridField) +diff --git a/src/Security/Group.php b/src/Security/Group.php +index 4fcb6a5eb07..0ba051006fd 100755 +--- a/src/Security/Group.php ++++ b/src/Security/Group.php +@@ -84,7 +84,7 @@ class Group extends DataObject + ]; + + private static $table_name = "Group"; +- ++ + private static $indexes = [ + 'Title' => true, + 'Code' => true, +@@ -159,11 +159,11 @@ public function getCMSFields() + if ($this->ID) { + $group = $this; + $config = GridFieldConfig_RelationEditor::create(); +- $config->addComponent(new GridFieldButtonRow('after')); +- $config->addComponents(new GridFieldExportButton('buttons-after-left')); +- $config->addComponents(new GridFieldPrintButton('buttons-after-left')); ++ $config->addComponent(GridFieldButtonRow::create('after')); ++ $config->addComponents(GridFieldExportButton::create('buttons-after-left')); ++ $config->addComponents(GridFieldPrintButton::create('buttons-after-left')); + $config->removeComponentsByType(GridFieldDeleteAction::class); +- $config->addComponent(new GridFieldGroupDeleteAction($this->ID), GridFieldPageCount::class); ++ $config->addComponent(GridFieldGroupDeleteAction::create($this->ID), GridFieldPageCount::class); + + /** @var GridFieldAddExistingAutocompleter $autocompleter */ + $autocompleter = $config->getComponentByType(GridFieldAddExistingAutocompleter::class);