onBeforeDuplicate / onAfterDuplicate question

<%- if @topic_view.topic.tags.present? %>
<%= t 'js.tagging.tags' %>: <%- @topic_view.topic.tags.each do |t| %> <%= t %> <%- end %>
<% end %>

Silverstripe Version: 3.7.3

Question:

I’m a bit confused about how the onBeforeDuplicate / onAfterDuplicate functions are intended to work. If I define these functions on a page object, when the page is duplicated the functions are being called twice:

  • SiteTree.duplicate() calls parent::duplicate(false)
  • DataObject.duplicate() creates the new object and then invokes onBeforeDuplicate() and onAfterDuplicate() on the clone, with the original record as the argument
  • SiteTree.duplicate() then invokes onBeforeDuplicate() on the original record, with the clone as the argument, then writes the record to the database, then calls onAfterDuplicate() in the same way.

For example, say I have these functions in my page class:

public function onBeforeDuplicate($arg) {
    SS_Log::log('onBeforeDuplicate called: ' . $this->ID . ', ' . $arg->ID, SS_Log::DEBUG);
}
public function onAfterDuplicate($arg) {
    SS_Log::log('onAfterDuplicate called: ' . $this->ID . ', ' . $arg->ID, SS_Log::DEBUG);
}

When I duplicate the page I see this in my logs:

DEBUG at framework/core/Object.php line 1031: onBeforeDuplicate called: 0, 500
DEBUG at framework/core/Object.php line 1031: onAfterDuplicate called: 0, 500
DEBUG at framework/core/Object.php line 1031: onBeforeDuplicate called: 500, 0
DEBUG at framework/core/Object.php line 1031: onAfterDuplicate called: 500, 501

Is it meant to work this way? I want to add some code that runs when a page is duplicated, but I don’t want it to run twice - and I need to know whether $this is the original record of the clone. The only way I can think to make this work at the moment is to check if $this->ID === 0. Is there a better way?

Thanks.