From f276a323ca7f2303f4120ba5a68a31a20397b3c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Nowacki?= Date: Tue, 12 Mar 2019 10:45:56 +0100 Subject: [PATCH] Avibility to change mutateDate behaviour Adds possibility to set mutateDate to return \DateTime instead of \CodeIgniter\I18n\Time instances. To make it work simpy use this code in your Entity child constructor: ``` public function __construct(?array $data = null) { parent::__construct($data, ['dateMutateAs' => 'DateTime']); } ``` or ``` public function __construct(?array $data = null) { parent::__construct($data); $this->setMutateDateAs('DateTime'); // will return boolean - value changed === true. } ``` I think it is required to add some code to make timezone changes work for \CodeIgniter\I18n\Time instance. For make this work in predictable way I think we should make some changes in \CodeIgniter\I18n\Time (#1807) --- system/Entity.php | 152 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 130 insertions(+), 22 deletions(-) diff --git a/system/Entity.php b/system/Entity.php index f2b99a2ae846..7c0ae735231f 100644 --- a/system/Entity.php +++ b/system/Entity.php @@ -1,8 +1,5 @@ _original = $properties; + if(isset($opts['dateMutateAs']) && is_string($opts['dateMutateAs'])) + { + $this->setMutateDateAs($opts['dateMutateAs']); + } + $this->setMutateDateTimezone($opts['dateMutateTimezone'] ?? app_timezone()); + if (is_array($data)) { $this->fill($data); @@ -281,7 +298,7 @@ public function __get(string $key) // Do we need to mutate this into a date? if (in_array($key, $this->_options['dates'])) { - $result = $this->mutateDate($result); + $result = $this->mutateDate($result, $this->getMutateDateTimezone()); } // Or cast it as something? else if ($this->_cast && isset($this->_options['casts'][$key]) && ! empty($this->_options['casts'][$key])) @@ -315,7 +332,7 @@ public function __set(string $key, $value = null) // Check if the field should be mutated into a date if (in_array($key, $this->_options['dates'])) { - $value = $this->mutateDate($value); + $value = $this->mutateDate($value, new \DateTimeZone('UTC')); } $isNullable = false; @@ -344,6 +361,11 @@ public function __set(string $key, $value = null) { $value = json_encode($value); } + + if($castTo === 'datetime' && $value instanceof \DateTime) + { + $value = $this->mutateDate($value, new \DateTimeZone('UTC')); + } } // if a set* method exists for this key, @@ -376,7 +398,6 @@ public function __set(string $key, $value = null) * attribute will be reset to that default value. * * @param string $key - * * @throws \ReflectionException */ public function __unset(string $key) @@ -453,31 +474,118 @@ protected function mapProperty(string $key) * * @param $value * - * @return \CodeIgniter\I18n\Time + * @param \DateTimeZone|null $timezone + * @return Time|\DateTime */ - protected function mutateDate($value) + protected function mutateDate($value, ?\DateTimeZone $timezone = null) { - if ($value instanceof Time) + // Default behaviour - return value as \CodeIgniter\I18n\Time + if($this->_mutateDateAs !== 'DateTime') { - return $value; - } + if ($value instanceof Time) + { + ;//Do nothing. We are ready to go. + } + else if ($value instanceof \DateTime) + { + $value = Time::instance($value); + } + else if (is_numeric($value)) + { + $value = Time::createFromTimestamp($value); + } + else if (is_string($value)) + { + $value = Time::parse($value); + } - if ($value instanceof \DateTime) + if(!is_null($timezone)) + { + $value = $value->setTimezone($timezone); + } + } + // Return value as \DateTime + else { - return Time::instance($value); + if (is_numeric($value)) + { + $value = '@' . $value; + } + else if ($value instanceof \DateTime) + { + $value = $value->format('c ') . ' CET'; + } + if(is_string($value)) + { + $value = (new class extends \DateTime + { + + public function __toString() + { + return $this->format('Y-m-d H:i:s'); + } + + public function set($time = 'now', \DateTimeZone $timezone = null) + { + parent::__construct($time, $timezone); + return $this; + } + + })->set($value, new \DateTimeZone('UTC')); + + if(!is_null($timezone)) + { + $value->setTimezone($timezone); + } + } } - if (is_numeric($value)) + return $value; + } + + /** + * @return string + */ + protected function getMutateDateAs(): string + { + return $this->_mutateDateAs; + } + + /** + * @param string $mutateDateAs + * @return bool + */ + protected function setMutateDateAs(string $mutateDateAs): bool + { + if(in_array($mutateDateAs, ['DateTime', 'Time'])) { - return Time::createFromTimestamp($value); + $this->_mutateDateAs = $mutateDateAs; + return true; } + return false; + } + + /** + * @return \DateTimeZone|null + */ + public function getMutateDateTimezone() + { + return $this->_mutateDateTimezone ?? new \DateTimeZone(app_timezone()); + } - if (is_string($value)) + /** + * @param \DateTimeZone|string $dateTimeZone + */ + public function setMutateDateTimezone($dateTimeZone): void + { + if(is_string($dateTimeZone) || is_null($dateTimeZone)) { - return Time::parse($value); + $this->_mutateDateTimezone = new \DateTimeZone($dateTimeZone ?? app_timezone()); + } + elseif ($dateTimeZone instanceof \DateTimeZone) + { + $this->_mutateDateTimezone = $dateTimeZone; } - - return $value; } //-------------------------------------------------------------------- @@ -486,7 +594,7 @@ protected function mutateDate($value) * Provides the ability to cast an item as a specific data type. * Add ? at the beginning of $type (i.e. ?string) to get NULL instead of castig $value if $value === null * - * @param $value + * @param $value * @param string $type * * @return mixed @@ -541,7 +649,7 @@ protected function castAs($value, string $type) $value = $this->castAsJson($value, true); break; case 'datetime': - return new \DateTime($value); + $value = $this->mutateDate($value, $this->getMutateDateTimezone()); break; case 'timestamp': return strtotime($value);