Problem/Motivation
Take the following two steps to reproduce the bug.
A1. Install Drupal in English.
A2. Install Language module.
A3. Install Content translation module.
A4. On admin/config/development/configuration/single/export
export language.types
.
B1. Install Drupal in English.
B2. Install Content translation module (it will automatically install Language module as a dependency).
B3. On admin/config/development/configuration/single/export
export language.types
.
You would expect to get the same output, right? No! In the first case, you get this (good) snippet as part of the export:
negotiation:
language_content:
enabled:
language-interface: 0
In the second case, you get the URL method enabled only:
negotiation:
language_content:
enabled:
language-url: 0
(Note the 0 is the weight of the method in both cases).
But you did not do anything other than installing modules slightly differently. Why does this happen?
function content_translation_install() {
// ...
\Drupal::service('language_negotiator')->saveConfiguration(LanguageInterface::TYPE_CONTENT, array(LanguageNegotiationUrl::METHOD_ID => 0));
}
This code is silly, it should leave the default shipped config alone. The default shipped config is good. Why is it that this only happens in interaction B? Well, language module and content translation are enabled in the same request, so this code does not kick in and leaves the updated (locked) content translation method intact:
/**
* Implements hook_modules_installed().
*/
function language_modules_installed($modules) {
if (!in_array('language', $modules)) {
$negotiator = \Drupal::service('language_negotiator');
$negotiator->updateConfiguration(array());
$negotiator->purgeConfiguration();
}
// ...
}
In case A, when content translation enabled, this code kicks in and rewrites the config based on the locked value.
Proposed resolution
Do not modify the configuration for a non-configurable language type in content translation. Fix the tests assuming the old behavior.
Remaining tasks
Commit.
User interface changes
None.
API changes
None.
Comment | File | Size | Author |
---|---|---|---|
#28 | interdiff.txt | 6.68 KB | Wim Leers |
#28 | 2424171-dont-update-locked-28.patch | 6.65 KB | Wim Leers |
#20 | diff-18-20.txt | 1.26 KB | victor-shelepen |
#20 | 2424171-dont-update-locked-20.patch | 3.32 KB | victor-shelepen |
#18 | diff-5-18.txt | 1.16 KB | victor-shelepen |
Comments
Comment #1
Gábor HojtsyWell, the bug is due to this hook, which rebuilds the config IF language module was not among the ones enabled, and resets it to defaults (updateConfiguration() checks for locked state and resets the locked ones to where they should be). When you enable language module with content translation, this does not run and the modified config prevails. Not a systemic bug and has nothing to do with config or module installer.
Comment #2
alexpottphew.
Comment #3
Gábor HojtsyStarting with throwing a plain exception for now where it should not actually save this config. Should introduce a custom exception for this but this is a first step.
Comment #5
Gábor HojtsySo LanguageNegotiator::saveConfiguration() is used as an API to persist locked settings too for easier lookup later. Let's not introduce unneeded API changes then and just fix the cause of this bug in content_translation_install(). Even if we would throw exceptions in saveConfiguration() it is still perfectly possible to update the config with the config API itself in whatever way. So there is no real foolproof way to protect that. We should just not do silly things ourselves at least.
Comment #9
vijaycs85Looks like the tests weren't really rendering /node. This patch fix them and the change of behaviour of code change in #5.
Comment #10
vijaycs85here is the patch for real...
Comment #12
vijaycs85Here is another assert fix.
Comment #15
Gábor HojtsyNot sure the fixes in #10 are correct? There are changes to many asserts that now assert the opposite compared to what they used to be. The patch should not make that happen, no?
Comment #16
victor-shelepen CreditAttribution: victor-shelepen commentedThe patch #5 breaks the system also. PathLanguageTest and BlockLanguageTest have common failures. Pages are not found. The alias manager could get a path.
Comment #17
vijaycs85#16: yep as I mentioned in #9, the /node URLs weren't working.
Comment #18
victor-shelepen CreditAttribution: victor-shelepen commentedThe PathLanguageTest has been fixed.
The fr language is preffered. If it see an english alises. It gets a node by path. But it uses the user preferred language - fr. So asking en alias we receive fr content.
Continue to check another tests.
Comment #20
victor-shelepen CreditAttribution: victor-shelepen commentedEnables url negotiator for content.
Result: The block exists:
There is not a block because of content language is en, block uses the content language.
$this->drupalGet('en/node');
The block exists on the page because of the query parameter sets the site language.
Comment #21
Gábor HojtsySo I see some tests were assuming that the URL method was set for language negotiation. What about fixing what is asserted then? I see you did that fix in the path language test, so why not do that in the block language test too? Unless we loose some important tested feature?
french => French
Also let's remove the added debug string.
Comment #22
victor-shelepen CreditAttribution: victor-shelepen commentedIn two tests I used the same fix. Yes, I've changed the test asserts. They are different to these were before. But they are logical. I want to highlight that if we use an english alias with user preferred language - French, The French content have to be shown. The assertion before was. If we opened an english alias with user user preferred language - French, we saw the english content. I do not know what is the right way. If test asserts were right we would open new issue. Elsewhere we have changed asserts logic a little bit. It is still logical. As for me. It is not clear, I do not see what should be changed.
Comment #23
Gábor Hojtsy@likin: if you are fixing the two tests the same way then I must be terribly mistaken. What I see is:
1. BlockLanguageTest: you updated the content language to be URL based, therefore practically redoing what the install code did that we remove
2. In PathLanguageTest you modified what is being asserted rather than changing the content language setting
Are you doing the same fix in the two tests then? What am I missing?
Comment #24
Wim LeersThis is also causing the
PathLanguageTest
failure in #2444231-39: Fix CacheableInterface so it makes sense (was: "Make Config objects & Entities implement CacheableInterface + add BubbleableMetadata::createFromCacheableObject()").Comment #25
Wim LeersComment #26
Wim LeersTested & confirmed that the patch in #20 fixes the bug discovered in #2444231: Fix CacheableInterface so it makes sense (was: "Make Config objects & Entities implement CacheableInterface + add BubbleableMetadata::createFromCacheableObject()") as well.
I'll leave it to Gábor to RTBC the test coverage though. But I consider the code changes RTBC already.
Comment #27
Wim LeersComment #28
Wim LeersPathLanguageTest
BlockLanguageTest
Comment #29
Gábor HojtsyYay, looks amazing. Thanks for walking through that with me. Looks like my instinct was very right that we either need to change config or the assertions but definitely not both. I think the changes are fine now, especially the path tests, there are very lengthy comments there as to why the found node should be French, so its strange it was not before. Now the world order is restored.
Comment #30
Gábor HojtsyUpdated issue summary.
Comment #31
victor-shelepen CreditAttribution: victor-shelepen commented:)
Where is a magic? The variable is renamed, nothing else has been touched. Thank you.
Comment #32
Gábor Hojtsy@likin: no magic involved. Asserting that accessing a French node when using an alias for an English node is confusing, and that is not what the test does. It asserts that it leads to the same node in a different language. Therefore $french_node and $english_node is confusing because they are both the same node. That change is not required to fix the bug but helped a tremendous amount to understand what is being tested and why the fix makes sense.
Comment #34
victor-shelepen CreditAttribution: victor-shelepen commented@Gábor Hojtsy Ok. I see. So the patch #33 also should pass tests,
Comment #35
Gábor Hojtsy@likin: no, probably not. The changes you made before or Wim's changes are needed to pass, because those two tests assumed the (broken) configuration that content language had earlier due to its install hook.
Comment #37
alexpottThis issue addresses a major bug and is allowed per https://www.drupal.org/core/beta-changes. Committed 8c5ffa3 and pushed to 8.0.x. Thanks!
Comment #39
Gábor HojtsyThanks @likin, @Wim Leers!