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.

Data Model Questions /

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

Duplicate page should duplicate and link dataobjects


Go to End


14 Posts   7856 Views

Avatar
Nobrainer Web

Community Member, 138 Posts

1 July 2011 at 11:21am

Hi,

I constantly keep running in to this issue.

I like to use DataObjects for lists of items on my pgaes, like images or links.
This works fine, no need for the DataObject Manger Module, just a DO.

Problem is when i duplicate a page (context menu in the CMS), the DataObject "references" gets lost and i'm left with adding all DataObjects manually to my page.

Can someone tell me how to get the DataObjects duplicated aswell? I think this most be something that some of you are using in your projects and i hope you will share some code or help me get it working.

I think it should be a matter of overloading the duplicate() method of the SiteTree class, but i dont know how this is done.
I've read all the threads i could find regarding this matter, closest thing i could find is this post: http://www.silverstripe.org/customising-the-cms/show/11571

Hope that someone can help!

Avatar
Nobrainer Web

Community Member, 138 Posts

1 July 2011 at 11:10pm

Ok willr answerede this question for me in the irq channel.

Adding the following code to the Page class (or what class you need it in) will duplicate page and the specified Dataobjects, and set the relation to the duplicated page.

(This method overloads the duplicate method from SiteTree.php - it's this function that is called when you right click a menu item in the CMS and choose duplicate this page)

/**
* Duplicate this page, and its DataObjects.
*
* @return Page
*/
public function duplicate() {
$page = parent::duplicate();

// the PageImages (name of the has many relation)
if($this->PageImages()) {
foreach($this->PageImages() as $image) {
$newField = $image->duplicate();
$newField->PageID = $page->ID; // Important that this is the ID of the relation to the DO's parent page!
// Can be ParentID, PageID atc. - It's the current class name
$newField->write();
}
}

return $page;
}

Hope this will help someone else to :o)

Thanks for helping willr

Avatar
mco

Community Member, 14 Posts

26 September 2011 at 9:38pm

Edited: 26/09/2011 9:38pm

Thanks for the input. I had an issue with updating a many_many relation. But then instead of doing a copy of the original items linked to the current page, you need to re-link them to the new object. Here is the modified code:

	/**
	 * Duplicate this page and update it's many_many relations
	 * 
	 * @return Page
	 */
	public function duplicate() {
		$page = parent::duplicate();

		if($this->Tags()) {
			$page->Tags()->addMany($this->Tags()->getIdList());
		}

		return $page;
	} 

where Tags is defined as

	static $many_many = array(
		'Tags' => 'Tag'
	);

Avatar
dendeffe

Community Member, 135 Posts

27 September 2011 at 2:34am

This looks great. I was trying to use it on translations, which doesn't use duplicate (as I was thinking). Any idea where I should get started on that?

Avatar
joelg

Community Member, 134 Posts

6 October 2011 at 11:06am

Wonderful informations about duplicating relations. Thanks everybody.

Avatar
mgherkins

Community Member, 8 Posts

6 March 2012 at 11:19am

great, thanks for that one.

this is what i ended up with:

duplicate all has_many and many_many relationships of a page dynamically...:

public function duplicate() {

    $page = parent::duplicate();

    //duplicate has many items
    foreach ($this->has_many() as $key => $className) {
      foreach ($this->{$key}() as $item) {
        $newField = $item->duplicate();
        $id = get_class($this) . 'ID';
        $newField->{$id} = $page->ID;
        $newField->write();
      }
    }
    
    //duplicate many_many items
    foreach( $this->many_many() as $key => $className ){
      $page->{$key}()->addMany($this->{$key}()->getIdList());
    }

    return $page;
  }

cheers

Avatar
Nobrainer Web

Community Member, 138 Posts

6 March 2012 at 8:55pm

Thank you so much for posting this max5k, this has gone in to my SilverStripe package that i put on all new sites.
So usefull!

Avatar
mgherkins

Community Member, 8 Posts

6 March 2012 at 9:19pm

you might want to add a filter, which relations to duplicate
the above version does a little too much in some cases...

public function duplicate() {

    $items_to_duplicate = array(
        'Images'  //anything you want to duplicate
    );

    $page = parent::duplicate();

    //duplicate has many items
    foreach ($this->has_many() as $key => $className) {
      if (in_array($key, $items_to_duplicate)) {
        foreach ($this->{$key}() as $item) {
          $newField = $item->duplicate();
          $id = get_class($this) . 'ID';
          $newField->{$id} = $page->ID;
          $newField->write();
        }
      }
    }

    //duplicate many_many items
    foreach ($this->many_many() as $key => $className) {
      if (in_array($key, $items_to_duplicate)) {
        $page->{$key}()->addMany($this->{$key}()->getIdList());
      }
    }

    return $page;
  }

Go to Top