Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Add ability to add custom actions to GridField record #526

Closed
wants to merge 7 commits into from

8 participants

@mlewis-everley

Mainly I see this as useful for ModelAdmin, but could be useful elsewhere as well.

Currently GridField only adds Create/Cancel or Save/Delete buttons when editing an object. The record controller now checks if the Model class provides a getCMSActions() method, and if so, uses that.

Also added some extra methods for Publishing and UnPublishing content.

Still rudimentary, but think it would be quite a useful feature.

Morven added some commits
Morven Add check for getCMSActions() on record. If exists (and object in DB)…
… use that instead of default actions.

Add doPublish() method as well, to provide support for Versioned extension on DataObjects
002049a
Morven Add basic unpublish support c43b854
Morven Add form and data parameters to unpublish method aa7c663
@sminnee
Owner

There is too much use-case specific stuff and magic in this approach.

  • Don't rely on getCMSActions(), provide configuration options (constructor arguments or setters) in the Detail form object to specify buttons. It then might appropriate in ModelAdmin rather than GridField to interrogate the values in getCMSActions() and pass the resulting buttons to GridFieldDetailForm. Alternatively, GridFieldDetailForm could be designed so that it can be passed a callback to fetch actions, and this callback could be set to:

    $detailFormComponent->setActions(function($record) {
        return $record->getCMSActions();
    });
    
  • Don't hard-code the publish and unpublish action handlers into GridFieldDetailForm. There are a few ways you could do this:

    • Provide a configuration option that let you add more action handlers (perhaps as anonymous functions).
    • Provide an additional GridField component that provided the additional actions.
    • Create a subclass of GridFieldDetailForm specifically for versioned objects.

Once again, the ModelAdmin could be configured to interrogate the managed object to identify which actions were necessary.

mlewis-everley and others added some commits
@mlewis-everley mlewis-everley Merge upstream changes from 3.0.0-rc1 9c9898d
morven Merge commit '3.0.0' into MLE-3.0.0-ModelAdmin 7056681
morven Update gridfield to use Getters and Setters for form actions
Remove publish and unpublish methods, as these can be added via an extension or subclass
Add getters and setters that can be manipulated after creating a new GridFieldDetailFrom()
646fb99
@mlewis-everley

Ok, I have done a lot of reverse engineering of GridField. Hopefully I am getting closer to your comments.

I have removed the Publish and UnPublish methods, and successfully SubClassed GridFieldDetailForm_ItemRequest, adding these methods to that.

I have also removed the getCMSActions check and instead added a getFormActions() and setFormActions() method to GridFieldDetailForm that is passed to GridFieldDetailForm_ItemRequest.

I haven't done anything with ModelAdmin however, so far I have managed to make use of these methods and subclasses in my ModelAdmin subclass (which is currently not ideal, as I have to copy the getEditForm() method from ModelAdmin intio my subclass.

Not sure if ModelAdmin should have some sort of setter to allow overwriting of these actions more easily?

Mo

@mlewis-everley

As far as I can tell, the cleanest way of using the setFormActions() method is to overwrite getEditForm() in your ModelAdmin subclass and add both the new actions and a new ItemRequest subclass (with methods called by your new actions).

So something like this:

function getEditForm($id = null, $fields = null) {
    $form = parent::getEditForm($id = null, $fields = null);    
    $listfield = $form->Fields()->fieldByName([MODELCLASS]);

    $listfield->getConfig()->getComponentByType('GridFieldDetailForm')
        ->setItemRequestClass('[CLASSNAME]_ItemRequest')
        ->setFormActions(singleton($this->modelClass)->getCMSActions());

    return $form;
}
@mlewis-everley mlewis-everley reopened this
@sminnee sminnee closed this
@sminnee sminnee reopened this
@travisbot

This pull request passes (merged 4ac4b23 into 64357a4).

@mlewis-everley

I am going to close this, as I have found that you can edit the Item Form actions in ModelAdmin quite easily by:

  1. Extending GridFieldDetailFrom_ItemRequest.
  2. Adding an ItemEditForm() method to your extension.
  3. Within ItemEditForm() call parent::ItemEditForm()->actions()
  4. Edit actions via the FieldList API.

Not really sure these changes need to be merged into core, so as I said am closing this request.

@chillu
Owner

Thanks anyway, Morven :)

@xini

Sorry I didn't quite get it. What is the final general solution to this?
Thanks, xini

@icecaster

extend GridFieldDetailForm & GridFieldDetailForm_ItemRequest
eg.

class VersionedGridFieldDetailForm extends GridFieldDetailForm {    
}

class VersionedGridFieldDetailForm_ItemRequest extends GridFieldDetailForm_ItemRequest {
}

then in VersionedGridFieldDetailForm_ItemRequest

function ItemEditForm() {
        $form = parent::ItemEditForm();
        $actions = $this->record->getCMSActions();

        $form->setActions($actions);
        return $form;
}

or in my case

function ItemEditForm() {
        $form = parent::ItemEditForm();
        $actions = FieldList::create(...actions...);

        $form->setActions($actions);
        return $form;
}

Hope this helps.

Cheers

@xini

I got it working. Thanks!

@vikas-srivastava

I am having a problem with this method. My action buttons are only appearing in Model Admin but not in Relation Editor, So when I am editing my dataobject from Model Admin they are working fine, but I have a relation of this dataobject with HomePage and when I try to edit this from HomePage, buttons are not appearing.

http://www.sspaste.com/paste/show/518e3dc335c85 . (See first comment for relation between my DataObject and HomePage).

Thanks

@tractorcow
Collaborator

I'd really like to get this feature formalised and, at the very least, put into some kind of tutorial that others can follow to add custom actions. I see the lack of core support for DataObject::getCMSActions() to be an oversight. It's a common use case which shouldn't require that much custom code to get working.

@xini

+1 too ;)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jun 13, 2012
  1. Add check for getCMSActions() on record. If exists (and object in DB)…

    Morven authored
    … use that instead of default actions.
    
    Add doPublish() method as well, to provide support for Versioned extension on DataObjects
  2. Add basic unpublish support

    Morven authored
Commits on Jun 23, 2012
  1. @mlewis-everley
Commits on Jul 2, 2012
  1. Update gridfield to use Getters and Setters for form actions

    morven authored
    Remove publish and unpublish methods, as these can be added via an extension or subclass
    Add getters and setters that can be manipulated after creating a new GridFieldDetailFrom()
Commits on Jul 5, 2012
  1. @mlewis-everley
This page is out of date. Refresh to see the latest.
Showing with 62 additions and 5 deletions.
  1. +62 −5 forms/gridfield/GridFieldDetailForm.php
View
67 forms/gridfield/GridFieldDetailForm.php
@@ -27,6 +27,11 @@ class GridFieldDetailForm implements GridField_URLHandler {
* @var Validator The form validator used for both add and edit fields.
*/
protected $validator;
+
+ /**
+ * @var FieldList
+ */
+ protected $formActions;
/**
* @var String
@@ -57,6 +62,7 @@ function getURLHandlers($gridField) {
*/
public function __construct($name = 'DetailForm') {
$this->name = $name;
+ $this->formActions = new FieldList();
}
/**
@@ -78,10 +84,29 @@ public function handleItem($gridField, $request) {
$handler = Object::create($class, $gridField, $this, $record, $controller, $this->name);
$handler->setTemplate($this->template);
+ $handler->setFormActions($this->getFormActions());
return $handler->handleRequest($request, DataModel::inst());
}
+ /**
+ * Set the actions to be used in ItemEditForm
+ *
+ * @param FieldList $actions
+ * @return FieldList
+ */
+ function setFormActions(FieldList $actions) {
+ $this->formActions = $actions;
+ return $this;
+ }
+
+ /**
+ * @return FieldList
+ */
+ function getFormActions() {
+ return $this->formActions;
+ }
+
/**
* @param String
*/
@@ -138,7 +163,7 @@ public function setItemRequestClass($class) {
/**
* @return String
*/
- public function getItemRequestClass() {
+ public function getItemRequestClass() {
if($this->itemRequestClass) {
return $this->itemRequestClass;
} else if(ClassInfo::exists(get_class($this) . "_ItemRequest")) {
@@ -200,6 +225,12 @@ class GridFieldDetailForm_ItemRequest extends RequestHandler {
*/
protected $template = 'GridFieldItemEditView';
+ /**
+ *
+ * @var FieldList
+ */
+ protected $formActions;
+
static $url_handlers = array(
'$Action!' => '$Action',
'' => 'edit',
@@ -289,10 +320,18 @@ function ItemEditForm() {
$actions = new FieldList();
if($this->record->ID !== 0) {
- $actions->push(FormAction::create('doSave', _t('GridFieldDetailForm.Save', 'Save'))
- ->setUseButtonTag(true)->addExtraClass('ss-ui-action-constructive')->setAttribute('data-icon', 'accept'));
- $actions->push(FormAction::create('doDelete', _t('GridFieldDetailForm.Delete', 'Delete'))
- ->addExtraClass('ss-ui-action-destructive'));
+ // Add check to see if record is providing its own actions.
+ // If not, fall back to default.
+ // Currently custom methods for manipulating data need to be
+ // added to this class via Object::add_extension();
+ if(!$this->getFormActions()->exists()) {
+ $actions->push(FormAction::create('doSave', _t('GridFieldDetailForm.Save', 'Save'))
+ ->setUseButtonTag(true)->addExtraClass('ss-ui-action-constructive')->setAttribute('data-icon', 'accept'));
+ $actions->push(FormAction::create('doDelete', _t('GridFieldDetailForm.Delete', 'Delete'))
+ ->addExtraClass('ss-ui-action-destructive'));
+ } else {
+ $actions->merge($this->getFormActions());
+ }
}else{ // adding new record
//Change the Save label to 'Create'
$actions->push(FormAction::create('doSave', _t('GridFieldDetailForm.Create', 'Create'))
@@ -409,6 +448,24 @@ function doDelete($data, $form) {
return $controller->redirect($noActionURL, 302); //redirect back to admin section
}
+
+ /**
+ * Set the actions to be used in ItemEditForm
+ *
+ * @param FieldList $actions
+ * @return FieldList
+ */
+ function setFormActions(FieldList $actions) {
+ $this->formActions = $actions;
+ return $this;
+ }
+
+ /**
+ * @return FieldList
+ */
+ function getFormActions() {
+ return $this->formActions;
+ }
/**
* @param String
Something went wrong with that request. Please try again.