Problem/Motivation
Since 1.4.17 (#3535823), importing content fails with:
TypeError: Cannot access offset of type array on array in Drupal\Core\Language\LanguageManager->getLanguage() (line 157 of core/lib/Drupal/Core/Language/LanguageManager.php).
Entity types with a dedicated base fields processor (node, paragraph, media, block_content, taxonomy_term, menu_link_content, etc.) export langcode as a string: 'langcode' => $entity->language()->getId().
Every other entity type falls back to GenericContentEntity, which exports each base field through ContentExporter::getFieldValue(). So langcode ends up as a field item list:
base_fields:
langcode:
-
value: enThe language handling added in #3535823 assumes $content['base_fields']['langcode'] is always a string. ContentImporter::prepareContentLanguage() passes it straight to LanguageManager::getLanguage(), which uses it as an array key and throws. The translation selection in doImport() (hasTranslation() / addTranslation()) makes the same assumption.
Before 1.4.17 the importer never passed this value to the language manager, so existing exports that imported fine on 1.4.16 now fail.
Trimmed trace (1.4.18):
#0 src/ContentImporter.php(355): Drupal\Core\Language\LanguageManager->getLanguage() #1 src/ContentImporter.php(184): Drupal\single_content_sync\ContentImporter->prepareContentLanguage() #2 src/Plugin/SingleContentSyncFieldProcessor/EntityReference.php(171): Drupal\single_content_sync\ContentImporter->doImport() #3 src/ContentImporter.php(500): ...EntityReference->importFieldValue() #4 src/ContentImporter.php(427): Drupal\single_content_sync\ContentImporter->setFieldValue() #5 src/ContentImporter.php(294): Drupal\single_content_sync\ContentImporter->importCustomValues() #6 src/Plugin/SingleContentSyncFieldProcessor/EntityReference.php(171): Drupal\single_content_sync\ContentImporter->doImport() ... #10 src/Form/ContentImportForm.php(186): Drupal\single_content_sync\ContentImporter->doImport()
Steps to reproduce
- Install single_content_sync 1.4.17 or 1.4.18.
- Export content that is, or references, an entity of a type with no dedicated base fields processor, so it is handled by
GenericContentEntity. - Confirm that the export has
langcodeas a list (- value: en) under that entity'sbase_fields. - Import the file with the language option left at "All languages".
- The import fails with the TypeError above.
If you pick a specific language instead, the import works, because rewriteContentLanguage() overwrites langcode with a string before it is used.
Proposed resolution
Normalize langcode to a string at the start of ContentImporter::doImport(). Every referenced entity is imported through doImport() as well, so nested entities are covered, and existing export files keep working without being re-exported.
--- a/src/ContentImporter.php
+++ b/src/ContentImporter.php
@@ -173,6 +173,10 @@ class ContentImporter implements ContentImporterInterface {
* {@inheritdoc}
*/
public function doImport(array $content, string $langcode = 'all'): EntityInterface {
+ // The generic base fields processor exports langcode as a field item list.
+ if (isset($content['base_fields']['langcode']) && is_array($content['base_fields']['langcode'])) {
+ $content['base_fields']['langcode'] = $content['base_fields']['langcode'][0]['value'] ?? NULL;
+ }
if ($langcode !== 'all') {
$content = $this->rewriteContentLanguage($content, $langcode);
}Another option is to change GenericContentEntity::exportBaseValues() to export langcode as a string. That would only fix new exports, so the import-side normalization is still needed for files created with earlier versions.
Remaining tasks
- Review the approach.
- Open an MR.
- Add a kernel test that imports a generic entity whose
langcodeis a field item list.
Comments