/**
  * Tests some possible entity table updates for a revision view.
  */
 public function testVariousTableUpdatesForRevisionView()
 {
     // base + revision <-> base + translation + revision
     $this->updateEntityTypeToRevisionable();
     // Multiple changes, so we have to invalidate the caches, otherwise
     // the second update will revert the first.
     $this->entityManager->clearCachedDefinitions();
     list($view, $display) = $this->getUpdatedViewAndDisplay(TRUE);
     $this->assertEqual('entity_test_update_revision', $view->get('base_table'));
     $this->assertEqual('entity_test_update_revision', $display['display_options']['fields']['id']['table']);
     $this->assertEqual('entity_test_update_revision', $display['display_options']['fields']['name']['table']);
     $this->updateEntityTypeToTranslatable();
     $this->entityDefinitionUpdateManager->applyUpdates();
     list($view, $display) = $this->getUpdatedViewAndDisplay(TRUE);
     $this->assertEqual('entity_test_update_revision', $view->get('base_table'));
     $this->assertEqual('entity_test_update_revision', $display['display_options']['fields']['id']['table']);
     $this->assertEqual('entity_test_update_revision_data', $display['display_options']['fields']['name']['table']);
     $this->updateEntityTypeToNotTranslatable();
     $this->entityDefinitionUpdateManager->applyUpdates();
     list($view, $display) = $this->getUpdatedViewAndDisplay(TRUE);
     $this->assertEqual('entity_test_update_revision', $view->get('base_table'));
     $this->assertEqual('entity_test_update_revision', $display['display_options']['fields']['id']['table']);
     $this->assertEqual('entity_test_update_revision', $display['display_options']['fields']['name']['table']);
     $this->resetEntityType();
 }
 /**
  * {@inheritdoc}
  */
 public function applyNewStorage()
 {
     // The first call is for making entity types revisionable, the second call
     // is for adding required fields.
     $this->updateManager->applyUpdates();
     $this->updateManager->applyUpdates();
     return $this;
 }
 /**
  * Asserts the given module can be installed and uninstalled.
  *
  * @param string $module_name
  *   The module to install and uninstall.
  */
 protected function assertModuleInstallUninstall($module_name)
 {
     $this->enableModules([$module_name]);
     $this->entityDefinitionUpdateManager->applyUpdates();
     $this->assertTrue($this->getModuleHandler()->moduleExists($module_name), $module_name . ' module is enabled.');
     $this->getModuleInstaller()->uninstall([$module_name]);
     $this->entityDefinitionUpdateManager->applyUpdates();
     $this->assertFalse($this->getModuleHandler()->moduleExists($module_name), $module_name . ' module is disabled.');
 }
 /**
  * Tests that entity updates are correctly reported in the status report page.
  */
 function testStatusReport()
 {
     // Create a test entity.
     $entity = EntityTest::create(['name' => $this->randomString(), 'user_id' => mt_rand()]);
     $entity->save();
     // Check that the status report initially displays no error.
     $this->drupalGet('admin/reports/status');
     $this->assertNoRaw('Out of date');
     $this->assertNoRaw('Mismatched entity and/or field definitions');
     // Enable an entity update and check that we have a dedicated status report
     // item.
     $this->container->get('state')->set('entity_test.remove_name_field', TRUE);
     $this->drupalGet('admin/reports/status');
     $this->assertNoRaw('Out of date');
     $this->assertRaw('Mismatched entity and/or field definitions');
     // Enable a db update and check that now the entity update status report
     // item is no longer displayed. We assume an update function will fix the
     // mismatch.
     $this->enableUpdates('entity_test', 'status_report', 8001);
     $this->drupalGet('admin/reports/status');
     $this->assertRaw('Out of date');
     $this->assertRaw('Mismatched entity and/or field definitions');
     // Apply db updates and check that entity updates were not applied.
     $this->applyUpdates();
     $this->drupalGet('admin/reports/status');
     $this->assertNoRaw('Out of date');
     $this->assertRaw('Mismatched entity and/or field definitions');
     // Check that en exception would be triggered when trying to apply them with
     // existing data.
     $message = 'Entity updates cannot run if entity data exists.';
     try {
         $this->updatesManager->applyUpdates();
         $this->fail($message);
     } catch (FieldStorageDefinitionUpdateForbiddenException $e) {
         $this->pass($message);
     }
     // Check the status report is the same after trying to apply updates.
     $this->drupalGet('admin/reports/status');
     $this->assertNoRaw('Out of date');
     $this->assertRaw('Mismatched entity and/or field definitions');
     // Delete entity data, enable a new update, run updates again and check that
     // entity updates were not applied even when no data exists.
     $entity->delete();
     $this->enableUpdates('entity_test', 'status_report', 8002);
     $this->applyUpdates();
     $this->drupalGet('admin/reports/status');
     $this->assertNoRaw('Out of date');
     $this->assertRaw('Mismatched entity and/or field definitions');
 }
 /**
  * Tests updating entity schema and creating a revisionable base field.
  *
  * This tests updating entity schema and creating a revisionable base field
  * at the same time when there are no existing entities.
  */
 public function testEntityTypeSchemaUpdateAndRevisionableBaseFieldCreateWithoutData()
 {
     $this->updateEntityTypeToRevisionable();
     $this->addRevisionableBaseField();
     $message = 'Successfully updated entity schema and created revisionable base field at the same time.';
     // Entity type updates create base fields as well, thus make sure doing both
     // at the same time does not lead to errors due to the base field being
     // created twice.
     try {
         $this->entityDefinitionUpdateManager->applyUpdates();
         $this->pass($message);
     } catch (\Exception $e) {
         $this->fail($message);
         throw $e;
     }
 }
 /**
  * Ensures that a new entity level index is created when data exists.
  *
  * @see Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema::onEntityTypeUpdate
  */
 public function testCreateIndexUsingEntityStorageSchemaWithData()
 {
     // Save an entity.
     $name = $this->randomString();
     $storage = $this->entityManager->getStorage('entity_test_update');
     $entity = $storage->create(array('name' => $name));
     $entity->save();
     // Create an index.
     $indexes = array('entity_test_update__type_index' => array('type'));
     $this->state->set('entity_test_update.additional_entity_indexes', $indexes);
     $this->entityDefinitionUpdateManager->applyUpdates();
     $this->assertTrue($this->database->schema()->indexExists('entity_test_update', 'entity_test_update__type_index'), "New index 'entity_test_update__type_index' has been created on the 'entity_test_update' table.");
     // Check index size in for MySQL.
     if (Database::getConnection()->driver() == 'mysql') {
         $result = Database::getConnection()->query('SHOW INDEX FROM {entity_test_update} WHERE key_name = \'entity_test_update__type_index\' and column_name = \'type\'')->fetchObject();
         $this->assertEqual(191, $result->Sub_part, 'The index length has been restricted to 191 characters for UTF8MB4 compatibility.');
     }
 }
 /**
  * Tests creating a multi-field index when there are existing entities.
  */
 public function testEntityIndexCreateWithData()
 {
     // Save an entity.
     $name = $this->randomString();
     $entity = $this->entityManager->getStorage('entity_test_update')->create(array('name' => $name));
     $entity->save();
     // Add an entity index, run the update. For now, it's expected to throw an
     // exception.
     // @todo Improve SqlContentEntityStorageSchema::requiresEntityDataMigration()
     //   to return FALSE when only index changes are required, so that it can be
     //   applied on top of existing data: https://www.drupal.org/node/2340993.
     $this->addEntityIndex();
     try {
         $this->entityDefinitionUpdateManager->applyUpdates();
         $this->fail('EntityStorageException thrown when trying to apply an update that requires data migration.');
     } catch (EntityStorageException $e) {
         $this->pass('EntityStorageException thrown when trying to apply an update that requires data migration.');
     }
 }
 /**
  * Tests updating a base field when it has existing data.
  */
 public function testBaseFieldEntityKeyUpdateWithExistingData()
 {
     // Add the base field and run the update.
     $this->addBaseField();
     $this->entityDefinitionUpdateManager->applyUpdates();
     // Save an entity with the base field populated.
     $this->entityManager->getStorage('entity_test_update')->create(['new_base_field' => $this->randomString()])->save();
     // Save an entity with the base field not populated.
     /** @var \Drupal\entity_test\Entity\EntityTestUpdate $entity */
     $entity = $this->entityManager->getStorage('entity_test_update')->create();
     $entity->save();
     // Promote the base field to an entity key. This will trigger the addition
     // of a NOT NULL constraint.
     $this->makeBaseFieldEntityKey();
     // Try to apply the update and verify they fail since we have a NULL value.
     $message = 'An error occurs when trying to enabling NOT NULL constraints with NULL data.';
     try {
         $this->entityDefinitionUpdateManager->applyUpdates();
         $this->fail($message);
     } catch (EntityStorageException $e) {
         $this->pass($message);
     }
     // Check that the update is correctly applied when no NULL data is left.
     $entity->set('new_base_field', $this->randomString());
     $entity->save();
     $this->entityDefinitionUpdateManager->applyUpdates();
     $this->pass('The update is correctly performed when no NULL data exists.');
     // Check that the update actually applied a NOT NULL constraint.
     $entity->set('new_base_field', NULL);
     $message = 'The NOT NULL constraint was correctly applied.';
     try {
         $entity->save();
         $this->fail($message);
     } catch (EntityStorageException $e) {
         $this->pass($message);
     }
 }