Issue #2457405 by stefan.r, andypost: DateTimePlus violates substitution principle of DateTime. Make it support PHP 7
parent
fcbb3c0c81
commit
b4fdbfd6c4
|
@ -7,26 +7,26 @@
|
||||||
namespace Drupal\Component\Datetime;
|
namespace Drupal\Component\Datetime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extends DateTime().
|
* Wraps DateTime().
|
||||||
*
|
*
|
||||||
* This class extends the PHP DateTime class with more flexible initialization
|
* This class wraps the PHP DateTime class with more flexible initialization
|
||||||
* parameters, allowing a date to be created from an existing date object,
|
* parameters, allowing a date to be created from an existing date object,
|
||||||
* a timestamp, a string with an unknown format, a string with a known
|
* a timestamp, a string with an unknown format, a string with a known
|
||||||
* format, or an array of date parts. It also adds an errors array
|
* format, or an array of date parts. It also adds an errors array
|
||||||
* and a __toString() method to the date object.
|
* and a __toString() method to the date object.
|
||||||
*
|
*
|
||||||
* This class is less lenient than the parent DateTime class. It changes
|
* This class is less lenient than the DateTime class. It changes
|
||||||
* the default behavior for handling date values like '2011-00-00'.
|
* the default behavior for handling date values like '2011-00-00'.
|
||||||
* The parent class would convert that value to '2010-11-30' and report
|
* The DateTime class would convert that value to '2010-11-30' and report
|
||||||
* a warning but not an error. This extension treats that as an error.
|
* a warning but not an error. This extension treats that as an error.
|
||||||
*
|
*
|
||||||
* As with the base class, a date object may be created even if it has
|
* As with the DateTime class, a date object may be created even if it has
|
||||||
* errors. It has an errors array attached to it that explains what the
|
* errors. It has an errors array attached to it that explains what the
|
||||||
* errors are. This is less disruptive than allowing datetime exceptions
|
* errors are. This is less disruptive than allowing datetime exceptions
|
||||||
* to abort processing. The calling script can decide what to do about
|
* to abort processing. The calling script can decide what to do about
|
||||||
* errors using hasErrors() and getErrors().
|
* errors using hasErrors() and getErrors().
|
||||||
*/
|
*/
|
||||||
class DateTimePlus extends \DateTime {
|
class DateTimePlus {
|
||||||
|
|
||||||
const FORMAT = 'Y-m-d H:i:s';
|
const FORMAT = 'Y-m-d H:i:s';
|
||||||
|
|
||||||
|
@ -91,6 +91,13 @@ class DateTimePlus extends \DateTime {
|
||||||
*/
|
*/
|
||||||
protected $errors = array();
|
protected $errors = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The DateTime object.
|
||||||
|
*
|
||||||
|
* @var \DateTime
|
||||||
|
*/
|
||||||
|
protected $dateTimeObject = NULL;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a date object from an input date object.
|
* Creates a date object from an input date object.
|
||||||
*
|
*
|
||||||
|
@ -126,7 +133,7 @@ class DateTimePlus extends \DateTime {
|
||||||
$date_parts = static::prepareArray($date_parts, TRUE);
|
$date_parts = static::prepareArray($date_parts, TRUE);
|
||||||
if (static::checkArray($date_parts)) {
|
if (static::checkArray($date_parts)) {
|
||||||
// Even with validation, we can end up with a value that the
|
// Even with validation, we can end up with a value that the
|
||||||
// parent class won't handle, like a year outside the range
|
// DateTime class won't handle, like a year outside the range
|
||||||
// of -9999 to 9999, which will pass checkdate() but
|
// of -9999 to 9999, which will pass checkdate() but
|
||||||
// fail to construct a date object.
|
// fail to construct a date object.
|
||||||
$iso_date = static::arrayToISO($date_parts);
|
$iso_date = static::arrayToISO($date_parts);
|
||||||
|
@ -251,7 +258,7 @@ class DateTimePlus extends \DateTime {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (empty($this->errors)) {
|
if (empty($this->errors)) {
|
||||||
parent::__construct($prepared_time, $prepared_timezone);
|
$this->dateTimeObject = new \DateTime($prepared_time, $prepared_timezone);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (\Exception $e) {
|
catch (\Exception $e) {
|
||||||
|
@ -266,7 +273,7 @@ class DateTimePlus extends \DateTime {
|
||||||
/**
|
/**
|
||||||
* Implements __toString() for dates.
|
* Implements __toString() for dates.
|
||||||
*
|
*
|
||||||
* The base DateTime class does not implement this.
|
* The DateTime class does not implement this.
|
||||||
*
|
*
|
||||||
* @see https://bugs.php.net/bug.php?id=62911
|
* @see https://bugs.php.net/bug.php?id=62911
|
||||||
* @see http://www.serverphorums.com/read.php?7,555645
|
* @see http://www.serverphorums.com/read.php?7,555645
|
||||||
|
@ -276,6 +283,43 @@ class DateTimePlus extends \DateTime {
|
||||||
return $this->format($format) . ' ' . $this->getTimeZone()->getName();
|
return $this->format($format) . ' ' . $this->getTimeZone()->getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements the magic __call method.
|
||||||
|
*
|
||||||
|
* Passes through all unknown calls onto the DateTime object.
|
||||||
|
*/
|
||||||
|
public function __call($method, $args) {
|
||||||
|
// @todo consider using assert() as per https://www.drupal.org/node/2451793.
|
||||||
|
if (!isset($this->dateTimeObject)) {
|
||||||
|
throw new \Exception('DateTime object not set.');
|
||||||
|
}
|
||||||
|
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(array($this->dateTimeObject, $method), $args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements the magic __callStatic method.
|
||||||
|
*
|
||||||
|
* Passes through all unknown static calls onto the DateTime object.
|
||||||
|
*/
|
||||||
|
public static function __callStatic($method, $args) {
|
||||||
|
if (!method_exists('\DateTime', $method)) {
|
||||||
|
throw new \BadMethodCallException(sprintf('Call to undefined method %s::%s()', get_called_class(), $method));
|
||||||
|
}
|
||||||
|
return call_user_func_array(array('\DateTime', $method), $args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements the magic __clone method.
|
||||||
|
*
|
||||||
|
* Deep-clones the DateTime object we're wrapping.
|
||||||
|
*/
|
||||||
|
public function __clone() {
|
||||||
|
$this->dateTimeObject = clone($this->dateTimeObject);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prepares the input time value.
|
* Prepares the input time value.
|
||||||
*
|
*
|
||||||
|
@ -349,7 +393,7 @@ class DateTimePlus extends \DateTime {
|
||||||
* @see http://us3.php.net/manual/en/time.getlasterrors.php
|
* @see http://us3.php.net/manual/en/time.getlasterrors.php
|
||||||
*/
|
*/
|
||||||
public function checkErrors() {
|
public function checkErrors() {
|
||||||
$errors = $this->getLastErrors();
|
$errors = \DateTime::getLastErrors();
|
||||||
if (!empty($errors['errors'])) {
|
if (!empty($errors['errors'])) {
|
||||||
$this->errors += $errors['errors'];
|
$this->errors += $errors['errors'];
|
||||||
}
|
}
|
||||||
|
@ -541,7 +585,7 @@ class DateTimePlus extends \DateTime {
|
||||||
|
|
||||||
// Format the date and catch errors.
|
// Format the date and catch errors.
|
||||||
try {
|
try {
|
||||||
$value = parent::format($format);
|
$value = $this->dateTimeObject->format($format);
|
||||||
}
|
}
|
||||||
catch (\Exception $e) {
|
catch (\Exception $e) {
|
||||||
$this->errors[] = $e->getMessage();
|
$this->errors[] = $e->getMessage();
|
||||||
|
|
|
@ -35,7 +35,8 @@ abstract class DateElementBase extends FormElement {
|
||||||
* described by this pattern.
|
* described by this pattern.
|
||||||
*/
|
*/
|
||||||
protected static function datetimeRangeYears($string, $date = NULL) {
|
protected static function datetimeRangeYears($string, $date = NULL) {
|
||||||
$this_year = date_format(new DrupalDateTime(), 'Y');
|
$datetime = new DrupalDateTime();
|
||||||
|
$this_year = $datetime->format('Y');
|
||||||
list($min_year, $max_year) = explode(':', $string);
|
list($min_year, $max_year) = explode(':', $string);
|
||||||
|
|
||||||
// Valid patterns would be -5:+5, 0:+1, 2008:2010.
|
// Valid patterns would be -5:+5, 0:+1, 2008:2010.
|
||||||
|
|
|
@ -238,7 +238,7 @@ class DateTimePlusTest extends UnitTestCase {
|
||||||
*/
|
*/
|
||||||
public function testDateTimezoneWithDateTimeObject() {
|
public function testDateTimezoneWithDateTimeObject() {
|
||||||
// Create a date object with another date object.
|
// Create a date object with another date object.
|
||||||
$input = new DateTimePlus('now', 'Pacific/Midway');
|
$input = new \DateTime('now', new \DateTimeZone('Pacific/Midway'));
|
||||||
$timezone = NULL;
|
$timezone = NULL;
|
||||||
$expected_timezone = 'Pacific/Midway';
|
$expected_timezone = 'Pacific/Midway';
|
||||||
$message = 'DateTimePlus uses the specified timezone if provided.';
|
$message = 'DateTimePlus uses the specified timezone if provided.';
|
||||||
|
|
Loading…
Reference in New Issue