13803bd2116adbe02fe7bad88cfc154b9b681388
[yaffs-website] / web / core / modules / migrate / tests / src / Kernel / MigrateEntityContentBaseTest.php
1 <?php
2
3 namespace Drupal\Tests\migrate\Kernel;
4
5 use Drupal\entity_test\Entity\EntityTestMul;
6 use Drupal\KernelTests\KernelTestBase;
7 use Drupal\language\Entity\ConfigurableLanguage;
8 use Drupal\migrate\MigrateExecutable;
9 use Drupal\migrate\Plugin\migrate\destination\EntityContentBase;
10 use Drupal\migrate\Plugin\MigrateIdMapInterface;
11 use Drupal\migrate\Plugin\MigrationInterface;
12 use Drupal\migrate\Row;
13 use Drupal\migrate_entity_test\Entity\StringIdEntityTest;
14
15 /**
16  * Tests the EntityContentBase destination.
17  *
18  * @group migrate
19  */
20 class MigrateEntityContentBaseTest extends KernelTestBase {
21
22   /**
23    * Modules to enable.
24    *
25    * @var array
26    */
27   public static $modules = ['migrate', 'user', 'language', 'entity_test'];
28
29   /**
30    * The storage for entity_test_mul.
31    *
32    * @var \Drupal\Core\Entity\ContentEntityStorageInterface
33    */
34   protected $storage;
35
36   /**
37    * A content migrate destination.
38    *
39    * @var \Drupal\migrate\Plugin\MigrateDestinationInterface
40    */
41   protected $destination;
42
43   /**
44    * {@inheritdoc}
45    */
46   protected function setUp() {
47     parent::setUp();
48
49     // Enable two required fields with default values: a single-value field and
50     // a multi-value field.
51     \Drupal::state()->set('entity_test.required_default_field', TRUE);
52     \Drupal::state()->set('entity_test.required_multi_default_field', TRUE);
53     $this->installEntitySchema('entity_test_mul');
54
55     ConfigurableLanguage::createFromLangcode('en')->save();
56     ConfigurableLanguage::createFromLangcode('fr')->save();
57
58     $this->storage = $this->container->get('entity.manager')->getStorage('entity_test_mul');
59   }
60
61   /**
62    * Check the existing translations of an entity.
63    *
64    * @param int $id
65    *   The entity ID.
66    * @param string $default
67    *   The expected default translation language code.
68    * @param string[] $others
69    *   The expected other translation language codes.
70    */
71   protected function assertTranslations($id, $default, $others = []) {
72     $entity = $this->storage->load($id);
73     $this->assertTrue($entity, "Entity exists");
74     $this->assertEquals($default, $entity->language()->getId(), "Entity default translation");
75     $translations = array_keys($entity->getTranslationLanguages(FALSE));
76     sort($others);
77     sort($translations);
78     $this->assertEquals($others, $translations, "Entity translations");
79   }
80
81   /**
82    * Create the destination plugin to test.
83    *
84    * @param array $configuration
85    *   The plugin configuration.
86    */
87   protected function createDestination(array $configuration) {
88     $this->destination = new EntityContentBase(
89       $configuration,
90       'fake_plugin_id',
91       [],
92       $this->getMock(MigrationInterface::class),
93       $this->storage,
94       [],
95       $this->container->get('entity.manager'),
96       $this->container->get('plugin.manager.field.field_type')
97     );
98   }
99
100   /**
101    * Test importing and rolling back translated entities.
102    */
103   public function testTranslated() {
104     // Create a destination.
105     $this->createDestination(['translations' => TRUE]);
106
107     // Create some pre-existing entities.
108     $this->storage->create(['id' => 1, 'langcode' => 'en'])->save();
109     $this->storage->create(['id' => 2, 'langcode' => 'fr'])->save();
110     $translated = $this->storage->create(['id' => 3, 'langcode' => 'en']);
111     $translated->save();
112     $translated->addTranslation('fr')->save();
113
114     // Pre-assert that things are as expected.
115     $this->assertTranslations(1, 'en');
116     $this->assertTranslations(2, 'fr');
117     $this->assertTranslations(3, 'en', ['fr']);
118     $this->assertFalse($this->storage->load(4));
119
120     $destination_rows = [
121       // Existing default translation.
122       ['id' => 1, 'langcode' => 'en', 'action' => MigrateIdMapInterface::ROLLBACK_PRESERVE],
123       // New translation.
124       ['id' => 2, 'langcode' => 'en', 'action' => MigrateIdMapInterface::ROLLBACK_DELETE],
125       // Existing non-default translation.
126       ['id' => 3, 'langcode' => 'fr', 'action' => MigrateIdMapInterface::ROLLBACK_PRESERVE],
127       // Brand new row.
128       ['id' => 4, 'langcode' => 'fr', 'action' => MigrateIdMapInterface::ROLLBACK_DELETE],
129     ];
130     $rollback_actions = [];
131
132     // Import some rows.
133     foreach ($destination_rows as $idx => $destination_row) {
134       $row = new Row();
135       foreach ($destination_row as $key => $value) {
136         $row->setDestinationProperty($key, $value);
137       }
138       $this->destination->import($row);
139
140       // Check that the rollback action is correct, and save it.
141       $this->assertEquals($destination_row['action'], $this->destination->rollbackAction());
142       $rollback_actions[$idx] = $this->destination->rollbackAction();
143     }
144
145     $this->assertTranslations(1, 'en');
146     $this->assertTranslations(2, 'fr', ['en']);
147     $this->assertTranslations(3, 'en', ['fr']);
148     $this->assertTranslations(4, 'fr');
149
150     // Rollback the rows.
151     foreach ($destination_rows as $idx => $destination_row) {
152       if ($rollback_actions[$idx] == MigrateIdMapInterface::ROLLBACK_DELETE) {
153         $this->destination->rollback($destination_row);
154       }
155     }
156
157     // No change, update of existing translation.
158     $this->assertTranslations(1, 'en');
159     // Remove added translation.
160     $this->assertTranslations(2, 'fr');
161     // No change, update of existing translation.
162     $this->assertTranslations(3, 'en', ['fr']);
163     // No change, can't remove default translation.
164     $this->assertTranslations(4, 'fr');
165   }
166
167   /**
168    * Tests creation of ID columns table with definitions taken from entity type.
169    */
170   public function testEntityWithStringId() {
171     $this->enableModules(['migrate_entity_test']);
172     $this->installEntitySchema('migrate_string_id_entity_test');
173
174     $definition = [
175       'source' => [
176         'plugin' => 'embedded_data',
177         'data_rows' => [
178           ['id' => 123, 'version' => 'foo'],
179           // This integer needs an 'int' schema with 'big' size. If 'destid1'
180           // is not correctly taking the definition from the destination entity
181           // type, the import will fail with a SQL exception.
182           ['id' => 123456789012, 'version' => 'bar'],
183         ],
184         'ids' => [
185           'id' => ['type' => 'integer', 'size' => 'big'],
186           'version' => ['type' => 'string'],
187         ],
188       ],
189       'process' => [
190         'id' => 'id',
191         'version' => 'version',
192       ],
193       'destination' => [
194         'plugin' => 'entity:migrate_string_id_entity_test',
195       ],
196     ];
197
198     $migration = \Drupal::service('plugin.manager.migration')->createStubMigration($definition);
199     $executable = new MigrateExecutable($migration);
200     $result = $executable->import();
201     $this->assertEquals(MigrationInterface::RESULT_COMPLETED, $result);
202
203     /** @var \Drupal\migrate\Plugin\MigrateIdMapInterface $id_map_plugin */
204     $id_map_plugin = $migration->getIdMap();
205
206     // Check that the destination has been stored.
207     $map_row = $id_map_plugin->getRowBySource(['id' => 123, 'version' => 'foo']);
208     $this->assertEquals(123, $map_row['destid1']);
209     $map_row = $id_map_plugin->getRowBySource(['id' => 123456789012, 'version' => 'bar']);
210     $this->assertEquals(123456789012, $map_row['destid1']);
211   }
212
213   /**
214    * Tests empty destinations.
215    */
216   public function testEmptyDestinations() {
217     $this->enableModules(['migrate_entity_test']);
218     $this->installEntitySchema('migrate_string_id_entity_test');
219
220     $definition = [
221       'source' => [
222         'plugin' => 'embedded_data',
223         'data_rows' => [
224           ['id' => 123, 'version' => 'foo'],
225           // This integer needs an 'int' schema with 'big' size. If 'destid1'
226           // is not correctly taking the definition from the destination entity
227           // type, the import will fail with an SQL exception.
228           ['id' => 123456789012, 'version' => 'bar'],
229         ],
230         'ids' => [
231           'id' => ['type' => 'integer', 'size' => 'big'],
232           'version' => ['type' => 'string'],
233         ],
234         'constants' => ['null' => NULL],
235       ],
236       'process' => [
237         'id' => 'id',
238         'version' => 'version',
239       ],
240       'destination' => [
241         'plugin' => 'entity:migrate_string_id_entity_test',
242       ],
243     ];
244
245     $migration = \Drupal::service('plugin.manager.migration')
246       ->createStubMigration($definition);
247     $executable = new MigrateExecutable($migration);
248     $executable->import();
249
250     /** @var \Drupal\migrate_entity_test\Entity\StringIdEntityTest $entity */
251     $entity = StringIdEntityTest::load('123');
252     $this->assertSame('foo', $entity->version->value);
253     $entity = StringIdEntityTest::load('123456789012');
254     $this->assertSame('bar', $entity->version->value);
255
256     // Rerun the migration forcing the version to NULL.
257     $definition['process'] = [
258       'id' => 'id',
259       'version' => 'constants/null',
260     ];
261
262     $migration = \Drupal::service('plugin.manager.migration')
263       ->createStubMigration($definition);
264     $executable = new MigrateExecutable($migration);
265     $executable->import();
266
267     /** @var \Drupal\migrate_entity_test\Entity\StringIdEntityTest $entity */
268     $entity = StringIdEntityTest::load('123');
269     $this->assertNull($entity->version->value);
270     $entity = StringIdEntityTest::load('123456789012');
271     $this->assertNull($entity->version->value);
272   }
273
274   /**
275    * Tests stub rows.
276    */
277   public function testStubRows() {
278     // Create a destination.
279     $this->createDestination([]);
280
281     // Import a stub row.
282     $row = new Row([], [], TRUE);
283     $row->setDestinationProperty('type', 'test');
284     $ids = $this->destination->import($row);
285     $this->assertCount(1, $ids);
286
287     // Make sure the entity was saved.
288     $entity = EntityTestMul::load(reset($ids));
289     $this->assertInstanceOf(EntityTestMul::class, $entity);
290     // Make sure the default value was applied to the required fields.
291     $single_field_name = 'required_default_field';
292     $single_default_value = $entity->getFieldDefinition($single_field_name)->getDefaultValueLiteral();
293     $this->assertSame($single_default_value, $entity->get($single_field_name)->getValue());
294
295     $multi_field_name = 'required_multi_default_field';
296     $multi_default_value = $entity->getFieldDefinition($multi_field_name)->getDefaultValueLiteral();
297     $count = 3;
298     $this->assertCount($count, $multi_default_value);
299     for ($i = 0; $i < $count; ++$i) {
300       $this->assertSame($multi_default_value[$i], $entity->get($multi_field_name)->get($i)->getValue());
301     }
302   }
303
304 }