diff --git a/core/lib/Drupal/Component/Datetime/DateTimePlus.php b/core/lib/Drupal/Component/Datetime/DateTimePlus.php index 3495314..ee9a26e 100644 --- a/core/lib/Drupal/Component/Datetime/DateTimePlus.php +++ b/core/lib/Drupal/Component/Datetime/DateTimePlus.php @@ -314,7 +314,16 @@ public function __call($method, $args) { if (!method_exists($this->dateTimeObject, $method)) { throw new \BadMethodCallException(sprintf('Call to undefined method %s::%s()', get_class($this), $method)); } - return call_user_func_array([$this->dateTimeObject, $method], $args); + + $val = call_user_func_array([$this->dateTimeObject, $method], $args); + + if (is_object($val) && get_class($val) === 'DateTime') { + $this->dateTimeObject = $val; + return $this; + } + else { + return $val; + } } /** diff --git a/core/tests/Drupal/Tests/Component/Datetime/DateTimePlusTest.php b/core/tests/Drupal/Tests/Component/Datetime/DateTimePlusTest.php index 2becc97..1a350e0 100644 --- a/core/tests/Drupal/Tests/Component/Datetime/DateTimePlusTest.php +++ b/core/tests/Drupal/Tests/Component/Datetime/DateTimePlusTest.php @@ -804,4 +804,45 @@ public function testValidateFormat() { $date = DateTimePlus::createFromFormat('Y-m-d H:i:s', '11-03-31 17:44:00', 'UTC', ['validate_format' => TRUE]); } + /** + * Tests that object methods are chainable. + * + * @covers ::__call + */ + public function testChainable() { + $date = new DateTimePlus('now', 'Australia/Sydney'); + + $date->setTimestamp(12345678); + $rendered = $date->render(); + $this->assertEquals('1970-05-24 07:21:18 Australia/Sydney', $rendered); + + $date->setTimestamp(23456789); + $rendered = $date->setTimezone(new \DateTimeZone('America/New_York'))->render(); + $this->assertEquals('1970-09-29 07:46:29 America/New_York', $rendered); + } + + /** + * Tests that non-chainable methods work. + * + * @covers ::__call + */ + public function testChainableNonChainable() { + $datetime1 = new DateTimePlus('2009-10-11 12:00:00'); + $datetime2 = new DateTimePlus('2009-10-13 12:00:00'); + $interval = $datetime1->diff($datetime2); + $this->assertInstanceOf(\DateInterval::class, $interval); + $this->assertEquals('+2 days', $interval->format('%R%a days')); + } + + /** + * Tests that chained calls to non-existent functions throw an exception. + * + * @covers ::__call + */ + public function testChainableNonCallable() { + $this->setExpectedException(\BadMethodCallException::class, 'Call to undefined method Drupal\Component\Datetime\DateTimePlus::nonexistent()'); + $date = new DateTimePlus('now', 'Australia/Sydney'); + $date->setTimezone(new \DateTimeZone('America/New_York'))->nonexistent(); + } + } diff --git a/core/tests/Drupal/Tests/Core/Datetime/DrupalDateTimeTest.php b/core/tests/Drupal/Tests/Core/Datetime/DrupalDateTimeTest.php index eff9f77..096d99d 100644 --- a/core/tests/Drupal/Tests/Core/Datetime/DrupalDateTimeTest.php +++ b/core/tests/Drupal/Tests/Core/Datetime/DrupalDateTimeTest.php @@ -156,4 +156,48 @@ public function providerTestInvalidDateDiff() { ]; } + /** + * Tests that object methods are chainable. + * + * @covers ::__call + */ + public function testChainable() { + $tz = new \DateTimeZone(date_default_timezone_get()); + $date = new DrupalDateTime('now', $tz, ['langcode' => 'en']); + + $date->setTimestamp(12345678); + $rendered = $date->render(); + $this->assertEquals('1970-05-24 07:21:18 Australia/Sydney', $rendered); + + $date->setTimestamp(23456789); + $rendered = $date->setTimezone(new \DateTimeZone('America/New_York'))->render(); + $this->assertEquals('1970-09-29 07:46:29 America/New_York', $rendered); + } + + /** + * Tests that non-chainable methods work. + * + * @covers ::__call + */ + public function testChainableNonChainable() { + $tz = new \DateTimeZone(date_default_timezone_get()); + $datetime1 = new DrupalDateTime('2009-10-11 12:00:00', $tz, ['langcode' => 'en']); + $datetime2 = new DrupalDateTime('2009-10-13 12:00:00', $tz, ['langcode' => 'en']); + $interval = $datetime1->diff($datetime2); + $this->assertInstanceOf(\DateInterval::class, $interval); + $this->assertEquals('+2 days', $interval->format('%R%a days')); + } + + /** + * Tests that chained calls to non-existent functions throw an exception. + * + * @covers ::__call + */ + public function testChainableNonCallable() { + $this->setExpectedException(\BadMethodCallException::class, 'Call to undefined method Drupal\Core\Datetime\DrupalDateTime::nonexistent()'); + $tz = new \DateTimeZone(date_default_timezone_get()); + $date = new DrupalDateTime('now', $tz, ['langcode' => 'en']); + $date->setTimezone(new \DateTimeZone('America/New_York'))->nonexistent(); + } + }