You are here

ContentTranslationSyncImageTest.php in Drupal 10

File

core/modules/content_translation/tests/src/Functional/ContentTranslationSyncImageTest.php
View source
<?php

namespace Drupal\Tests\content_translation\Functional;

use Drupal\Component\Render\FormattableMarkup;
use Drupal\Core\Entity\EntityInterface;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\file\Entity\File;
use Drupal\Tests\TestFileCreationTrait;

/**
 * Tests the field synchronization behavior for the image field.
 *
 * @group content_translation
 */
class ContentTranslationSyncImageTest extends ContentTranslationTestBase {
  use TestFileCreationTrait {
    getTestFiles as drupalGetTestFiles;
  }

  /**
   * {@inheritdoc}
   */
  protected $defaultTheme = 'stark';

  /**
   * The cardinality of the image field.
   *
   * @var int
   */
  protected $cardinality;

  /**
   * The test image files.
   *
   * @var array
   */
  protected $files;

  /**
   * Modules to enable.
   *
   * @var array
   */
  protected static $modules = [
    'language',
    'content_translation',
    'entity_test',
    'image',
    'field_ui',
  ];
  protected function setUp() : void {
    parent::setUp();
    $this->files = $this
      ->drupalGetTestFiles('image');
  }

  /**
   * Creates the test image field.
   */
  protected function setupTestFields() {
    $this->fieldName = 'field_test_et_ui_image';
    $this->cardinality = 3;
    FieldStorageConfig::create([
      'field_name' => $this->fieldName,
      'entity_type' => $this->entityTypeId,
      'type' => 'image',
      'cardinality' => $this->cardinality,
    ])
      ->save();
    FieldConfig::create([
      'entity_type' => $this->entityTypeId,
      'field_name' => $this->fieldName,
      'bundle' => $this->entityTypeId,
      'label' => 'Test translatable image field',
      'third_party_settings' => [
        'content_translation' => [
          'translation_sync' => [
            'file' => FALSE,
            'alt' => 'alt',
            'title' => 'title',
          ],
        ],
      ],
    ])
      ->save();
  }

  /**
   * {@inheritdoc}
   */
  protected function getEditorPermissions() {

    // Every entity-type-specific test needs to define these.
    return [
      'administer entity_test_mul fields',
      'administer languages',
      'administer content translation',
    ];
  }

  /**
   * Tests image field synchronization.
   */
  public function testImageFieldSync() {

    // Check that the alt and title fields are enabled for the image field.
    $this
      ->drupalLogin($this->editor);
    $this
      ->drupalGet('entity_test_mul/structure/' . $this->entityTypeId . '/fields/' . $this->entityTypeId . '.' . $this->entityTypeId . '.' . $this->fieldName);
    $this
      ->assertSession()
      ->checkboxChecked('edit-third-party-settings-content-translation-translation-sync-alt');
    $this
      ->assertSession()
      ->checkboxChecked('edit-third-party-settings-content-translation-translation-sync-title');
    $edit = [
      'third_party_settings[content_translation][translation_sync][alt]' => FALSE,
      'third_party_settings[content_translation][translation_sync][title]' => FALSE,
    ];
    $this
      ->submitForm($edit, 'Save settings');

    // Check that the content translation settings page reflects the changes
    // performed in the field edit page.
    $this
      ->drupalGet('admin/config/regional/content-language');
    $this
      ->assertSession()
      ->checkboxNotChecked('edit-settings-entity-test-mul-entity-test-mul-columns-field-test-et-ui-image-alt');
    $this
      ->assertSession()
      ->checkboxNotChecked('edit-settings-entity-test-mul-entity-test-mul-columns-field-test-et-ui-image-title');
    $edit = [
      'settings[entity_test_mul][entity_test_mul][fields][field_test_et_ui_image]' => TRUE,
      'settings[entity_test_mul][entity_test_mul][columns][field_test_et_ui_image][alt]' => TRUE,
      'settings[entity_test_mul][entity_test_mul][columns][field_test_et_ui_image][title]' => TRUE,
    ];
    $this
      ->drupalGet('admin/config/regional/content-language');
    $this
      ->submitForm($edit, 'Save configuration');
    $this
      ->assertSession()
      ->statusMessageNotExists('error');
    $this
      ->assertSession()
      ->checkboxChecked('edit-settings-entity-test-mul-entity-test-mul-columns-field-test-et-ui-image-alt');
    $this
      ->assertSession()
      ->checkboxChecked('edit-settings-entity-test-mul-entity-test-mul-columns-field-test-et-ui-image-title');
    $this
      ->drupalLogin($this->translator);
    $default_langcode = $this->langcodes[0];
    $langcode = $this->langcodes[1];

    // Populate the test entity with some random initial values.
    $values = [
      'name' => $this
        ->randomMachineName(),
      'user_id' => mt_rand(1, 128),
      'langcode' => $default_langcode,
    ];
    $entity = \Drupal::entityTypeManager()
      ->getStorage($this->entityTypeId)
      ->create($values);

    // Create some file entities from the generated test files and store them.
    $values = [];
    for ($delta = 0; $delta < $this->cardinality; $delta++) {

      // For the default language use the same order for files and field items.
      $index = $delta;

      // Create the file entity for the image being processed and record its
      // identifier.
      $field_values = [
        'uri' => $this->files[$index]->uri,
        'uid' => \Drupal::currentUser()
          ->id(),
      ];
      $file = File::create($field_values);
      $file
        ->setPermanent();
      $file
        ->save();
      $fid = $file
        ->id();
      $this->files[$index]->fid = $fid;

      // Generate the item for the current image file entity and attach it to
      // the entity.
      $item = [
        'target_id' => $fid,
        'alt' => $default_langcode . '_' . $fid . '_' . $this
          ->randomMachineName(),
        'title' => $default_langcode . '_' . $fid . '_' . $this
          ->randomMachineName(),
      ];
      $entity->{$this->fieldName}[] = $item;

      // Store the generated values keying them by fid for easier lookup.
      $values[$default_langcode][$fid] = $item;
    }
    $entity = $this
      ->saveEntity($entity);

    // Create some field translations for the test image field. The translated
    // items will be one less than the original values to check that only the
    // translated ones will be preserved. In fact we want the same fids and
    // items order for both languages.
    $translation = $entity
      ->addTranslation($langcode);
    for ($delta = 0; $delta < $this->cardinality - 1; $delta++) {

      // Simulate a field reordering: items are shifted of one position ahead.
      // The modulo operator ensures we start from the beginning after reaching
      // the maximum allowed delta.
      $index = ($delta + 1) % $this->cardinality;

      // Generate the item for the current image file entity and attach it to
      // the entity.
      $fid = $this->files[$index]->fid;
      $item = [
        'target_id' => $fid,
        'alt' => $langcode . '_' . $fid . '_' . $this
          ->randomMachineName(),
        'title' => $langcode . '_' . $fid . '_' . $this
          ->randomMachineName(),
      ];
      $translation->{$this->fieldName}[] = $item;

      // Again store the generated values keying them by fid for easier lookup.
      $values[$langcode][$fid] = $item;
    }

    // Perform synchronization: the translation language is used as source,
    // while the default language is used as target.
    $this->manager
      ->getTranslationMetadata($translation)
      ->setSource($default_langcode);
    $entity = $this
      ->saveEntity($translation);
    $translation = $entity
      ->getTranslation($langcode);

    // Check that one value has been dropped from the original values.
    $assert = count($entity->{$this->fieldName}) == 2;
    $this
      ->assertTrue($assert, 'One item correctly removed from the synchronized field values.');

    // Check that fids have been synchronized and translatable column values
    // have been retained.
    $fids = [];
    foreach ($entity->{$this->fieldName} as $delta => $item) {
      $value = $values[$default_langcode][$item->target_id];
      $source_item = $translation->{$this->fieldName}
        ->get($delta);
      $assert = $item->target_id == $source_item->target_id && $item->alt == $value['alt'] && $item->title == $value['title'];
      $this
        ->assertTrue($assert, new FormattableMarkup('Field item @fid has been successfully synchronized.', [
        '@fid' => $item->target_id,
      ]));
      $fids[$item->target_id] = TRUE;
    }

    // Check that the dropped value is the right one.
    $removed_fid = $this->files[0]->fid;
    $this
      ->assertTrue(!isset($fids[$removed_fid]), new FormattableMarkup('Field item @fid has been correctly removed.', [
      '@fid' => $removed_fid,
    ]));

    // Add back an item for the dropped value and perform synchronization again.
    $values[$langcode][$removed_fid] = [
      'target_id' => $removed_fid,
      'alt' => $langcode . '_' . $removed_fid . '_' . $this
        ->randomMachineName(),
      'title' => $langcode . '_' . $removed_fid . '_' . $this
        ->randomMachineName(),
    ];
    $translation->{$this->fieldName}
      ->setValue(array_values($values[$langcode]));
    $entity = $this
      ->saveEntity($translation);
    $translation = $entity
      ->getTranslation($langcode);

    // Check that the value has been added to the default language.
    $assert = count($entity->{$this->fieldName}
      ->getValue()) == 3;
    $this
      ->assertTrue($assert, 'One item correctly added to the synchronized field values.');
    foreach ($entity->{$this->fieldName} as $delta => $item) {

      // When adding an item its value is copied over all the target languages,
      // thus in this case the source language needs to be used to check the
      // values instead of the target one.
      $fid_langcode = $item->target_id != $removed_fid ? $default_langcode : $langcode;
      $value = $values[$fid_langcode][$item->target_id];
      $source_item = $translation->{$this->fieldName}
        ->get($delta);
      $assert = $item->target_id == $source_item->target_id && $item->alt == $value['alt'] && $item->title == $value['title'];
      $this
        ->assertTrue($assert, new FormattableMarkup('Field item @fid has been successfully synchronized.', [
        '@fid' => $item->target_id,
      ]));
    }
  }

  /**
   * Saves the passed entity and reloads it, enabling compatibility mode.
   *
   * @param \Drupal\Core\Entity\EntityInterface $entity
   *   The entity to be saved.
   *
   * @return \Drupal\Core\Entity\EntityInterface
   *   The saved entity.
   */
  protected function saveEntity(EntityInterface $entity) {
    $entity
      ->save();
    $entity = \Drupal::entityTypeManager()
      ->getStorage('entity_test_mul')
      ->loadUnchanged($entity
      ->id());
    return $entity;
  }

}

Classes

Namesort descending Description
ContentTranslationSyncImageTest Tests the field synchronization behavior for the image field.