Problem/Motivation

lingotek_entity_insert() causes the entity being inserted to be resaved. This then fires update hooks before all the insert hooks have finished firing. All a client site this is resulting in duplicate entries in the url_alias table. Pathauto has a module weight of 1 whilst lingotek has a 0. This guarantees the lingotek hook fires before pathautos.

Proposed resolution

One solution would be to use hook_module_implements_alter and guarantee this comes last. But it is not a good solution. Re-saving the entity during an insert is a pretty tricky thing to do reliably when other modules can come in and do all sorts.

Remaining tasks

User interface changes

API changes

Data model changes

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

alexpott created an issue. See original summary.

alexpott’s picture

lingotek_entity_update() will have the same problem - resaving an entity during it own save events is not robust.

alexpott’s picture

I think some of the logic should move to a presave - i.e the calculation of of the hash. And then you just need to compare the original value with the new value.

alexpott’s picture

Priority: Major » Critical

Actually this is a critical bug for this module as it is likely to not make it inter-operable with many modules. Update hooks firing before insert hooks is very surprising :)

alexpott’s picture

I think this patch should fail because \Drupal\lingotek\LingotekContentTranslationService::hasEntityChanged is not quite right yet - it needs to account for the presave change.

Status: Needs review » Needs work

The last submitted patch, 5: 2781625.5.patch, failed testing.

The last submitted patch, 5: 2781625.5.patch, failed testing.

The last submitted patch, 5: 2781625.5.patch, failed testing.

alexpott’s picture

Status: Needs review » Needs work

The last submitted patch, 9: 2781625.9.patch, failed testing.

The last submitted patch, 9: 2781625.9.patch, failed testing.

The last submitted patch, 9: 2781625.9.patch, failed testing.

alexpott’s picture

The other option here is to try and not save the hash on the content entity. Given the changes content_moderation might bring to core that might be a desirable route. We could just use $entity->original and $entity during hook_entity_insert and hook_entity_update to work out if there is anything to do. That should work in those cases - I'm not 100% certain about the other cases where the hash is used.

alexpott’s picture

Status: Needs review » Needs work

The last submitted patch, 14: 2782085.14.patch, failed testing.

The last submitted patch, 14: 2782085.14.patch, failed testing.

The last submitted patch, 14: 2782085.14.patch, failed testing.

alexpott’s picture

alexpott’s picture

+++ b/lingotek.module
@@ -33,6 +33,32 @@ function lingotek_toolbar() {
+  // Make sure lingotek_entity_presave() comes last.
+  switch ($hook) {
+    // Move our hook_entity_type_alter() implementation to the end of the list.
+    case 'entity_presave':
+      $group = $implementations['lingotek'];
+      unset($implementations['lingotek']);
+      $implementations['lingotek'] = $group;
+      break;
+  }

This is not great but if we're going to save the hash to content entity probably the best option because it won't result in double saves.

penyaskito’s picture

Thanks so much Alex for working on this!

+++ b/lingotek.module
@@ -89,7 +115,8 @@ function lingotek_entity_insert(EntityInterface $entity) {
+      // Entity inserts are always changes.
+      $entity_has_changed = TRUE;

For Lingotek translation purposes, if the changed fields are not configured to be translated with lingotek, we want to avoid uploading it again.

penyaskito’s picture

Status: Needs review » Needs work

The last submitted patch, 21: 2781625-21.patch, failed testing.

The last submitted patch, 21: 2781625-21.patch, failed testing.

The last submitted patch, 21: 2781625-21.patch, failed testing.

penyaskito’s picture

OH, stupid me. Insert is insert and will be the first upload, so @alexpott was right.

penyaskito’s picture

Status: Needs work » Reviewed & tested by the community

Have been talking to Alex on IRC about #13. The naming is a bit poor, but hasChanged() not only checks if there are changes on the entity while it's been saved, but also we consider it changed even if there are no changes to the entity, but to the fields set to be uploaded. So we cannot rely on $entity->original for that, unless we track when the config changed.
This could be another hard problem and can have other complications.

For now let's commit #18, and will explore soon having a different entity for metadata (as we do with configuration entities actually). That's a re-architecture change that can be made back-compatible, and worth a try as it could help simplifying how we handle revisions too.

RTBCing #18.

penyaskito’s picture

penyaskito’s picture

Title: lingotek_entity_insert() is highly problematic » Avoid entity saves in lingotek_entity_insert(), as it can be highly problematic

  • penyaskito committed 46d6f61 on 8.x-1.x authored by alexpott
    Issue #2781625 by alexpott: Avoid entity saves in lingotek_entity_insert...
penyaskito’s picture

Status: Reviewed & tested by the community » Fixed

Committed 46d6f61 and pushed to 8.x-1.x. Thanks!

azinck’s picture

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.