Coping objects and history

How can I copy objects to another server and keep the history (workflow and edits)?

This will not be easy.
Since ages, Zope's ObjectManager supports export and import of objects. However, because it is so old, is does not know about more modern concepts such as workflow or history. The import builds on methods used for copying -- and one can consider a copied object as a new object. In the following, I speak only about workflow (because I know it well) and not about history (with which I have only limited experience).

The modern component architecture integrates workflow with an object's lifetime via events and subscribers. When you suppress the "copied event", the workflow component would not get informed that it must reset the object's workflow state. However, other components might have registered handlers for the same events (e.g. in order to index new object copies) and when you suppress the events, those other components no longer will get informed.

A solution approach:

  • you look at the implementation of ObjectManager.manage_importObject and derive your own implementation. Yours will almost look like the original but it will notify a specialized event derived from the original one (actually, the events are notified in _setObject - and it is not a single event but a whole family)
  • you determine which subscribers are relevant for your use case (e.g. the subscriber which controls the workflow state) and replace those by your own subscribers which can distinguish between the standard event and your specific import event: your new subscribers do whatever the old one did for a standard event and do whatever you wish for your import event
  • you can remove (global) registration (such as those for subscribers) via z3c.unconfigure
  • in your implementation, you will likely need a minor modification of _setObject (it does everything as the original, but notifies your event). You can avoid a source code copy by using dm.reuse.rebindFunction. dm.reuse has also a "proxy" class which allows you to create a proxy for an object which behaves like the original with minor modifications (e.g. a changed _setObject implementation).

EDIT sorry realised this applies to zope import but you are asking about a zope copy. But a similar patch could be made to work for that too.

We made a plugin that allows you to suppress zope events in import. That should prevent workflow etc being reset but I'm not sure. You might have to do a manual reindex and rebuild if your path changes after the copy however as your index might be using the old path. It's better to import into the same path as the original due to the way the index works.

The "not easy" applies to export/import of selected individual objects. It is easy to transfer a whole Zope instance data set between servers (without changing anything): ensure compatible code versions at source and destination; then copy the ZODB storages.

thanks, i was trying it on 5.2.1 but it did not work.
I figure out the issue I'm having with the content history.
the current workflow is different, so the history is not displayed for that reason. is there a way to modify the .zexp file? if I could just removed copy_of_ from the workflow in the zexp file it should import with the history. (I tried editing the file in pycharm but I get an error if I try to import the modified copy, but I see the history and workflow there)

I believe there is a bug in the portal_workflow where only the history for the current workflow of the object is shown instead of all the history even if it gets remapped. any other version workflow history is still in the object but only displayed if the content type workflow is changed to the previous used workflow.

what is the best way to report this bug? git? which repo?

workflow = getToolByName(context, 'portal_workflow')
review_history = []
review_history = workflow.getInfoFor(context, 'review_history')

if in doubt, always report at Products.CMFPlone

FIXED
We modified WorkflowTool.py in Products.CMFCore to give us the full history