From f11b482b3de2def420ed3f65f162ab461d5357a8 Mon Sep 17 00:00:00 2001 From: Peter Gribanov Date: Wed, 17 Jun 2020 11:44:45 +0300 Subject: [PATCH] show and edit date in the same timezone add convert timezone test optimize convert timezone not use assign operation inside the if condition test change datetime on change timezone create named datasets --- src/Action/SetObjectFieldValueAction.php | 10 ++++- .../views/CRUD/base_list_field.html.twig | 2 +- tests/Action/Bafoo.php | 2 +- .../Action/SetObjectFieldValueActionTest.php | 43 ++++++++++++++++++- 4 files changed, 52 insertions(+), 5 deletions(-) diff --git a/src/Action/SetObjectFieldValueAction.php b/src/Action/SetObjectFieldValueAction.php index dcc805a26f..e1b5ec4d45 100644 --- a/src/Action/SetObjectFieldValueAction.php +++ b/src/Action/SetObjectFieldValueAction.php @@ -121,7 +121,15 @@ public function __invoke(Request $request): JsonResponse // Handle date and datetime types have setter expecting a DateTime object if ('' !== $value && \in_array($fieldDescription->getType(), ['date', 'datetime'], true)) { - $value = new \DateTime($value); + $inputTimezone = new \DateTimeZone(date_default_timezone_get()); + $outputTimezone = $fieldDescription->getOption('timezone'); + + if ($outputTimezone && !$outputTimezone instanceof \DateTimeZone) { + $outputTimezone = new \DateTimeZone($outputTimezone); + } + + $value = new \DateTime($value, $outputTimezone ?: $inputTimezone); + $value->setTimezone($inputTimezone); } // Handle boolean type transforming the value into a boolean diff --git a/src/Resources/views/CRUD/base_list_field.html.twig b/src/Resources/views/CRUD/base_list_field.html.twig index 5f9eef3c9c..812b64bc41 100644 --- a/src/Resources/views/CRUD/base_list_field.html.twig +++ b/src/Resources/views/CRUD/base_list_field.html.twig @@ -55,7 +55,7 @@ file that was distributed with this source code. ) %} {% if field_description.type == constant('Sonata\\AdminBundle\\Templating\\TemplateRegistry::TYPE_DATE') and value is not empty %} - {% set data_value = value.format('Y-m-d') %} + {% set data_value = value|date('Y-m-d', options.timezone|default(null)) %} {% elseif field_description.type == constant('Sonata\\AdminBundle\\Templating\\TemplateRegistry::TYPE_BOOLEAN') and value is empty %} {% set data_value = 0 %} {% elseif value is iterable %} diff --git a/tests/Action/Bafoo.php b/tests/Action/Bafoo.php index f5df9a767d..91c6f36a73 100644 --- a/tests/Action/Bafoo.php +++ b/tests/Action/Bafoo.php @@ -31,7 +31,7 @@ public function setDateProp(\DateTime $dateProp): self return $this; } - public function getDatetimeProp(): \DateTime + public function getDatetimeProp(): ?\DateTime { return $this->datetimeProp; } diff --git a/tests/Action/SetObjectFieldValueActionTest.php b/tests/Action/SetObjectFieldValueActionTest.php index 75fe058dec..8ac2386799 100644 --- a/tests/Action/SetObjectFieldValueActionTest.php +++ b/tests/Action/SetObjectFieldValueActionTest.php @@ -126,7 +126,25 @@ public function testSetObjectFieldValueAction(): void $this->assertSame(Response::HTTP_OK, $response->getStatusCode()); } - public function testSetObjectFieldValueActionWithDate(): void + public function getTimeZones(): iterable + { + $default = new \DateTimeZone(date_default_timezone_get()); + $custom = new \DateTimeZone('Europe/Rome'); + + return [ + 'empty timezone' => [null, $default], + 'disabled timezone' => [false, $default], + 'default timezone by name' => [$default->getName(), $default], + 'default timezone by object' => [$default, $default], + 'custom timezone by name' => [$custom->getName(), $custom], + 'custom timezone by object' => [$custom, $custom], + ]; + } + + /** + * @dataProvider getTimeZones + */ + public function testSetObjectFieldValueActionWithDate($timezone, \DateTimeZone $expectedTimezone): void { $object = new Bafoo(); $request = new Request([ @@ -161,6 +179,7 @@ public function testSetObjectFieldValueActionWithDate(): void $container->reveal() )); $fieldDescription->getOption('editable')->willReturn(true); + $fieldDescription->getOption('timezone')->willReturn($timezone); $fieldDescription->getAdmin()->willReturn($this->admin->reveal()); $fieldDescription->getType()->willReturn('date'); $fieldDescription->getTemplate()->willReturn('field_template'); @@ -171,9 +190,20 @@ public function testSetObjectFieldValueActionWithDate(): void $response = ($this->action)($request); $this->assertSame(Response::HTTP_OK, $response->getStatusCode()); + + $defaultTimezone = new \DateTimeZone(date_default_timezone_get()); + $expectedDate = new \DateTime($request->query->get('value'), $expectedTimezone); + $expectedDate->setTimezone($defaultTimezone); + + $this->assertInstanceOf(\DateTime::class, $object->getDateProp()); + $this->assertSame($expectedDate->format('Y-m-d'), $object->getDateProp()->format('Y-m-d')); + $this->assertSame($defaultTimezone->getName(), $object->getDateProp()->getTimezone()->getName()); } - public function testSetObjectFieldValueActionWithDateTime(): void + /** + * @dataProvider getTimeZones + */ + public function testSetObjectFieldValueActionWithDateTime($timezone, \DateTimeZone $expectedTimezone): void { $object = new Bafoo(); $request = new Request([ @@ -208,6 +238,7 @@ public function testSetObjectFieldValueActionWithDateTime(): void $container->reveal() )); $fieldDescription->getOption('editable')->willReturn(true); + $fieldDescription->getOption('timezone')->willReturn($timezone); $fieldDescription->getAdmin()->willReturn($this->admin->reveal()); $fieldDescription->getType()->willReturn('datetime'); $fieldDescription->getTemplate()->willReturn('field_template'); @@ -218,6 +249,14 @@ public function testSetObjectFieldValueActionWithDateTime(): void $response = ($this->action)($request); $this->assertSame(Response::HTTP_OK, $response->getStatusCode()); + + $defaultTimezone = new \DateTimeZone(date_default_timezone_get()); + $expectedDate = new \DateTime($request->query->get('value'), $expectedTimezone); + $expectedDate->setTimezone($defaultTimezone); + + $this->assertInstanceOf(\DateTime::class, $object->getDatetimeProp()); + $this->assertSame($expectedDate->format('Y-m-d H:i:s'), $object->getDatetimeProp()->format('Y-m-d H:i:s')); + $this->assertSame($defaultTimezone->getName(), $object->getDatetimeProp()->getTimezone()->getName()); } public function testSetObjectFieldValueActionOnARelationField(): void