diff --git a/core/modules/datetime/datetime.install b/core/modules/datetime/datetime.install index ae63a92f01..4153f120ea 100644 --- a/core/modules/datetime/datetime.install +++ b/core/modules/datetime/datetime.install @@ -5,14 +5,14 @@ * Contains update functions for the Datetime module. */ +use Drupal\datetime\Plugin\Field\FieldType\DateTimeItem; +use Drupal\datetime\Plugin\Field\FieldType\DateTimeItemInterface; use Drupal\field\Entity\FieldStorageConfig; /** * Update datetime fields to explicitly store UTC time zone offset (+00:00). */ function datetime_update_8601(&$sandbox) { - // Update field storage for existing datetime fields. - /** @var \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager */ $entity_type_manager = \Drupal::getContainer()->get('entity_type.manager'); /** @var \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager */ @@ -23,8 +23,9 @@ function datetime_update_8601(&$sandbox) { $entity_type_manager->useCaches(FALSE); $entity_field_manager->useCaches(FALSE); + // Build up the list of entity/fields that need to be updated. At this point, + // we know what needs to be updated because there is a schema mismatch. $change_list = []; - foreach ($entity_type_manager->getDefinitions() as $entity_type_id => $entity_type) { if ($entity_type_manager->getStorage($entity_type_id) instanceof \Drupal\Core\Entity\Schema\DynamicallyFieldableEntityStorageSchemaInterface) { $field_changes = []; @@ -32,11 +33,10 @@ function datetime_update_8601(&$sandbox) { $storage_definitions = $entity_field_manager->getFieldStorageDefinitions($entity_type_id); $original_storage_definitions = $entity_last_installed_schema_repository->getLastInstalledFieldStorageDefinitions($entity_type_id); - // Detect updated field storage definitions. foreach (array_intersect_key($storage_definitions, $original_storage_definitions) as $field_name => $storage_definition) { if ($storage_definition->getType() === 'datetime') { if ($entity_type_manager->getStorage($entity_type_id)->requiresFieldStorageSchemaChanges($storage_definition, $original_storage_definitions[$field_name])) { - $field_changes[$field_name] = TRUE; + $field_changes[$field_name] = $storage_definition->getSetting('datetime_type'); } } } @@ -52,6 +52,9 @@ function datetime_update_8601(&$sandbox) { } } + // Loop through the change list an update the schema in storage, the fields + // in SQL, and the field values. + $field_spec = [ 'description' => 'The date value.', 'type' => 'varchar', @@ -66,7 +69,7 @@ function datetime_update_8601(&$sandbox) { $schema = \Drupal::keyValue('entity.storage_schema.sql')->getAll(); foreach ($change_list as $entity_type_id => $changes) { - foreach (array_keys($changes['field_storage_definitions']) as $field_name) { + foreach ($changes['field_storage_definitions'] as $field_name => $datetime_type) { $value_field_name = $field_name . '_value'; $key = "{$entity_type_id}.field_schema_data.{$field_name}"; @@ -76,13 +79,14 @@ function datetime_update_8601(&$sandbox) { $schema[$key][$base_table]['fields'][$field_name . '_value']['length'] = 25; - \Drupal::database() - ->update($base_table) - ->expression($value_field_name, "CONCAT({$value_field_name}, :offset)", [ - ':offset' => '+00:00', - ]) - ->where("LENGTH({$value_field_name}) = 19") - ->execute(); + if ($datetime_type !== DateTimeItem::DATETIME_TYPE_DATE) { + \Drupal::database() + ->update($base_table) + ->expression($value_field_name, "CONCAT({$value_field_name}, :offset)", [ + ':offset' => '+00:00', + ]) + ->execute(); + } if ($changes['revision_table']) { $revision_table = $changes['revision_table'] . '__' . $field_name; @@ -91,18 +95,20 @@ function datetime_update_8601(&$sandbox) { $schema[$key][$revision_table]['fields'][$field_name . '_value']['length'] = 25; - \Drupal::database() - ->update($revision_table) - ->expression($value_field_name, "CONCAT({$value_field_name}, :offset)", [ - ':offset' => '+00:00', - ]) - ->where("LENGTH({$value_field_name}) = 19") - ->execute(); + if ($datetime_type !== DateTimeItem::DATETIME_TYPE_DATE) { + \Drupal::database() + ->update($revision_table) + ->expression($value_field_name, "CONCAT({$value_field_name}, :offset)", [ + ':offset' => '+00:00', + ]) + ->execute(); + } } } } \Drupal::keyValue('entity.storage_schema.sql')->setMultiple($schema); + // Loop though the field storage definitions and update the schema. $definitions = \Drupal::keyValue('entity.definitions.installed')->getAll(); $definitions_copy = $definitions; foreach ($definitions as $item_name => $item_value) { diff --git a/core/modules/datetime/tests/src/Functional/Update/DateTimeUpdate8601Test.php b/core/modules/datetime/tests/src/Functional/Update/DateTimeUpdate8601Test.php new file mode 100644 index 0000000000..143ea31ebe --- /dev/null +++ b/core/modules/datetime/tests/src/Functional/Update/DateTimeUpdate8601Test.php @@ -0,0 +1,88 @@ +databaseDumpFiles = [ + __DIR__ . '/../../../../../system/tests/fixtures/update/drupal-8.filled.standard.php.gz', + ]; + } + + /** + * Test that the column length is updated. + */ + public function testFieldDefinition() { + /** @var \Drupal\Core\Entity\EntityLastInstalledSchemaRepositoryInterface $entity_last_installed_schema_repository */ + $entity_last_installed_schema_repository = \Drupal::getContainer()->get('entity.last_installed_schema.repository'); + $field_definitions = $entity_last_installed_schema_repository->getLastInstalledFieldStorageDefinitions('node'); + $schema = $field_definitions['field_test_3']->getSchema(); + $this->assertEquals(20, $schema['columns']['value']['length']); + + $this->runUpdates(); + + $field_definition = \Drupal::entityDefinitionUpdateManager()->getFieldStorageDefinition('field_test_3', 'node'); + $schema = $field_definition->getSchema(); + $this->assertEquals(25, $schema['columns']['value']['length']); + } + + /** + * Test that date-only fields do not get modified. + */ + public function testDateonly() { + $node = Node::load(8); + $this->assertEquals('2015-08-16', $node->field_test_3); + + $this->runUpdates(); + + $node = Node::load(8); + $this->assertEquals('2015-08-16', $node->field_test_3); + } + + /** + * Test that datetime fields get modified. + */ + public function testDatetime() { + $fieldStorage = FieldStorageConfig::create([ + 'field_name' => 'field_datetime', + 'entity_type' => 'node', + 'type' => 'datetime', + 'settings' => ['datetime_type' => DateTimeItem::DATETIME_TYPE_DATETIME], + ]); + $fieldStorage->save(); + + $field = FieldConfig::create([ + 'field_storage' => $fieldStorage, + 'label' => 'Datetime', + 'bundle' => 'test_content_type', + 'description' => 'Description for Datetime', + 'required' => TRUE, + ]); + $field->save(); + + $node = Node::load(8); + $node->field_datetime = '2018-02-03T17:05:00'; + $node->save(); + + $this->runUpdates(); + + $node = Node::load(8); + $this->assertEquals('2018-02-03T17:05:00+00:00', $node->field_datetime); + } + +}