Problem/Motivation

Only the default revision gets exported. It should be possible to export (and import) all revisions.

Steps to reproduce

  • Create a node with multiple revisions.
  • Export the node.

Expected behavior: with revisioning support enabled, all revisions should be exported.

Actual behavior: there's no revisioning support, therefore only the default revision gets exported.

Proposed resolution

Add a submodule that also exports revisions, so it's easy to enable/disable revisioning support as needed.

Remaining tasks

Review, merge, release. Possibly contemplate upon the impossibility of properly exporting/importing paragraphs.

User interface changes

None.

API changes

None. Actually, the submodule is possible by using the already-existing API.

Data model changes

Just like with translations, there should be a revisions entry in the exported YAML.

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

Boobaa created an issue. See original summary.

boobaa’s picture

Issue summary: View changes
Status: Active » Needs review
StatusFileSize
new6.72 KB

The attached patch adds a single_content_sync_revisions submodule, which adds this feature.

Rangaswini’s picture

Assigned: Unassigned » Rangaswini
Rangaswini’s picture

Assigned: Rangaswini » Unassigned
StatusFileSize
new99.13 KB
new89.57 KB
new1.5 MB
new3.8 MB

Reviewed patch #2 and works fine with version 1.4. Please refer screenshot
Step:
Created a node with multiple revisions.
Exported the node.
Result: All revisions are exported now.

abramm’s picture

Hi Boobaa,

Thank you for your effort!
A few thoughts here.

1) We definitely don't want to have accessCheck(FALSE). The current user may not have permissions to view all revisions; this code will give them read access. This is a security/data disclosure issue.

2) The core version requirement should be core_version_requirement: ^9.3 || ^10, same as in root info.yml.

3) The following line will produce a warning if there are no revisions in YML file:
if ($content['revisions']) {

4) The revision creation time should be import/exported the same way we do for created/changed timestamps.

5) We'd likely need a test for this; also, please create the merge request to run automated tests.

Thanks!

abramm’s picture

Status: Needs review » Needs work
nitish kumar pandey’s picture

Hi,
I have tried to using this patch it is getting exported with revision but as I a paragraph field when i am import it i am getting as
Call to undefined method Drupal\paragraphs\Entity\Paragraph::setRevisionCreationTime() in Drupal\single_content_sync_revisions\ImportSubscriber->onImportEvent() (line 52 )... please look to this issue as well

boobaa’s picture

Issue summary: View changes

1) We definitely don't want to have accessCheck(FALSE).

Fixed.

2) The core version requirement should be core_version_requirement: ^9.3 || ^10, same as in root info.yml.

Fixed.

3) The following line will produce a warning if there are no revisions in YML file:
if ($content['revisions']) {

Fixed.

4) The revision creation time should be import/exported the same way we do for created/changed timestamps.

The revision creation time is imported the same way it is done for the created/changed timestamps: although the exported zip only contain the created data, the current timestamp is used during the import. Changed timestamps are completely ignored, even during export. Please refer to ContentImporter::doImport().

5) We'd likely need a test for this; also, please create the merge request to run automated tests.

Tests to be written in a later phase.

I have tried to using this patch it is getting exported with revision but as I a paragraph field when i am import it i am getting as
Call to undefined method Drupal\paragraphs\Entity\Paragraph::setRevisionCreationTime() in Drupal\single_content_sync_revisions\ImportSubscriber->onImportEvent() (line 52 )...

Thank you for reporting this; turns out Paragraph entities do not have proper revisioning support: as Paragraph items are referenced not only by their entity ID, but also their revision ID, and revisions do not have UUIDs, there is no way to properly import references to Paragraphs' revisions. Because of that, even exporting Paragraph revisions is useless.

Note this also means that the parent entity (eg. node) might have its revisions exported, but ALL those revisions would have the same content in the paragraph fields' revisions: the one belonging to the latest revision. Other, non-paragraph fields of the parent have proper revisioned content.

Therefore the MR just skips Paragraph revisions, even during export.

boobaa’s picture

Status: Needs work » Needs review
mxr576’s picture

(It looks like UUID vs revisioning supported is tracked under this Drupal core issue: #1812202: Add UUID support for entity revisions. Bumped that with a quote from comment 9.)

mxr576’s picture

Issue tags: +Needs tests

Tests to be written in a later phase.

But still in this issue, am I right?

mxr576’s picture

Status: Needs review » Needs work
boobaa’s picture

Status: Needs work » Needs review

All concerns from @mxr576 have been addressed and the MR got updated accordingly.

ludo.r’s picture

I have a content type with 150+ custom fields and some nodes that have dozens of revisions.
When loading revisions when exporting, this causes memory issues and also a long time to export.

Changing this (in modules/single_content_sync_revisions/src/ExportSubscriber.php):

      // Second step is exporting those revisions.
      /** @var \Drupal\Core\Entity\ContentEntityInterface $revision */
      foreach ($storage->loadMultipleRevisions($revision_ids) as $revision) {

to:

      // Second step is exporting those revisions.
      foreach ($revision_ids as $revision_id) {
        /** @var \Drupal\Core\Entity\ContentEntityInterface $revision */
        $revision = $storage->loadRevision($revision_id);

solves the memory issues and makes the process much faster.

mxr576’s picture

Good catch and regular issue, although the fix leads to the infamous N+1 problem of ORMs

I would rather recommend implementing something like I did in an other module, load multiple with a maximum amount:

https://git.drupalcode.org/project/view_usernames_node_author/-/blob/1.0...

(tricks like this is necessary until a stable solution lands in Core for #2577417: Add an entity iterator to load entities in chunks)

mxr576’s picture

Status: Needs review » Needs work
aaronchristian’s picture

I just realized there is a sub-module now for this called single_content_sync_revisions.

arno_vgh made their first commit to this issue’s fork.

mr.york made their first commit to this issue’s fork.