It would be useful to work with dates column like that:
class Order extends ActiveRecord
{
use MutateDatesAttributes;
protected $dates = [
'is_send_scheduled', 'created_at', 'updated_at'
];
}
$order->is_send_scheduled = (new \DateTime)->add(new DateInterval('PT4H'))
I implemented in trait that logic on my own like that:
trait MutateDatesAttributes
{
/**
* The attributes that should be mutated to dates.
*
* @var array
*/
protected $dates = [];
/**
* The storage format of the model's date columns.
*
* @var string
*/
protected $dateFormat;
/**
* @param $name
* @return DateTime
* @throws \Exception
*/
public function __get($name)
{
$value = parent::__get($name);
// If the attribute is listed as a date, we will convert it to a DateTime
// instance on retrieval, which makes it quite convenient to work with
// date fields without having to create a mutator for each property.
if ($this->isDateAttribute($name) &&
! is_null($value)) {
return $this->asDateTime($value);
}
return $value;
}
/**
* @param $name
* @return string
* @throws \Exception
*/
public function getAttribute($name)
{
$value = parent::getAttribute($name);
// If the attribute is listed as a date, we will convert it to a DateTime
// instance on retrieval, which makes it quite convenient to work with
// date fields without having to create a mutator for each property.
if ($this->isDateAttribute($name) &&
! is_null($value)) {
return $this->asDateTime($value);
}
return $value;
}
/**
* Return a timestamp as DateTime object.
*
* @param mixed $value
* @return DateTime
* @throws \Exception
*/
protected function asDateTime($value)
{
// If this value is already a DateTime instance, we shall just return it as is.
// This prevents us having to re-instantiate a DateTime instance when we know
// it already is one, which wouldn't be fulfilled by the DateTime check.
if ($value instanceof DateTime) {
return $value;
}
// If this value is an integer, we will assume it is a UNIX timestamp's value
// and format a \DateTime object from this timestamp. This allows flexibility
// when defining your date fields as they might be UNIX timestamps here.
if (is_numeric($value)) {
return (new DateTime)->setTimestamp($value);
}
// If the value is in simply year, month, day format, we will instantiate the
// DateTime instances from that format. Again, this provides for simple date
// fields on the database, while still supporting DateTime conversion.
if ($this->isStandardDateFormat($value)) {
return DateTime::createFromFormat('Y-m-d', $value)->setTime(0, 0);
}
// Finally, we will just assume this date is in the format used by default on
// the database connection and use that format to create the DateTime object
// that is returned back out to the developers after we convert it here.
return DateTime::createFromFormat(
str_replace('.v', '.u', $this->getDateFormat()), $value
);
}
/**
* Determine if the given value is a standard date format.
*
* @param string $value
* @return bool
*/
protected function isStandardDateFormat($value)
{
return preg_match('/^(\d{4})-(\d{1,2})-(\d{1,2})$/', $value);
}
/**
* Get the format for database stored dates.
*
* @return string
*/
public function getDateFormat()
{
/** @var Connection $db */
$db = static::getDb();
switch ($db->getDriverName()) {
case 'mysql':
default:
return $this->dateFormat ?: 'Y-m-d H:i:s';
}
}
/**
* Determine if the given attribute is a date.
*
* @param string $name
* @return bool
*/
protected function isDateAttribute($name)
{
return in_array($name, $this->dates);
}
/**
* @param $name
* @param $value
* @throws \Exception
*/
public function __set($name, $value)
{
if ($this->isDateAttribute($name)) {
$value = $this->fromDateTime($value);
}
return parent::__set($name, $value);
}
/**
* @param $name
* @param $value
* @throws \Exception
*/
public function setAttribute($name, $value)
{
if ($this->isDateAttribute($name)) {
$value = $this->fromDateTime($value);
}
return parent::setAttribute($name, $value);
}
/**
* Convert a DateTime to a storable string.
*
* @param mixed $value
* @return string|null
* @throws \Exception
*/
public function fromDateTime($value)
{
return empty($value) ? $value : $this->asDateTime($value)->format(
$this->getDateFormat()
);
}
}
Feature request to add the ability to convert dates columns to instances of DateTime inspired by [laravel].(https://laravel.com/docs/7.x/eloquent-mutators#date-mutators).
It would be useful to work with dates column like that:
I implemented in trait that logic on my own like that:
If that feature is ok i would have create pr.