This issue is based on a bug found when using the Configuration installer contrib module : #2623878: The "configurable_language" entity type does not exist.. It looks like a core bug to me, which might happen in other configuration imports use cases. Sorry if I'm wrong.
A comment in ConfigurableLanguageManager->getLanguages() mentions :
// Load configurable languages on top of the defaults. Ideally this could
// use the entity API to load and instantiate ConfigurableLanguage
// objects. However the entity API depends on the language system, so that
// would result in infinite loops. We use the configuration system
// directly and instantiate runtime Language objects. When language
// entities are imported those cover the default and locked languages, so
// site-specific configuration will prevail over the fallback values.
// Having them in the array already ensures if this is invoked in the
// middle of importing language configuration entities, the defaults are
// always present.
Unfortunately, infinite loops can still happen, at least in my use case. The languages sort needs the languages names, which need getLanguages() again to get translated, etc. I have no idea where the loop should be broken.
Here's the loop (you can see the full calls tree in #2623878: The "configurable_language" entity type does not exist.).
222.75179744536Drupal\language\ConfigurableLanguageManager->getLanguages( )../language.module:286
232.75379751024Drupal\Core\Language\Language::sort( )../ConfigurableLanguageManager.php:319
242.75379751432uasort
( )../Language.php:157
252.75379751560Drupal\Core\Language\Language::Drupal\Core\Language\{closure}( )../Language.php:157
262.75379751640strnatcasecmp
( )../Language.php:154
272.75379751824Drupal\Core\StringTranslation\TranslatableMarkup->__toString( )../Language.php:154
282.75379751968Drupal\Core\StringTranslation\TranslatableMarkup->render( )../ToStringTrait.php:20
292.75379752080Drupal\Core\StringTranslation\TranslationManager->translateString( )../TranslatableMarkup.php:204
302.75379752224Drupal\Core\StringTranslation\TranslationManager->doTranslate( )../TranslationManager.php:119
312.75379752784Drupal\Core\StringTranslation\TranslationManager->getStringTranslation( )../TranslationManager.php:147
322.75389754048Drupal\locale\LocaleTranslation->getStringTranslation( )../TranslationManager.php:99
332.75409767672Drupal\Core\Cache\CacheCollector->get( )../LocaleTranslation.php:123
342.75449788040Drupal\locale\LocaleLookup->resolveCacheMiss( )../CacheCollector.php:153
352.78329821016Drupal\language\ConfigurableLanguageManager->getFallbackCandidates( )../LocaleLookup.php:163
362.78329821016Drupal\language\ConfigurableLanguageManager->isMultilingual( )../ConfigurableLanguageManager.php:372
372.78339821064Drupal\language\ConfigurableLanguageManager->getLanguages( )../ConfigurableLanguageManager.php:149
382.78359823976Drupal\Core\Language\Language::sort( )../ConfigurableLanguageManager.php:319
392.78359824384uasort
I can easily make Xdebug breakpoints on it if needed, as the same infinite loop happens when I try to load any page of my not-fully-imported website.
After $languages += $this->getDefaultLockedLanguages($default->getWeight());
instruction, $languages in an array with und, zxx, and fr. One line after that, $config_ids is set to
Array
(
[0] => language.entity.fr
[1] => language.entity.und
)
This is because language.entity.zxx.yml it not yet imported. So that on Language::sort($languages);
instruction, $languages[$langcode]->name
is a string for fr and und, but for zxx the name is still a TranslatableMarkup object, so that the sort will call __toString() on it.
Comment | File | Size | Author |
---|---|---|---|
#23 | 2625782-23.patch | 3.42 KB | alexpott |
#23 | 20-23-interdiff.txt | 1.02 KB | alexpott |
#20 | 2625782-18.patch | 3.35 KB | alexpott |
#20 | 7-18-interdiff.txt | 1.98 KB | alexpott |
#8 | 2625782-7.patch | 3.19 KB | alexpott |
Comments
Comment #2
GaëlGComment #3
alexpottHere's a patch - I'm trying to write a failing test but it fixes the ConfigInstaller when it is applied.
Comment #4
legolasboI ran into
Maximum function nesting level of '512' reached
errors while importing configuration via the UI using the config_installer profile. The patch in #3 fixed this.Comment #5
alexpottSo this is super weird... the new KernelTestBase struggles to test this :(
The test only patch passes like so:
Once the fix is applied...
Weird.
Comment #6
alexpottHere's a test-only patch the proves the above
Comment #7
alexpottHere's an old kernel test base based approach that fails as expected..
Comment #8
alexpottPatches did not get added properly :(
Comment #12
dawehnerIt looks like ideally we would manage to fix phpunit to not not fatal, honestly.
Comment #13
GaëlGI can confirm the first patch fixes the initial problem. Thank you and good luck with tests!
Comment #14
alexpott#12 I'm not sure how we can do that - the problem is that infinite loops are possible the test causes one and so I think a fatal error in the test only patches is the expected result.
Comment #16
alexpottI think proceeding with #8 and the old style KernelTestBase test is the way to go here - neither @dawehner nor I can get #6 to fail locally. I suspect that this something OS related since once I comment out
protected $runTestInSeparateProcess = TRUE;
in KernelTestBase I get a segfault when running the test without a fix.Comment #17
dawehnerIt would be nice to explain why we need 'setSyncing' TRUE here.
Comment #18
alexpottThanks @dawehner - I also fixed up the array style to be consistent.
Comment #19
dawehnerWhat about uploading some files :)
Comment #20
alexpottWell, yeah.
Comment #21
dawehnerI love the usage of proper british english.
Comment #22
claudiu.cristeaTypo s/cuase/cause. And maybe "because THAT can cause..."?
But, it can be fixed on commit.
Comment #23
alexpottThanks for the review @claudiu.cristea - updated comment to make it completely clear what is going on.
Comment #24
catchCommitted/pushed to 8.1.x and cherry-picked to 8.0.x. Thanks!