5f7c9fd9b8ecebf885a4a5e8b4f82379103c83db
[yaffs-website] / web / core / modules / content_translation / tests / src / Functional / ContentTranslationSyncImageTest.php
1 <?php
2
3 namespace Drupal\Tests\content_translation\Functional;
4
5 use Drupal\Core\Entity\EntityInterface;
6 use Drupal\field\Entity\FieldConfig;
7 use Drupal\field\Entity\FieldStorageConfig;
8 use Drupal\file\Entity\File;
9 use Drupal\Tests\TestFileCreationTrait;
10
11 /**
12  * Tests the field synchronization behavior for the image field.
13  *
14  * @group content_translation
15  */
16 class ContentTranslationSyncImageTest extends ContentTranslationTestBase {
17
18   use TestFileCreationTrait {
19     getTestFiles as drupalGetTestFiles;
20   }
21
22   /**
23    * The cardinality of the image field.
24    *
25    * @var int
26    */
27   protected $cardinality;
28
29   /**
30    * The test image files.
31    *
32    * @var array
33    */
34   protected $files;
35
36   /**
37    * Modules to enable.
38    *
39    * @var array
40    */
41   public static $modules = ['language', 'content_translation', 'entity_test', 'image', 'field_ui'];
42
43   protected function setUp() {
44     parent::setUp();
45     $this->files = $this->drupalGetTestFiles('image');
46   }
47
48   /**
49    * Creates the test image field.
50    */
51   protected function setupTestFields() {
52     $this->fieldName = 'field_test_et_ui_image';
53     $this->cardinality = 3;
54
55     FieldStorageConfig::create([
56       'field_name' => $this->fieldName,
57       'entity_type' => $this->entityTypeId,
58       'type' => 'image',
59       'cardinality' => $this->cardinality,
60     ])->save();
61
62     FieldConfig::create([
63       'entity_type' => $this->entityTypeId,
64       'field_name' => $this->fieldName,
65       'bundle' => $this->entityTypeId,
66       'label' => 'Test translatable image field',
67       'third_party_settings' => [
68         'content_translation' => [
69           'translation_sync' => [
70             'file' => FALSE,
71             'alt' => 'alt',
72             'title' => 'title',
73           ],
74         ],
75       ],
76     ])->save();
77   }
78
79   /**
80    * {@inheritdoc}
81    */
82   protected function getEditorPermissions() {
83     // Every entity-type-specific test needs to define these.
84     return ['administer entity_test_mul fields', 'administer languages', 'administer content translation'];
85   }
86
87   /**
88    * Tests image field field synchronization.
89    */
90   public function testImageFieldSync() {
91     // Check that the alt and title fields are enabled for the image field.
92     $this->drupalLogin($this->editor);
93     $this->drupalGet('entity_test_mul/structure/' . $this->entityTypeId . '/fields/' . $this->entityTypeId . '.' . $this->entityTypeId . '.' . $this->fieldName);
94     $this->assertFieldChecked('edit-third-party-settings-content-translation-translation-sync-alt');
95     $this->assertFieldChecked('edit-third-party-settings-content-translation-translation-sync-title');
96     $edit = [
97       'third_party_settings[content_translation][translation_sync][alt]' => FALSE,
98       'third_party_settings[content_translation][translation_sync][title]' => FALSE,
99     ];
100     $this->drupalPostForm(NULL, $edit, t('Save settings'));
101
102     // Check that the content translation settings page reflects the changes
103     // performed in the field edit page.
104     $this->drupalGet('admin/config/regional/content-language');
105     $this->assertNoFieldChecked('edit-settings-entity-test-mul-entity-test-mul-columns-field-test-et-ui-image-alt');
106     $this->assertNoFieldChecked('edit-settings-entity-test-mul-entity-test-mul-columns-field-test-et-ui-image-title');
107     $edit = [
108       'settings[entity_test_mul][entity_test_mul][fields][field_test_et_ui_image]' => TRUE,
109       'settings[entity_test_mul][entity_test_mul][columns][field_test_et_ui_image][alt]' => TRUE,
110       'settings[entity_test_mul][entity_test_mul][columns][field_test_et_ui_image][title]' => TRUE,
111     ];
112     $this->drupalPostForm('admin/config/regional/content-language', $edit, t('Save configuration'));
113     $errors = $this->xpath('//div[contains(@class, "messages--error")]');
114     $this->assertFalse($errors, 'Settings correctly stored.');
115     $this->assertFieldChecked('edit-settings-entity-test-mul-entity-test-mul-columns-field-test-et-ui-image-alt');
116     $this->assertFieldChecked('edit-settings-entity-test-mul-entity-test-mul-columns-field-test-et-ui-image-title');
117     $this->drupalLogin($this->translator);
118
119     $default_langcode = $this->langcodes[0];
120     $langcode = $this->langcodes[1];
121
122     // Populate the test entity with some random initial values.
123     $values = [
124       'name' => $this->randomMachineName(),
125       'user_id' => mt_rand(1, 128),
126       'langcode' => $default_langcode,
127     ];
128     $entity = entity_create($this->entityTypeId, $values);
129
130     // Create some file entities from the generated test files and store them.
131     $values = [];
132     for ($delta = 0; $delta < $this->cardinality; $delta++) {
133       // For the default language use the same order for files and field items.
134       $index = $delta;
135
136       // Create the file entity for the image being processed and record its
137       // identifier.
138       $field_values = [
139         'uri' => $this->files[$index]->uri,
140         'uid' => \Drupal::currentUser()->id(),
141         'status' => FILE_STATUS_PERMANENT,
142       ];
143       $file = File::create($field_values);
144       $file->save();
145       $fid = $file->id();
146       $this->files[$index]->fid = $fid;
147
148       // Generate the item for the current image file entity and attach it to
149       // the entity.
150       $item = [
151         'target_id' => $fid,
152         'alt' => $default_langcode . '_' . $fid . '_' . $this->randomMachineName(),
153         'title' => $default_langcode . '_' . $fid . '_' . $this->randomMachineName(),
154       ];
155       $entity->{$this->fieldName}[] = $item;
156
157       // Store the generated values keying them by fid for easier lookup.
158       $values[$default_langcode][$fid] = $item;
159     }
160     $entity = $this->saveEntity($entity);
161
162     // Create some field translations for the test image field. The translated
163     // items will be one less than the original values to check that only the
164     // translated ones will be preserved. In fact we want the same fids and
165     // items order for both languages.
166     $translation = $entity->addTranslation($langcode);
167     for ($delta = 0; $delta < $this->cardinality - 1; $delta++) {
168       // Simulate a field reordering: items are shifted of one position ahead.
169       // The modulo operator ensures we start from the beginning after reaching
170       // the maximum allowed delta.
171       $index = ($delta + 1) % $this->cardinality;
172
173       // Generate the item for the current image file entity and attach it to
174       // the entity.
175       $fid = $this->files[$index]->fid;
176       $item = [
177         'target_id' => $fid,
178         'alt' => $langcode . '_' . $fid . '_' . $this->randomMachineName(),
179         'title' => $langcode . '_' . $fid . '_' . $this->randomMachineName(),
180       ];
181       $translation->{$this->fieldName}[] = $item;
182
183       // Again store the generated values keying them by fid for easier lookup.
184       $values[$langcode][$fid] = $item;
185     }
186
187     // Perform synchronization: the translation language is used as source,
188     // while the default language is used as target.
189     $this->manager->getTranslationMetadata($translation)->setSource($default_langcode);
190     $entity = $this->saveEntity($translation);
191     $translation = $entity->getTranslation($langcode);
192
193     // Check that one value has been dropped from the original values.
194     $assert = count($entity->{$this->fieldName}) == 2;
195     $this->assertTrue($assert, 'One item correctly removed from the synchronized field values.');
196
197     // Check that fids have been synchronized and translatable column values
198     // have been retained.
199     $fids = [];
200     foreach ($entity->{$this->fieldName} as $delta => $item) {
201       $value = $values[$default_langcode][$item->target_id];
202       $source_item = $translation->{$this->fieldName}->get($delta);
203       $assert = $item->target_id == $source_item->target_id && $item->alt == $value['alt'] && $item->title == $value['title'];
204       $this->assertTrue($assert, format_string('Field item @fid has been successfully synchronized.', ['@fid' => $item->target_id]));
205       $fids[$item->target_id] = TRUE;
206     }
207
208     // Check that the dropped value is the right one.
209     $removed_fid = $this->files[0]->fid;
210     $this->assertTrue(!isset($fids[$removed_fid]), format_string('Field item @fid has been correctly removed.', ['@fid' => $removed_fid]));
211
212     // Add back an item for the dropped value and perform synchronization again.
213     $values[$langcode][$removed_fid] = [
214       'target_id' => $removed_fid,
215       'alt' => $langcode . '_' . $removed_fid . '_' . $this->randomMachineName(),
216       'title' => $langcode . '_' . $removed_fid . '_' . $this->randomMachineName(),
217     ];
218     $translation->{$this->fieldName}->setValue(array_values($values[$langcode]));
219     $entity = $this->saveEntity($translation);
220     $translation = $entity->getTranslation($langcode);
221
222     // Check that the value has been added to the default language.
223     $assert = count($entity->{$this->fieldName}->getValue()) == 3;
224     $this->assertTrue($assert, 'One item correctly added to the synchronized field values.');
225
226     foreach ($entity->{$this->fieldName} as $delta => $item) {
227       // When adding an item its value is copied over all the target languages,
228       // thus in this case the source language needs to be used to check the
229       // values instead of the target one.
230       $fid_langcode = $item->target_id != $removed_fid ? $default_langcode : $langcode;
231       $value = $values[$fid_langcode][$item->target_id];
232       $source_item = $translation->{$this->fieldName}->get($delta);
233       $assert = $item->target_id == $source_item->target_id && $item->alt == $value['alt'] && $item->title == $value['title'];
234       $this->assertTrue($assert, format_string('Field item @fid has been successfully synchronized.', ['@fid' => $item->target_id]));
235     }
236   }
237
238   /**
239    * Saves the passed entity and reloads it, enabling compatibility mode.
240    *
241    * @param \Drupal\Core\Entity\EntityInterface $entity
242    *   The entity to be saved.
243    *
244    * @return \Drupal\Core\Entity\EntityInterface
245    *   The saved entity.
246    */
247   protected function saveEntity(EntityInterface $entity) {
248     $entity->save();
249     $entity = entity_test_mul_load($entity->id(), TRUE);
250     return $entity;
251   }
252
253 }