Problem/Motivation

This is a follow-up from #2837022: Concurrently editing two translations of a node may result in data loss for non-translatable fields and detected thanks to the manual testing done by @matsbla so please make sure that he receives credit on this issue.

The problem found in #41 @matsbla is that content_translation allows for making only specific field properties translatable or not translatable and syncs the non-translatable properties in hook_entity_presave(), which means content_translation will be updating a field after the check for changes by ChangedItem::preSave() has run. This makes it impossible to update the changed timestamp, because the entity field preSave method is invoked before the entity presave hooks.

Proposed resolution

Invoke ChangedFieldItemList::preSave() once again after all the presave process has run to detect all changes that have been made during the presave process.

Remaining tasks

User interface changes

API changes

Data model changes

Comments

hchonov created an issue. See original summary.

hchonov’s picture

StatusFileSize
new1.43 KB
hchonov’s picture

StatusFileSize
new2.49 KB
new4.41 KB
hchonov’s picture

Issue tags: -Needs tests
drumm’s picture

Issue tags: -Drupalcon Vienna 2017

Updating to the canonical tag for DrupalCon Vienna 2017.

The last submitted patch, 3: 2912318-3-FAIL.patch, failed testing. View results

matsbla’s picture

@hchonov, thanks for working on this patch! I did some manual testings now and looks like it solves the problem, great work =)

charlotte.b’s picture

I'm current working on testing this with @joycelam at DrupalCon Vienna 2017

charlotte.b’s picture

Because this is a follow up issue to https://www.drupal.org/node/2837022, I followed the steps in comment https://www.drupal.org/node/2837022#comment-12203105

Full steps:

- Activated language and content translation modules
- Added a second language (French)
- Go to content language settings page
- Select Content and select a content type
- Hit save configuration
- Go to the content type configured above and add a new image field
- Edit the field and Deselect file under translatable elements
- Created a new content page with an image for English
- Added a translation for French
- Both of the translations have the new image
- I edited both translations at the same time, updating the image for one

Both translations ended up with the same image, so I wasn't able to replicate the issue in https://www.drupal.org/node/2837022#comment-12203105 however the updated time only changed for the first translation and after applying the patch, both of the updated times are successfully updated. Can you please confirm that this bug is just to fix the updated time and not the issue referred to in the comment?

I have been working on this with my mentor @sugaroverflow please let me know if there are other steps I need to take to replicate this issue.

matsbla’s picture

hi charlotte, thanks for testing this! :)

> I wasn't able to replicate the issue in https://www.drupal.org/node/2837022#comment-12203105

So does it mean that when you follow the steps described there you get a lock? or what happens?

when I test with this patch I get a lock also when untranslatable image files are updated avoiding that they will be updated concurrently (which shold not happen). The correct updated time helps fire the lock.

hchonov’s picture

Reply to #9

however the updated time only changed for the first translation and after applying the patch, both of the updated times are successfully updated

I am glad to hear this :). We already have a failing test demonstrating this in a similar manner.

Can you please confirm that this bug is just to fix the updated time and not the issue referred to in the comment?

Yes, I confirm that the issue here is for properly updating the changed timestamp when an entity is being updated in a presave entity hook.

I have been working on this with my mentor @sugaroverflow please let me know if there are other steps I need to take to replicate this issue.

I think that the steps you've performed are enough as they are testing exactly the issue.

charlotte.b’s picture

@matsbla before applying the patch I get a lock with the message (The content has either been modified by another user, or you have already submitted modifications. As a result, your changes cannot be saved.) on the form I press save on last. If the first form has an updated image, then this image is updated for all translations, however only the first translation has the updated time set.

After applying the patch if I repeat the test then I get no lock error if I hit save on the translation with a new image updated first, then quickly hit save on the translation with no updated image. The image doesn't get updated (I would expect it to contain the new image?), but the updated time is set correctly.

It seems there are two different things going on here, @matsbla and @hchonov please can you both confirm if this is what's expected :)

hchonov’s picture

After applying the patch if I repeat the test then I get no lock error if I hit save on the translation with a new image updated first, then quickly hit save on the translation with no updated image. The image doesn't get updated (I would expect it to contain the new image?), but the updated time is set correctly.

It seems there are two different things going on here, @matsbla and @hchonov please can you both confirm if this is what's expected :)

@charlotte.b this looks like a race condition to me. I didn't understand which translations have which image after the save? Do all translations have the image updated on the first translation saved or all have the original image with which the second translation is being saved? I would expect that all translations have the original image, which will confirm the race condition, as in this case because of doing this quickly the second submission retrieves the initial entity instead the one saved in the other tab as the submission from the first tab isn't completely ready yet and therefore the validation could not fail and prevent saving.

Could you please repeat these steps, but not "quickly"? :) I mean wait until the redirect on the first tab has occurred and then save the other translation with the untouched image.

charlotte.b’s picture

@hchonov I just repeated, waiting until the first saves and get the same result, the original image is saved for both translations.

hchonov’s picture

@charlotte.b, thank you for your testing. I've reproduced your steps and found out that the problem that we have here is the one from the other issue - #2837022: Concurrently editing two translations of a node may result in data loss for non-translatable fields. So if you apply the latest patch from the other issue together with the patch from the current issue you'll be prevented from saving the second translation. Could you please confirm that if none of the patches is applied you will be allowed to save the second translation and if both patches are applied you'll be prevented from saving the second translation with the message 'The content has either been modified by another user, or you have already submitted modifications. As a result, your changes cannot be saved.'?

P.S. these are still two independent issues and therefore the current one should not be postponed on the other one.

charlotte.b’s picture

Status: Needs review » Reviewed & tested by the community

@hchonov thank you, I applied the patch from #2837022: Concurrently editing two translations of a node may result in data loss for non-translatable fields and it now successfully locks, applies the first update and updates the timestamps as expected.

I think the other issue was confusing things, but the steps to replicate this issue in isolation are:

- Activated language and content translation modules
- Added a second language (French)
- Go to content language settings page
- Select Content and select a content type
- Hit save configuration
- Go to the content type configured above and add a new image field
- Edit the field and Deselect file under translatable elements
- Created a new content page with an image for English
- Added a translation for French
- Edit a translation and update the image
- The image is successfully saved for all translations but the timestamp is only updated for the translation that was edited

Apply the patch 2912318-3.patch and retest, the timestamp is updated for all translations

hchonov’s picture

Status: Reviewed & tested by the community » Needs review
StatusFileSize
new5.36 KB
new2.27 KB

After I've looked over the patch again I've noticed two things that had to be cleared as well:

1. Iterating over the fields and finding the changed field and then iterating over each entity translation and explicitly retrieving the changed field should be more efficient then iterating over the entity translations and then each time over the fields.
2. In order to be consistent with \Drupal\Core\Entity\ContentEntityStorageBase::invokeFieldMethod() we have to invoke the field presave method first on the current translation and then on any other translations.

The patch should still be green, but since I've changed the patch I am putting the status back again to "Needs review".

charlotte.b’s picture

Status: Needs review » Reviewed & tested by the community

Retested with patch 2912318-17_0.patch and all works as expected :)

catch’s picture

Status: Reviewed & tested by the community » Needs review

hmm I think I prefer the approach in #2617628: ChangedItem will not detect a change if another field item changes its value in field::preSave which ensures that ChangedItem runs last - that seems more obvious than having it run twice?

hchonov’s picture

@catch, it runs as the last item during field presave, but still does not cover the changes made in hook_entity_presave, because the hook is invoked after the field presave. Ideally we would let it run only once, but it will be a BC break to remove the field presave method as currently if changes in fields are found during field presave the updated changed timestamp will be available in the hook_entity_presave. In order not to break BC we have to support -

  1. Current behaviour - the changed timestamp is updated after field presave and before hook_entity_presave. We still need #2617628: ChangedItem will not detect a change if another field item changes its value in field::preSave so that it works properly, but the referenced issue is independent of the problem being solved with the new behaviour.
  2. New behaviour - the changed timestamp is updated after hook_entity_presave.

This leaves us only one option and it is to check for changes twice. But this will be not that bad once #2863818: Fix notification issues in the entity/field on-change system is fixed as then it will be really easy to detect if something has changed :).

matsbla’s picture

I tested this patch again now. It solves the problem if two translations are edited concurrently, however the lock is not working if a new translations is added concurrently as another translation is edited (and change the non-translatable image file).

If the new translation is added concurrently, it then reverts the changes made back to the old image file. It still keeps the new image text, so in fact the image text for the new image is now set to the old image file.

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.0-alpha1 will be released the week of January 17, 2018, which means new developments and disruptive changes should now be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.6.x-dev » 8.7.x-dev

Drupal 8.6.0-alpha1 will be released the week of July 16, 2018, which means new developments and disruptive changes should now be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

matsbla’s picture

Issue tags: +data integrity

Version: 8.7.x-dev » 8.8.x-dev

Drupal 8.7.0-alpha1 will be released the week of March 11, 2019, which means new developments and disruptive changes should now be targeted against the 8.8.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.0-alpha1 will be released the week of October 14th, 2019, which means new developments and disruptive changes should now be targeted against the 8.9.x-dev branch. (Any changes to 8.9.x will also be committed to 9.0.x in preparation for Drupal 9’s release, but some changes like significant feature additions will be deferred to 9.1.x.). For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 8.9.x-dev » 9.1.x-dev

Drupal 8.9.0-beta1 was released on March 20, 2020. 8.9.x is the final, long-term support (LTS) minor release of Drupal 8, which means new developments and disruptive changes should now be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

needs-review-queue-bot’s picture

Status: Needs review » Needs work
StatusFileSize
new134 bytes

The Needs Review Queue Bot tested this issue. It either no longer applies to Drupal core, or fails the Drupal core commit checks. Therefore, this issue status is now "Needs work".

Apart from a re-roll or rebase, this issue may need more work to address feedback in the issue or MR comments. To progress an issue, incorporate this feedback as part of the process of updating the issue. This helps other contributors to know what is outstanding.

Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 11.x-dev » main

Drupal core is now using the main branch as the primary development branch. New developments and disruptive changes should now be targeted to the main branch.

Read more in the announcement.