3 namespace Drupal\Tests\system\Functional\Entity;
5 use Drupal\entity_test\Entity\EntityTestMulRev;
6 use Drupal\field\Entity\FieldConfig;
7 use Drupal\field\Entity\FieldStorageConfig;
8 use Drupal\language\Entity\ConfigurableLanguage;
9 use Drupal\Tests\BrowserTestBase;
12 * Create a entity with revisions and test viewing, saving, reverting, and
17 class EntityRevisionsTest extends BrowserTestBase {
24 public static $modules = ['entity_test', 'language'];
27 * A user with permission to administer entity_test content.
29 * @var \Drupal\user\UserInterface
33 protected function setUp() {
36 // Create and log in user.
37 $this->webUser = $this->drupalCreateUser([
38 'administer entity_test content',
41 $this->drupalLogin($this->webUser);
43 // Enable an additional language.
44 ConfigurableLanguage::createFromLangcode('de')->save();
48 * Check node revision related operations.
50 public function testRevisions() {
52 // All revisable entity variations have to have the same results.
53 foreach (entity_test_entity_types(ENTITY_TEST_TYPES_REVISABLE) as $entity_type) {
54 $this->runRevisionsTests($entity_type);
59 * Executes the revision tests for the given entity type.
61 * @param string $entity_type
62 * The entity type to run the tests with.
64 protected function runRevisionsTests($entity_type) {
65 // Create a translatable test field.
66 $field_storage = FieldStorageConfig::create([
67 'entity_type' => $entity_type,
68 'field_name' => 'translatable_test_field',
72 $field_storage->save();
74 $field = FieldConfig::create([
75 'field_storage' => $field_storage,
76 'label' => $this->randomMachineName(),
77 'bundle' => $entity_type,
78 'translatable' => TRUE,
82 entity_get_form_display($entity_type, $entity_type, 'default')
83 ->setComponent('translatable_test_field')
86 /** @var \Drupal\Core\Entity\ContentEntityStorageInterface $storage */
87 $storage = \Drupal::entityTypeManager()->getStorage($entity_type);
89 // Create initial entity.
90 /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
94 'user_id' => $this->webUser->id(),
96 $entity->translatable_test_field->value = 'bar';
97 $entity->addTranslation('de', ['name' => 'foo - de']);
103 // Create three revisions.
105 for ($i = 0; $i < $revision_count; $i++) {
106 $legacy_revision_id = $entity->revision_id->value;
107 $legacy_name = $entity->name->value;
108 $legacy_text = $entity->translatable_test_field->value;
110 $entity = $storage->load($entity->id->value);
111 $entity->setNewRevision(TRUE);
112 $values['en'][$i] = [
113 'name' => $this->randomMachineName(32),
114 'translatable_test_field' => [
115 $this->randomMachineName(32),
116 $this->randomMachineName(32),
118 'created' => time() + $i + 1,
120 $entity->set('name', $values['en'][$i]['name']);
121 $entity->set('translatable_test_field', $values['en'][$i]['translatable_test_field']);
122 $entity->set('created', $values['en'][$i]['created']);
124 $revision_ids[] = $entity->revision_id->value;
126 // Add some values for a translation of this revision.
127 if ($entity->getEntityType()->isTranslatable()) {
128 $values['de'][$i] = [
129 'name' => $this->randomMachineName(32),
130 'translatable_test_field' => [
131 $this->randomMachineName(32),
132 $this->randomMachineName(32),
135 $translation = $entity->getTranslation('de');
136 $translation->set('name', $values['de'][$i]['name']);
137 $translation->set('translatable_test_field', $values['de'][$i]['translatable_test_field']);
138 $translation->save();
141 // Check that the fields and properties contain new content.
142 $this->assertTrue($entity->revision_id->value > $legacy_revision_id, format_string('%entity_type: Revision ID changed.', ['%entity_type' => $entity_type]));
143 $this->assertNotEqual($entity->name->value, $legacy_name, format_string('%entity_type: Name changed.', ['%entity_type' => $entity_type]));
144 $this->assertNotEqual($entity->translatable_test_field->value, $legacy_text, format_string('%entity_type: Text changed.', ['%entity_type' => $entity_type]));
147 $revisions = $storage->loadMultipleRevisions($revision_ids);
148 for ($i = 0; $i < $revision_count; $i++) {
149 // Load specific revision.
150 $entity_revision = $revisions[$revision_ids[$i]];
152 // Check if properties and fields contain the revision specific content.
153 $this->assertEqual($entity_revision->revision_id->value, $revision_ids[$i], format_string('%entity_type: Revision ID matches.', ['%entity_type' => $entity_type]));
154 $this->assertEqual($entity_revision->name->value, $values['en'][$i]['name'], format_string('%entity_type: Name matches.', ['%entity_type' => $entity_type]));
155 $this->assertEqual($entity_revision->translatable_test_field[0]->value, $values['en'][$i]['translatable_test_field'][0], format_string('%entity_type: Text matches.', ['%entity_type' => $entity_type]));
156 $this->assertEqual($entity_revision->translatable_test_field[1]->value, $values['en'][$i]['translatable_test_field'][1], format_string('%entity_type: Text matches.', ['%entity_type' => $entity_type]));
158 // Check the translated values.
159 if ($entity->getEntityType()->isTranslatable()) {
160 $revision_translation = $entity_revision->getTranslation('de');
161 $this->assertEqual($revision_translation->name->value, $values['de'][$i]['name'], format_string('%entity_type: Name matches.', ['%entity_type' => $entity_type]));
162 $this->assertEqual($revision_translation->translatable_test_field[0]->value, $values['de'][$i]['translatable_test_field'][0], format_string('%entity_type: Text matches.', ['%entity_type' => $entity_type]));
163 $this->assertEqual($revision_translation->translatable_test_field[1]->value, $values['de'][$i]['translatable_test_field'][1], format_string('%entity_type: Text matches.', ['%entity_type' => $entity_type]));
166 // Check non-revisioned values are loaded.
167 $this->assertTrue(isset($entity_revision->created->value), format_string('%entity_type: Non-revisioned field is loaded.', ['%entity_type' => $entity_type]));
168 $this->assertEqual($entity_revision->created->value, $values['en'][2]['created'], format_string('%entity_type: Non-revisioned field value is the same between revisions.', ['%entity_type' => $entity_type]));
171 // Confirm the correct revision text appears in the edit form.
172 $entity = $storage->load($entity->id->value);
173 $this->drupalGet($entity_type . '/manage/' . $entity->id->value . '/edit');
174 $this->assertFieldById('edit-name-0-value', $entity->name->value, format_string('%entity_type: Name matches in UI.', ['%entity_type' => $entity_type]));
175 $this->assertFieldById('edit-translatable-test-field-0-value', $entity->translatable_test_field->value, format_string('%entity_type: Text matches in UI.', ['%entity_type' => $entity_type]));
179 * Tests that an entity revision is upcasted in the correct language.
181 public function testEntityRevisionParamConverter() {
182 // Create a test entity with multiple revisions and translations for them.
183 $entity = EntityTestMulRev::create([
184 'name' => 'default revision - en',
185 'user_id' => $this->webUser,
188 $entity->addTranslation('de', ['name' => 'default revision - de']);
191 $pending_revision = \Drupal::entityTypeManager()->getStorage('entity_test_mulrev')->loadUnchanged($entity->id());
193 $pending_revision->setNewRevision();
194 $pending_revision->isDefaultRevision(FALSE);
196 $pending_revision->name = 'pending revision - en';
197 $pending_revision->save();
199 $pending_revision_translation = $pending_revision->getTranslation('de');
200 $pending_revision_translation->name = 'pending revision - de';
201 $pending_revision_translation->save();
203 // Check that the entity revision is upcasted in the correct language.
204 $revision_url = 'entity_test_mulrev/' . $entity->id() . '/revision/' . $pending_revision->getRevisionId() . '/view';
206 $this->drupalGet($revision_url);
207 $this->assertText('pending revision - en');
208 $this->assertNoText('pending revision - de');
210 $this->drupalGet('de/' . $revision_url);
211 $this->assertText('pending revision - de');
212 $this->assertNoText('pending revision - en');
216 * Tests manual revert of the revision ID value.
218 * @covers \Drupal\Core\Entity\ContentEntityBase::getRevisionId
219 * @covers \Drupal\Core\Entity\ContentEntityBase::getLoadedRevisionId
220 * @covers \Drupal\Core\Entity\ContentEntityBase::setNewRevision
221 * @covers \Drupal\Core\Entity\ContentEntityBase::isNewRevision
223 public function testNewRevisionRevert() {
224 $entity = EntityTestMulRev::create(['name' => 'EntityLoadedRevisionTest']);
227 // Check that revision ID field is reset while the loaded revision ID is
228 // preserved when flagging a new revision.
229 $revision_id = $entity->getRevisionId();
230 $entity->setNewRevision();
231 $this->assertNull($entity->getRevisionId());
232 $this->assertEquals($revision_id, $entity->getLoadedRevisionId());
233 $this->assertTrue($entity->isNewRevision());
235 // Check that after manually restoring the original revision ID, the entity
236 // is stored without creating a new revision.
237 $key = $entity->getEntityType()->getKey('revision');
238 $entity->set($key, $revision_id);
240 $this->assertEquals($revision_id, $entity->getRevisionId());
241 $this->assertEquals($revision_id, $entity->getLoadedRevisionId());
243 // Check that manually restoring the original revision ID causes the "new
244 // revision" state to be reverted.
245 $entity->setNewRevision();
246 $this->assertNull($entity->getRevisionId());
247 $this->assertEquals($revision_id, $entity->getLoadedRevisionId());
248 $this->assertTrue($entity->isNewRevision());
249 $entity->set($key, $revision_id);
250 $this->assertFalse($entity->isNewRevision());
251 $this->assertEquals($revision_id, $entity->getRevisionId());
252 $this->assertEquals($revision_id, $entity->getLoadedRevisionId());
254 // Check that flagging a new revision again works correctly.
255 $entity->setNewRevision();
256 $this->assertNull($entity->getRevisionId());
257 $this->assertEquals($revision_id, $entity->getLoadedRevisionId());
258 $this->assertTrue($entity->isNewRevision());
260 // Check that calling setNewRevision() on a new entity without a revision ID
261 // and then with a revision ID does not unset the revision ID.
262 $entity = EntityTestMulRev::create(['name' => 'EntityLoadedRevisionTest']);
263 $entity->set('revision_id', NULL);
264 $entity->set('revision_id', 5);
265 $this->assertTrue($entity->isNewRevision());
266 $entity->setNewRevision();
267 $this->assertEquals(5, $entity->get('revision_id')->value);