Support exporting/importing revisions

Created on 16 February 2024, about 1 year ago

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

Patch, review, commit, release.

User interface changes

None.

API changes

None. Actually, the submodule should be possible using the already-existing API.

Data model changes

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

✨ Feature request
Status

Active

Version

1.4

Component

Code

Created by

πŸ‡­πŸ‡ΊHungary boobaa

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Merge Requests

Comments & Activities

  • Issue created by @boobaa
  • Status changed to Needs review about 1 year ago
  • πŸ‡­πŸ‡ΊHungary boobaa

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

  • Assigned to Rangaswini
  • Issue was unassigned.
  • 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.

  • πŸ‡ΊπŸ‡¦Ukraine abramm Lutsk

    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!

  • Status changed to Needs work about 1 year ago
  • πŸ‡ΊπŸ‡¦Ukraine abramm Lutsk
  • 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

  • Merge request !117Support exporting/importing revisions β†’ (Open) created by boobaa
  • Pipeline finished with Success
    5 months ago
    Total: 203s
    #298821
  • πŸ‡­πŸ‡ΊHungary boobaa

    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.

  • πŸ‡­πŸ‡ΊHungary boobaa
  • πŸ‡­πŸ‡ΊHungary mxr576 Hungary

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

  • πŸ‡­πŸ‡ΊHungary mxr576 Hungary

    Tests to be written in a later phase.

    But still in this issue, am I right?

  • πŸ‡­πŸ‡ΊHungary mxr576 Hungary
  • πŸ‡­πŸ‡ΊHungary boobaa

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

  • Pipeline finished with Success
    4 months ago
    #309232
  • Status changed to Needs review about 2 months ago
  • πŸ‡§πŸ‡ͺBelgium ludo.r Brussels

    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.

  • πŸ‡­πŸ‡ΊHungary mxr576 Hungary

    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)

  • πŸ‡­πŸ‡ΊHungary mxr576 Hungary
Production build 0.71.5 2024