Skip to main content

This site requires you to update your browser. Your browsing experience maybe affected by not having the most up to date version.

We've moved the forum!

Please use forum.silverstripe.org for any new questions (announcement).
The forum archive will stick around, but will be read only.

You can also use our Slack channel or StackOverflow to ask for help.
Check out our community overview for more options to contribute.

DataObjectManager Module /

Discuss the DataObjectManager module, and the related ImageGallery module.

Moderators: martimiz, UncleCheese, Sean, Ed, biapar, Willr, Ingo, swaiba

New Stuff!


Go to End


17 Posts   5485 Views

Avatar
UncleCheese

Forum Moderator, 4102 Posts

23 November 2009 at 4:33pm

Edited: 03/12/2009 11:19am

Just checked in a bunch of new stuff:

Custom DOM Actions

A lot of people have been asking about how to create a custom action on the list view of a DOM in addition to edit, delete, and recently, duplicate. In the following example, I'll show you how to add a custom action to a Listing object that sets its status to "Approved" or "Unapproved" by clicking an an icon in the DOM, without having to edit the record in the popup.

Listing.php

	public function customDOMActions()
	{
		$title = $this->Approved ? "Disapprove" : "Approve";
		$image = $this->Approved ? "delete.png" : "accept.png";

		return new DataObjectManagerAction(
			$title,
			"/ListingPage_Controller/approve/$this->ID",
			"refresh",
			"/mysite/images/$image"
		);
	}

	public function toggleApproved()
	{
		if($this->getField('Approved') == 1)
			$this->setField('Approved',0);
		else
			$this->setField('Approved',1);
		$this->write();
		
	}
	

We create a function with the name "customDOMActions" in the DataObject. The name of this function is compulsory. If you have multiple custom actions, you can return them in a DataObjectSet. The arguments for a DataObjectManagerAction are as follows:

$title : The title of the action. In this case, "approve" or "disapprove"
$link : Link to the action. We'll handle the request on the ListingPage controller
$behaviour : Options for the behavior of this action:

- "refresh" : Runs the action and refreshes the DOM on success.
- "popup" : Load the link into a popup window (like edit view)
- "delete" : Remove the record from the DOM after executing the link

$icon : URL to the icon for the action

In the function toggleApprove we run a simple update that toggles the object status.

Now we'll handle the custom action request in a custom controller.

Listing_Controller

class Listing_Controller extends Controller {
	static $url_handlers = array(
		'approve/$ID' => 'handleApprove'
	);

	public function handleApprove($request)
	{
		if($listing = DataObject::get_by_id("Listing",$request->param('ID'))) {
			$listing->toggleApproved();
		}
	}
}

That's it! You can now click the approve/disapprove icon in your list view to update the record without instantiating a popup. There are many other applications for this feature. This is just one of many possibilities.

Many thanks to forum member Nick Jacobs for sponsoring this feature.

New Popup Form Styling

Updated CSS of the DOM popup to place the pagination and save button in a fixed position at the bottom of the frame, so they are always visible regardless of your scroll. Also add a transparent PNG to help ease the bottom of the viewport and bring some definition to the actions bar against the fieldset.

Bug Fix: DOM Items Lose Sort in Popup Pagination

Fixed this issue. You can now act on the DOM sort or pagination and the records retain their order when paginated in the popup with the prev/next buttons.

Avatar
bummzack

Community Member, 904 Posts

25 November 2009 at 7:20am

Hi UncleCheese

Thanks a lot for these great new features. I think the Custom DOM Actions are especially useful.

I tested this and found the following issues:
Your example code didn't work for me. I had to remove the slashes before the action link and the image.

return new DataObjectManagerAction(
	$title,
	"ListingPageController/approve/$this->ID",
	'refresh',
	"site/images/$image"
);

There's also a potential security risk in your example code.
When somebody uses your example, it becomes possible to alter DataObjects without being logged in to the CMS. This by simply visiting an address like this:
http://somedomain.xx/ListingPage_Controller/approve/2

This would approve the Listing DataObject with ID 2, and doesn't require a login!
I'm aware that this kind of URL is probably pretty hard to figure out, but as soon as somebody posts some example code here, his site can be modified this way.

So to anybody who wants to use this feature, secure the access to your method(s) by putting something like this in your Controller class:

static $allowed_actions = array(
	'handleApprove' => 'CMSMain'
);

Access to the 'handleApprove' method will then only be granted if the current user has access to "CMSMain" (Site Content).
If you got actions like "rss" for RSS Feeds and the like, add them to the array of allowed actions, without access constraint:

static $allowed_actions = array(
	'rss',
	'myPublicAction',
	'handleApprove' => 'CMSMain'
);

This just as a notice/warning to anybody who wishes to use these features.
And thanks to UncleCheese for providing us with these nice updates ;)
Way to go.

Avatar
UncleCheese

Forum Moderator, 4102 Posts

25 November 2009 at 7:53am

Thanks, Banal. Yeah, I coded that up pretty quickly, and I wasn't thinking. Thanks very much for pointing that out. It's so easy to forget that just because a URL is usually called from the CMS doesn't mean it has to be.

Glad you like everything. I think this will get a lot of use.

Avatar
vancouverWill

Community Member, 121 Posts

25 November 2009 at 10:30am

once again, congratulations Uncle Cheese. great addition. how would I go about putting a header on to the top of the table so that can people can tell straight away that that is the approve column without having to hover over it? Thanks

Will

Avatar
UncleCheese

Forum Moderator, 4102 Posts

25 November 2009 at 10:38am

Yeah, good point. It isn't really set up to do that right now. The other buttons -- edit, delete do not have a header. They rely on definitive icons to state their purpose. If you omit the icon argument, the text "Approve" will display, and that will be clearer to the user.

Avatar
vancouverWill

Community Member, 121 Posts

25 November 2009 at 11:10am

Edited: 25/11/2009 11:11am

How do you combine it in to a dataobjectset

First I tried this which I guess wasn't really the point but I thought I'd give it a try

public function customDOMActions()
   {
      $title = $this->Approved ? "Disapprove" : "Approve";
      $image = $this->Approved ? "disapprove.png" : "approve.png";
	  
		$featuredTitle = $this->IsFeaturedProject ? "Disable Featured" : "Make Featured";
		$featuredImage = $this->IsFeaturedProject ? "disapprove.png" : "approve.png";

      return new DataObjectManagerAction(
         $title,
         "/ProjectPage_Controller/approve/$this->ID",
         "refresh",
         "/assets/graphics/$image"
      );
	  
	  return new DataObjectManagerAction(
         $featuredTitle,
         "/ProjectPage_Controller/feature/$this->ID",
         "refresh",
         "/assets/graphics/$featuredImage"
      );
   } 

then I tried this

 public function customDOMActions()
   {
      $title = $this->Approved ? "Disapprove" : "Approve";
      $image = $this->Approved ? "disapprove.png" : "approve.png";
	  
		$featuredTitle = $this->IsFeaturedProject ? "Disable Featured" : "Make Featured";
		$featuredImage = $this->IsFeaturedProject ? "disapprove.png" : "approve.png";
	
	$collection = new DataObjectSet;
	
	$collection = ((
      new DataObjectManagerAction(
         $title,
         "/ProjectPage_Controller/approve/$this->ID",
         "refresh",
         "/assets/graphics/$image"
      )),(
	  
	  new DataObjectManagerAction(
         $featuredTitle,
         "/ProjectPage_Controller/feature/$this->ID",
         "refresh",
         "/assets/graphics/$featuredImage"
      )));
	  
	  return $collection;
   }

They both work seperately so I was hoping it is an easy fix to combine them together. I had a look on the dataobjectset page but couldn't see how to add them together. Thanks again

Avatar
vancouverWill

Community Member, 121 Posts

25 November 2009 at 11:17am

Edited: 25/11/2009 11:48am

Had a look a bit further and I found the easy fix

public function customDOMActions()
   {
      $title = $this->Approved ? "Disapprove" : "Approve";
      $image = $this->Approved ? "disapprove.png" : "approve.png";
	  
		$featuredTitle = $this->IsFeaturedProject ? "Disable Featured" : "Make Featured";
		$featuredImage = $this->IsFeaturedProject ? "disapprove.png" : "approve.png";
	
	$collection = new DataObjectSet();
	
	$collection->push(
      new DataObjectManagerAction(
         $title,
         "/ProjectPage_Controller/approve/$this->ID",
         "refresh",
         "/assets/graphics/$image"
      ));
	  
	$collection->push(  
		new DataObjectManagerAction(
         $featuredTitle,
         "/ProjectPage_Controller/feature/$this->ID",
         "refresh",
         "/assets/graphics/$featuredImage"
      ));
	  
	  return $collection;
   }

worked just as I hope. Thanks UncleCheese

edit: I guess the key lines I was looking for were

  $collection = new DataObjectSet();
   
   $collection->push( 

if that helps anyone else hope that is useful.

Avatar
UncleCheese

Forum Moderator, 4102 Posts

25 November 2009 at 12:17pm

Yup. You got it. You can also do:

new DataObjectSet(
new DataObjectManagerAction(),
new DataObjectManagerAction()
);

Go to Top