Skip to content

Commit

Permalink
Avibility to change mutateDate behaviour
Browse files Browse the repository at this point in the history
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 (codeigniter4#1807)
  • Loading branch information
nowackipawel authored Mar 12, 2019
1 parent ba4f258 commit f276a32
Showing 1 changed file with 130 additions and 22 deletions.
152 changes: 130 additions & 22 deletions system/Entity.php
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
<?php namespace CodeIgniter;

use CodeIgniter\I18n\Time;
use CodeIgniter\Exceptions\CastException;

/**
* CodeIgniter
*
Expand Down Expand Up @@ -85,12 +82,26 @@ class Entity
**/
private $_cast = true;

/**
* Contains information about type returned by mutateDate for:
* - datetime casted properties and
* - $_options['dates'] defined properties
* Allowed values are:
* 'Time' for: \CodeIgniter\I18n\Time
* 'DateTime' for: \DateTime
*
* @var string
*/
private $_mutateDateAs = 'Time';
private $_mutateDateTimezone = null;

/**
* Allows filling in Entity parameters during construction.
*
* @param array|null $data
* @param array|null $opts
*/
public function __construct(array $data = null)
public function __construct(array $data = null, array $opts = null)
{
// Collect any original values of things
// so we can compare later to see what's changed
Expand All @@ -106,6 +117,12 @@ public function __construct(array $data = null)

$this->_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);
Expand Down Expand Up @@ -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]))
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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;
}

//--------------------------------------------------------------------
Expand All @@ -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
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit f276a32

Please sign in to comment.