Added Entity and Entity Reference Revisions which got dropped somewhere along the...
[yaffs-website] / web / modules / contrib / entity_reference_revisions / tests / src / Kernel / EntityReferenceRevisionsCompositeTranslatableFieldTest.php
1 <?php
2
3 namespace Drupal\Tests\entity_reference_revisions\Kernel;
4
5 use Drupal\entity_composite_relationship_test\Entity\EntityTestCompositeRelationship;
6 use Drupal\field\Entity\FieldConfig;
7 use Drupal\field\Entity\FieldStorageConfig;
8 use Drupal\KernelTests\Core\Entity\EntityKernelTestBase;
9 use Drupal\language\Entity\ConfigurableLanguage;
10 use Drupal\node\Entity\Node;
11 use Drupal\node\Entity\NodeType;
12 use Drupal\Tests\node\Traits\ContentTypeCreationTrait;
13 use Drupal\Tests\node\Traits\NodeCreationTrait;
14
15 /**
16  * Tests entity_reference_revisions composites with a translatable field.
17  *
18  * @group entity_reference_revisions
19  */
20 class EntityReferenceRevisionsCompositeTranslatableFieldTest extends EntityKernelTestBase {
21
22   use ContentTypeCreationTrait;
23   use NodeCreationTrait;
24
25   /**
26    * Modules to enable.
27    *
28    * @var array
29    */
30   public static $modules = array(
31     'node',
32     'field',
33     'entity_reference_revisions',
34     'entity_composite_relationship_test',
35     'language',
36     'content_translation'
37   );
38
39   /**
40    * The current database connection.
41    *
42    * @var \Drupal\Core\Database\Connection
43    */
44   protected $database;
45
46   /**
47    * The entity type manager.
48    *
49    * @var \Drupal\Core\Entity\EntityTypeManagerInterface
50    *
51    */
52   protected $entityTypeManager;
53
54   /**
55    * {@inheritdoc}
56    */
57   protected function setUp() {
58     parent::setUp();
59
60     ConfigurableLanguage::createFromLangcode('de')->save();
61     ConfigurableLanguage::createFromLangcode('fr')->save();
62
63     $this->installEntitySchema('entity_test_composite');
64     $this->installSchema('node', ['node_access']);
65
66     // Create article content type.
67     NodeType::create(['type' => 'article', 'name' => 'Article'])->save();
68
69     // Create the reference to the composite entity test.
70     $field_storage = FieldStorageConfig::create(array(
71       'field_name' => 'composite_reference',
72       'entity_type' => 'node',
73       'type' => 'entity_reference_revisions',
74       'settings' => array(
75         'target_type' => 'entity_test_composite'
76       ),
77     ));
78     $field_storage->save();
79     $field = FieldConfig::create(array(
80       'field_storage' => $field_storage,
81       'bundle' => 'article',
82       'translatable' => TRUE,
83     ));
84     $field->save();
85
86     // Inject database connection and entity type manager for the tests.
87     $this->database = \Drupal::database();
88     $this->entityTypeManager = \Drupal::entityTypeManager();
89
90     // @todo content_translation should not be needed for a storage test, but
91     //   \Drupal\Core\Entity\ContentEntityBase::isTranslatable() only returns
92     //   TRUE if the bundle is explicitly translatable.
93     \Drupal::service('content_translation.manager')->setEnabled('node', 'article', TRUE);
94     \Drupal::service('content_translation.manager')->setEnabled('entity_test_composite', 'entity_test_composite', TRUE);
95     \Drupal::service('content_translation.manager')->setBundleTranslationSettings('node', 'article', [
96       'untranslatable_fields_hide' => TRUE,
97     ]);
98     \Drupal::service('entity_type.bundle.info')->clearCachedBundles();
99   }
100
101   /**
102    * Test the storage for handling pending revisions with translations.
103    */
104   public function testCompositePendingRevisionTranslation() {
105     /** @var \Drupal\node\NodeStorageInterface $node_storage */
106     $node_storage = \Drupal::entityTypeManager()->getStorage('node');
107
108     // Create the test composite entity.
109     $composite = EntityTestCompositeRelationship::create([
110       'langcode' => 'en',
111       'name' => 'Initial Source Composite',
112     ]);
113     $composite->save();
114
115     // Create a node with a reference to the test composite entity.
116     $node = Node::create([
117       'langcode' => 'en',
118       'title' => 'Initial Source Node',
119       'type' => 'article',
120       'composite_reference' => $composite,
121     ]);
122     $node->save();
123
124     /** @var \Drupal\node\NodeInterface $node */
125     $node = $node_storage->load($node->id());
126
127     // Assert the revision count.
128     $this->assertRevisionCount(1, 'node', $node->id());
129     $this->assertRevisionCount(1, 'entity_test_composite', $composite->id());
130
131     // Create a translation as a pending revision for both the composite and the
132     // node. While technically, the referenced composite could be the same
133     // entity, for translatable fields, it makes more sense if each translation
134     // points to a separate entity, each only with a single language.
135     $composite_de = $node->get('composite_reference')->entity->createDuplicate();
136     $composite_de->set('langcode', 'de');
137     $composite_de->set('name', 'Pending Revision Composite #1 DE');
138     /** @var \Drupal\node\NodeInterface $node_de */
139     $node_de = $node->addTranslation('de', ['title' => 'Pending Revision Node #1 DE', 'composite_reference' => $composite_de] + $node->toArray());
140     $node_de->setNewRevision(TRUE);
141     $node_de->isDefaultRevision(FALSE);
142     $node_de->save();
143
144     // Assert the revision count.
145     $this->assertRevisionCount(2, 'node', $node->id());
146     $this->assertRevisionCount(1, 'entity_test_composite', $composite->id());
147     $this->assertRevisionCount(1, 'entity_test_composite', $composite_de->id());
148
149     // The DE translation will now reference to a pending revision of the
150     // composite entity but the en translation will reference the existing,
151     // unchanged revision.
152     /** @var \Drupal\node\NodeInterface $node_revision */
153     $node_revision = $node_storage->loadRevision($node_de->getRevisionId());
154     $this->assertFalse($node_revision->isDefaultRevision());
155     $this->assertFalse((bool) $node_revision->isRevisionTranslationAffected());
156     $this->assertEquals('Initial Source Node', $node_revision->label());
157     $this->assertTrue($node_revision->get('composite_reference')->entity->isDefaultRevision());
158     $this->assertEquals('Initial Source Composite', $node_revision->get('composite_reference')->entity->label());
159     $this->assertFalse($node_revision->get('composite_reference')->entity->hasTranslation('de'));
160     $this->assertEquals($node->get('composite_reference')->target_revision_id, $node_revision->get('composite_reference')->target_revision_id);
161
162     $node_de = $node_revision->getTranslation('de');
163     $this->assertTrue((bool) $node_de->isRevisionTranslationAffected());
164     $this->assertEquals('Pending Revision Node #1 DE', $node_de->label());
165     // The composite is the default revision because it is a new entity.
166     $this->assertTrue($node_de->get('composite_reference')->entity->isDefaultRevision());
167     $this->assertEquals('Pending Revision Composite #1 DE', $node_de->get('composite_reference')->entity->label());
168     $this->assertNotEquals($node->get('composite_reference')->target_revision_id, $node_de->get('composite_reference')->target_revision_id);
169
170     // Reload the default revision of the node, make sure that the composite
171     // there is unchanged.
172     $node = $node_storage->load($node->id());
173     $this->assertFalse($node->hasTranslation('de'));
174     $this->assertEquals('Initial Source Node', $node->label());
175     $this->assertFalse($node->get('composite_reference')->entity->hasTranslation('de'));
176     $this->assertEquals('Initial Source Composite', $node->get('composite_reference')->entity->label());
177
178     // Create a second translation revision for FR.
179     $composite_fr = $node->get('composite_reference')->entity->createDuplicate();
180     $composite_fr->set('langcode', 'fr');
181     $composite_fr->set('name', 'Pending Revision Composite #1 FR');
182     $node_fr = $node->addTranslation('fr', ['title' => 'Pending Revision Node #1 FR', 'composite_reference' => $composite_fr] + $node->toArray());
183     $node_fr->setNewRevision(TRUE);
184     $node_fr->isDefaultRevision(FALSE);
185     $node_fr->save();
186
187     // Assert the revision count.
188     $this->assertRevisionCount(3, 'node', $node->id());
189     $this->assertRevisionCount(1, 'entity_test_composite', $composite->id());
190     $this->assertRevisionCount(1, 'entity_test_composite', $composite_de->id());
191     $this->assertRevisionCount(1, 'entity_test_composite', $composite_fr->id());
192
193     // Now assert that all 3 revisions exist as expected. Two translation
194     // pending revisions, each has the original revision as parent without
195     // any existing translation.
196     /** @var \Drupal\node\NodeInterface $node_fr */
197     $node_revision = $node_storage->loadRevision($node_fr->getRevisionId());
198     $this->assertFalse($node_revision->isDefaultRevision());
199     $this->assertFalse((bool) $node_revision->isRevisionTranslationAffected());
200     $this->assertEquals('Initial Source Node', $node_revision->label());
201     $this->assertTrue($node_revision->get('composite_reference')->entity->isDefaultRevision());
202     $this->assertEquals('Initial Source Composite', $node_revision->get('composite_reference')->entity->label());
203     $this->assertFalse($node_revision->get('composite_reference')->entity->hasTranslation('de'));
204     $this->assertEquals($node->get('composite_reference')->target_revision_id, $node_revision->get('composite_reference')->target_revision_id);
205
206     $node_fr = $node_revision->getTranslation('fr');
207     $this->assertTrue((bool) $node_fr->isRevisionTranslationAffected());
208     $this->assertEquals('Pending Revision Node #1 FR', $node_fr->label());
209     $this->assertTrue($node_fr->get('composite_reference')->entity->isDefaultRevision());
210     $this->assertEquals('Pending Revision Composite #1 FR', $node_fr->get('composite_reference')->entity->label());
211     $this->assertNotEquals($node->get('composite_reference')->target_revision_id, $node_fr->get('composite_reference')->target_revision_id);
212
213     $node_de = $node_storage->loadRevision($node_de->getRevisionId())->getTranslation('de');
214     $this->assertTrue((bool) $node_de->isRevisionTranslationAffected());
215     $this->assertEquals('Pending Revision Node #1 DE', $node_de->label());
216     $this->assertTrue($node_de->get('composite_reference')->entity->isDefaultRevision());
217     $this->assertEquals('Pending Revision Composite #1 DE', $node_de->get('composite_reference')->entity->label());
218     $this->assertNotEquals($node->get('composite_reference')->target_revision_id, $node_de->get('composite_reference')->target_revision_id);
219
220     // Reload the default revision of the node, make sure that the composite
221     // there is unchanged.
222     $node = $node_storage->load($node->id());
223     $this->assertFalse($node->hasTranslation('de'));
224     $this->assertEquals('Initial Source Node', $node->label());
225     $this->assertFalse($node->get('composite_reference')->entity->hasTranslation('de'));
226     $this->assertEquals('Initial Source Composite', $node->get('composite_reference')->entity->label());
227
228     // Now make a change to the initial source revision, save as a new default
229     // revision.
230     $initial_revision_id = $node->getRevisionId();
231     $node->get('composite_reference')->entity->set('name', 'Updated Source Composite');
232     $node->setTitle('Updated Source Node');
233     $node->setNewRevision(TRUE);
234     $node->save();
235
236     // Assert the revision count.
237     $this->assertRevisionCount(4, 'node', $node->id());
238     $this->assertRevisionCount(2, 'entity_test_composite', $composite->id());
239     $this->assertRevisionCount(1, 'entity_test_composite', $composite_de->id());
240     $this->assertRevisionCount(1, 'entity_test_composite', $composite_fr->id());
241
242     // Assert the two english revisions.
243     // Reload the default revision of the node, make sure that the composite
244     // there is unchanged.
245     $node = $node_storage->load($node->id());
246     $this->assertTrue($node->isDefaultRevision());
247     $this->assertFalse($node->hasTranslation('de'));
248     $this->assertFalse($node->hasTranslation('fr'));
249     $this->assertTrue((bool) $node->isRevisionTranslationAffected());
250     $this->assertEquals('Updated Source Node', $node->label());
251     $this->assertTrue($node->get('composite_reference')->entity->isDefaultRevision());
252     $this->assertFalse($node->get('composite_reference')->entity->hasTranslation('de'));
253     $this->assertEquals('Updated Source Composite', $node->get('composite_reference')->entity->label());
254
255     $node_initial = $node_storage->loadRevision($initial_revision_id);
256     $this->assertFalse($node_initial->isDefaultRevision());
257     $this->assertFalse($node_initial->hasTranslation('de'));
258     $this->assertFalse($node_initial->hasTranslation('fr'));
259     $this->assertEquals('Initial Source Node', $node_initial->label());
260     $this->assertFalse($node_initial->get('composite_reference')->entity->isDefaultRevision());
261     $this->assertFalse($node_initial->get('composite_reference')->entity->hasTranslation('de'));
262     $this->assertEquals('Initial Source Composite', $node_initial->get('composite_reference')->entity->label());
263
264     // Now publish the FR pending revision.
265     $node_storage->createRevision($node_fr->getTranslation('fr'))->save();
266
267     // Assert the revision count.
268     $this->assertRevisionCount(5, 'node', $node->id());
269     $this->assertRevisionCount(2, 'entity_test_composite', $composite->id());
270     $this->assertRevisionCount(1, 'entity_test_composite', $composite_de->id());
271     $this->assertRevisionCount(1, 'entity_test_composite', $composite_fr->id());
272
273     // The new default revision should now have the updated english source and
274     // the french pending revision.
275     $node = $node_storage->load($node->id());
276     $this->assertTrue($node->isDefaultRevision());
277     $this->assertFalse($node->hasTranslation('de'));
278     $this->assertTrue($node->hasTranslation('fr'));
279     $node_fr = $node->getTranslation('fr');
280     $this->assertFalse((bool) $node->isRevisionTranslationAffected());
281     $this->assertTrue((bool) $node->getTranslation('fr')->isRevisionTranslationAffected());
282     $this->assertEquals('Updated Source Node', $node->label());
283     $this->assertTrue($node->get('composite_reference')->entity->isDefaultRevision());
284     $this->assertFalse($node->get('composite_reference')->entity->hasTranslation('de'));
285     $this->assertTrue($node_fr->get('composite_reference')->entity->hasTranslation('fr'));
286     $this->assertEquals('Pending Revision Node #1 FR', $node_fr->label());
287     $this->assertEquals('Pending Revision Composite #1 FR', $node_fr->get('composite_reference')->entity->getTranslation('fr')->label());
288     $this->assertEquals('Updated Source Composite', $node->get('composite_reference')->entity->label());
289
290     // Now publish the DE pending revision as well.
291     $node_storage->createRevision($node_de->getTranslation('de'))->save();
292
293     // Assert the revision count.
294     $this->assertRevisionCount(6, 'node', $node->id());
295     $this->assertRevisionCount(2, 'entity_test_composite', $composite->id());
296     $this->assertRevisionCount(1, 'entity_test_composite', $composite_de->id());
297     $this->assertRevisionCount(1, 'entity_test_composite', $composite_fr->id());
298
299     // The new default revision should now have the updated source and both
300     // translations.
301     $node = $node_storage->load($node->id());
302     $this->assertTrue($node->isDefaultRevision());
303     $this->assertTrue($node->hasTranslation('de'));
304     $this->assertTrue($node->hasTranslation('fr'));
305     $node_fr = $node->getTranslation('fr');
306     $node_de = $node->getTranslation('de');
307     $this->assertFalse((bool) $node->isRevisionTranslationAffected());
308     $this->assertFalse((bool) $node->getTranslation('fr')->isRevisionTranslationAffected());
309     $this->assertTrue((bool) $node->getTranslation('de')->isRevisionTranslationAffected());
310     $this->assertEquals('Updated Source Node', $node->label());
311
312     // Each translation only has the composite in its translation.
313     $this->assertTrue($node->get('composite_reference')->entity->hasTranslation('en'));
314     $this->assertFalse($node->get('composite_reference')->entity->hasTranslation('de'));
315     $this->assertFalse($node->get('composite_reference')->entity->hasTranslation('fr'));
316     $this->assertFalse($node_fr->get('composite_reference')->entity->hasTranslation('en'));
317     $this->assertTrue($node_fr->get('composite_reference')->entity->hasTranslation('fr'));
318     $this->assertFalse($node_fr->get('composite_reference')->entity->hasTranslation('de'));
319     $this->assertFalse($node_de->get('composite_reference')->entity->hasTranslation('en'));
320     $this->assertTrue($node_de->get('composite_reference')->entity->hasTranslation('de'));
321     $this->assertFalse($node_de->get('composite_reference')->entity->hasTranslation('fr'));
322
323     $this->assertEquals('Pending Revision Node #1 FR', $node_fr->label());
324     $this->assertEquals('Pending Revision Composite #1 FR', $node_fr->get('composite_reference')->entity->getTranslation('fr')->label());
325     $this->assertEquals('Pending Revision Node #1 DE', $node_de->label());
326     $this->assertEquals('Pending Revision Composite #1 DE', $node_de->get('composite_reference')->entity->getTranslation('de')->label());
327     $this->assertEquals('Updated Source Composite', $node->get('composite_reference')->entity->label());
328   }
329
330   /**
331    * Asserts the revision count of a certain entity.
332    *
333    * @param int $expected
334    *   The expected count.
335    * @param string $entity_type_id
336    *   The entity type ID, e.g. node.
337    * @param int $entity_id
338    *   The entity ID.
339    */
340   protected function assertRevisionCount($expected, $entity_type_id, $entity_id) {
341     $id_field = \Drupal::entityTypeManager()->getDefinition($entity_type_id)->getKey('id');
342
343     $revision_count = \Drupal::entityQuery($entity_type_id)
344       ->condition($id_field, $entity_id)
345       ->allRevisions()
346       ->count()
347       ->execute();
348     $this->assertEquals($expected, $revision_count);
349   }
350
351 }