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: en

The 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

  1. Install single_content_sync 1.4.17 or 1.4.18.
  2. Export content that is, or references, an entity of a type with no dedicated base fields processor, so it is handled by GenericContentEntity.
  3. Confirm that the export has langcode as a list (- value: en) under that entity's base_fields.
  4. Import the file with the language option left at "All languages".
  5. 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 langcode is a field item list.

Comments

bdanin created an issue.