From 626a6aa3e1491b499ac0da82a86865f678f3a142 Mon Sep 17 00:00:00 2001 From: Lee Rowlands Date: Wed, 21 Aug 2019 18:42:29 +1000 Subject: [PATCH] Issue #3007102 by mikelutz, juampynr, DamienMcKenna, vpa24: Migrating to Date-only field does not drop time value --- .../src/Plugin/migrate/field/DateField.php | 23 +++++- .../migrate/field/DateFieldLegacyTest.php | 19 ++++- .../Plugin/migrate/field/DateFieldTest.php | 75 +++++++++++++++++-- .../src/Kernel/Migrate/d7/MigrateNodeTest.php | 3 + 4 files changed, 110 insertions(+), 10 deletions(-) diff --git a/core/modules/datetime/src/Plugin/migrate/field/DateField.php b/core/modules/datetime/src/Plugin/migrate/field/DateField.php index 876c9da09b6..8bae1069090 100644 --- a/core/modules/datetime/src/Plugin/migrate/field/DateField.php +++ b/core/modules/datetime/src/Plugin/migrate/field/DateField.php @@ -2,11 +2,14 @@ namespace Drupal\datetime\Plugin\migrate\field; +use Drupal\datetime\Plugin\Field\FieldType\DateTimeItemInterface; use Drupal\migrate\Plugin\MigrationInterface; use Drupal\migrate\MigrateException; use Drupal\migrate_drupal\Plugin\migrate\field\FieldPluginBase; /** + * Provides a field plugin for date and time fields. + * * @MigrateField( * id = "datetime", * type_map = { @@ -45,19 +48,35 @@ class DateField extends FieldPluginBase { * {@inheritdoc} */ public function defineValueProcessPipeline(MigrationInterface $migration, $field_name, $data) { + $to_format = DateTimeItemInterface::DATETIME_STORAGE_FORMAT; + if (isset($data['field_definition']['data'])) { + $field_data = unserialize($data['field_definition']['data']); + if (isset($field_data['settings']['granularity'])) { + $granularity = $field_data['settings']['granularity']; + if ($granularity = $field_data['settings']['granularity'] && + $granularity['hour'] === 0 && + $granularity['minute'] === 0 && + $granularity['second'] === 0) { + + $to_format = DateTimeItemInterface::DATE_STORAGE_FORMAT; + } + } + } + switch ($data['type']) { case 'date': $from_format = 'Y-m-d\TH:i:s'; - $to_format = 'Y-m-d\TH:i:s'; break; + case 'datestamp': $from_format = 'U'; $to_format = 'U'; break; + case 'datetime': $from_format = 'Y-m-d H:i:s'; - $to_format = 'Y-m-d\TH:i:s'; break; + default: throw new MigrateException(sprintf('Field %s of type %s is an unknown date field type.', $field_name, var_export($data['type'], TRUE))); } diff --git a/core/modules/datetime/tests/src/Unit/Plugin/migrate/field/DateFieldLegacyTest.php b/core/modules/datetime/tests/src/Unit/Plugin/migrate/field/DateFieldLegacyTest.php index fb51066196c..897826d5e91 100644 --- a/core/modules/datetime/tests/src/Unit/Plugin/migrate/field/DateFieldLegacyTest.php +++ b/core/modules/datetime/tests/src/Unit/Plugin/migrate/field/DateFieldLegacyTest.php @@ -2,17 +2,30 @@ namespace Drupal\Tests\datetime\Unit\Plugin\migrate\field; +use Drupal\datetime\Plugin\migrate\field\DateField; +use Drupal\migrate\MigrateException; +use Drupal\Tests\UnitTestCase; + /** + * Tests legacy methods on the date_field plugin. + * * @group migrate * @group legacy */ -class DateFieldLegacyTest extends DateFieldTest { +class DateFieldLegacyTest extends UnitTestCase { /** + * Tests deprecation on calling processFieldValues(). + * * @expectedDeprecation Deprecated in Drupal 8.6.0, to be removed before Drupal 9.0.0. Use defineValueProcessPipeline() instead. See https://www.drupal.org/node/2944598. */ - public function testUnknownDateType($method = 'processFieldValues') { - parent::testUnknownDateType($method); + public function testUnknownDateType() { + $migration = $this->prophesize('Drupal\migrate\Plugin\MigrationInterface')->reveal(); + $plugin = new DateField([], '', []); + + $this->expectException(MigrateException::class); + $this->expectExceptionMessage("Field field_date of type 'timestamp' is an unknown date field type."); + $plugin->processFieldValues($migration, 'field_date', ['type' => 'timestamp']); } } diff --git a/core/modules/datetime/tests/src/Unit/Plugin/migrate/field/DateFieldTest.php b/core/modules/datetime/tests/src/Unit/Plugin/migrate/field/DateFieldTest.php index b12694adc75..43bac7e22d2 100644 --- a/core/modules/datetime/tests/src/Unit/Plugin/migrate/field/DateFieldTest.php +++ b/core/modules/datetime/tests/src/Unit/Plugin/migrate/field/DateFieldTest.php @@ -7,20 +7,85 @@ use Drupal\migrate\MigrateException; use Drupal\Tests\UnitTestCase; /** + * Provides unit tests for the DateField Plugin. + * + * @coversDefaultClass \Drupal\datetime\Plugin\migrate\field\DateField + * * @group migrate */ class DateFieldTest extends UnitTestCase { /** - * Tests an Exception is thrown when the field type is not a known date type. + * Tests defineValueProcessPipeline. + * + * @covers ::defineValueProcessPipeline + * + * @dataProvider providerTestDefineValueProcessPipeline */ - public function testUnknownDateType($method = 'defineValueProcessPipeline') { - $migration = $this->prophesize('Drupal\migrate\Plugin\MigrationInterface')->reveal(); + public function testDefineValueProcessPipeline($data, $from_format, $to_format) { + $migration = $this->createMock('Drupal\migrate\Plugin\MigrationInterface'); + $migration->expects($this->once()) + ->method('mergeProcessOfProperty') + ->with('field_date', [ + 'plugin' => 'sub_process', + 'source' => 'field_date', + 'process' => [ + 'value' => [ + 'plugin' => 'format_date', + 'from_format' => $from_format, + 'to_format' => $to_format, + 'source' => 'value', + ], + ], + ]) + ->will($this->returnValue($migration)); + + $plugin = new DateField([], '', []); + $plugin->defineValueProcessPipeline($migration, 'field_date', $data); + } + + /** + * Provides data for testDefineValueProcessPipeline(). + */ + public function providerTestDefineValueProcessPipeline() { + return [ + [['type' => 'date'], 'Y-m-d\TH:i:s', 'Y-m-d\TH:i:s'], + [['type' => 'datestamp'], 'U', 'U'], + [['type' => 'datetime'], 'Y-m-d H:i:s', 'Y-m-d\TH:i:s'], + [ + [ + 'type' => 'datetime', + 'field_definition' => [ + 'data' => serialize([ + 'settings' => [ + 'granularity' => [ + 'hour' => 0, + 'minute' => 0, + 'second' => 0, + ], + ], + ]), + ], + ], + 'Y-m-d H:i:s', + 'Y-m-d', + ], + ]; + } + + /** + * Tests invalid date types throw an exception. + * + * @covers ::defineValueProcessPipeline + */ + public function testDefineValueProcessPipelineException() { + $migration = $this->createMock('Drupal\migrate\Plugin\MigrationInterface'); + $plugin = new DateField([], '', []); $this->expectException(MigrateException::class); - $this->expectExceptionMessage("Field field_date of type 'timestamp' is an unknown date field type."); - $plugin->$method($migration, 'field_date', ['type' => 'timestamp']); + + $plugin->defineValueProcessPipeline($migration, 'field_date', ['type' => 'totoro']); } } diff --git a/core/modules/node/tests/src/Kernel/Migrate/d7/MigrateNodeTest.php b/core/modules/node/tests/src/Kernel/Migrate/d7/MigrateNodeTest.php index 7caeb724278..287dd4037e5 100644 --- a/core/modules/node/tests/src/Kernel/Migrate/d7/MigrateNodeTest.php +++ b/core/modules/node/tests/src/Kernel/Migrate/d7/MigrateNodeTest.php @@ -149,6 +149,9 @@ class MigrateNodeTest extends MigrateDrupal7TestBase { $node = Node::load(1); $this->assertTrue($node->field_boolean->value); $this->assertEquals('99-99-99-99', $node->field_phone->value); + $this->assertSame('2015-01-20T04:15:00', $node->field_date->value); + $this->assertSame('2015-01-20', $node->field_date_without_time->value); + $this->assertSame('2015-01-20', $node->field_datetime_without_time->value); $this->assertEquals('1', $node->field_float->value); $this->assertEquals('5', $node->field_integer->value); $this->assertEquals('Some more text', $node->field_text_list[0]->value);