Problem/Motivation
If a content entity containing a viewsreference field has been created on v2.0-beta8 or earlier, trying to translate it on v2.0-beta9 or later will not work and produces the "Non-translatable fields can only be changed when updating the original language" error.
In my case, this happens with a translatable node containing an untranslatable reference to a translatable paragraph which has an untranslatable viewsreference field, but it seems likely this will also happen if the viewsreference field exists directly on a node.
Details
The viewsreference module uses a custom class (ViewsReferenceFieldItemList) for handling field item lists on forms. When updating an entity which contains a viewsreference field, the 'equals' method in that class is used to determine whether the field value has changed from the previous value. Even when a viewsreference field is marked untranslatable, that class is still comparing the field value of the source language entity to the field value in the translation being created.
In the case of viewreference, the compared values are objects containing the settings for the chosen view reference. The settings include a serialized field, 'data', which holds the "extra settings" which can be enabled in the field configuration:
- Pagination
- Argument
- Limit results
- Offset results
- Hide header
- Include View Title
When the entity has been created on beta8 or earlier, the serialized data in the source translation will not contain the 'header' key, as the "Hide header" option was added as a part of issue #3427005, released in beta9.
After upgrading to beta9 or later, the serialized data for the translation being created will contain the 'header' key, which leads to ViewsReferenceFieldItemList considering the source and translation fields unequal, which will cause EntityUntranslatableFieldsConstraint to kick in and prevent saving the entity.
Steps to reproduce
- Install 2.0-beta8
- In a translatable but untranslated node (the source language), add a translatable paragraph which contains an untranslatable viewsreference field
- Save the node
- Upgrade to 2.0-beta9 or 2.0-beta10
- Attempt to translate the node and observe that it's not possible
Workaround
Make some change in the source entity and save it (and undo your change and save it a second time).
This will re-create the serialized data stored in the field item.
After that, translation will work again.
Proposed resolution
The serialized data contains keys for all the extra settings even when no extra settings are enabled, which is probably how it needs to be: otherwise enabling a setting after content is already created would create this same issue.
One solution would be using module update hooks to recreate existing field item data whenever there is a change in the available settings.
Maybe a better one would be to change how ViewsReferenceFieldItemList::equals handles the comparison. It would need to disregard missing keys on either side of the comparison, but at the same time, enforce that keys found on both sides have the same values.
Issue fork viewsreference-3542448
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
Comment #3
marttir commentedQuick patch. Probably doesn't work right if items in a multi-value field are added/removed.
Comment #4
marttir commentedNote: test failures are not related to the changes done here.
Comment #6
scott_euser commentedThanks for the contribution! This sounds like it might be better as a update hook instead? Though I have not looked deeply at the cause.
For now I rebased latest into your MR since tests past on latest at the moment
Comment #7
scott_euser commentedWill set to Needs Work per your comment in #3 in any case, but my guess is update hook is probably the way to go instead
Comment #8
marttir commentedThinking about this further, I think the comparison does work for multi-value fields, since what's being compared is the entire field value at once, and not e.g. pairs of items. So e.g. adding new field items, removing some, or changing the order would still be detected as unequal even before the code hits the part where it checks the serialized data.
There are some reasons to favor changing the comparison over adding an update hook:
So going the update hook route would increase the maintenance burden and potentially slow down deployments where the update runs. Also, there would still be the possibility of forgetting to create the hook and ending up in the same situation again.