CakePHP 3 temporary column add date
I have several columns defined in my MySQL database as "time". That is, they have a time, but not a date. When they are read by the CakePHP 3 ORM, they are converted to Cake \ I18n \ Time objects (via the Cake \ Database \ Type \ TimeType class), but the result always has both a date and a time in it, and the date is set to the current date. For example, if the value is "20:00:00", it debug($record['start_time'])
will generate:
object(Cake\I18n\Time) {
'time' => '2015-06-21T20:00:00+0000',
'timezone' => 'UTC',
'fixedNowTime' => false
}
And when I repeat it in the template (without using it setToStringFormat
) I get something like 6/21/15 8:00 PM
. Of course I can use $this->Time->format
to put it back in time format, but it seems very strange to me that I would need to do this. Why is Cake ignoring the fact that it's just time and, more importantly, is there a way to stop it?
source to share
Date / time values ββare all passed into one underlying structure, i.e. object DateTime
or DateTimeImmutable
, and therefore natural values ββwith date will have the added value of time ( 00:00:00
) and time - only values ββhave a date (today's date).
CakePHP will use specific subclasses depending on the SQL datatype, i.e.
-
\Cake\I18n\Time
or\Cake\I18n\FrozenTime
forTIME
,TIMESTAMP
andDateTime
-
\Cake\I18n\Date
or\Cake\I18n\FrozenDate
forDATE
Previous versions of CakePHP 3 had only \Cake\I18n\Time
.
It would be nice if there was a separate class for time-only types that would have the correct default-only output format, but until something like this is added, you'll have to take care of the output format.
Format in your views
It is up to you how to display this in your views. You can use i18nFormat()
class instance method easilyTIME
$record['start_time']->i18nFormat(
[\IntlDateFormatter::NONE, \IntlDateFormatter::SHORT]
)
or TIME
, to show only the temporary part
$this->Time->i18nFormat(
$record['start_time'],
[\IntlDateFormatter::NONE, \IntlDateFormatter::SHORT]
)
Guess it doesn't hurt, if baking generates similar code according to the column type, you might want to suggest that as an improvement . As mentioned, using additional classes (or perhaps options) for time-only columns might be worth considering.
Use your own time class
If you wanted this behavior wherever the string representation of an object is used without having to manually invoke formatting, you can use an extended class \Cake\I18n\Time
or \Cake\I18n\FrozenTime
overridden $_toStringFormat
so that it formats the date accordingly.
SRC / i18n / FrozenTimeOnly.php
namespace App\I18n;
use Cake\I18n\FrozenTime;
class FrozenTimeOnly extends FrozenTime
{
protected static $_toStringFormat = [
\IntlDateFormatter::NONE,
\IntlDateFormatter::SHORT
];
}
Src / config / bootstrap.php
use Cake\Database\Type\TimeType;
use App\I18n\FrozenTimeOnly;
TimeType::$dateTimeClass = FrozenTimeOnly::class;
// remove the default `useImmutable()` call, you may however
// want to keep further calls for formatting and stuff
Type::build('time');
// ...
This should be pretty much a self exploratory column TIME
that maps to TimeType
will now use App\I18n\FrozenTimeOnly
instead of the default one Cake\I18n\Time
.
DateTimeType::$dateTimeClass
obsolete
To handle this, you need a custom database type, which is pretty simple as well.
CSI / Database / Type / TimeOnlyType.php
namespace App\Database\Type;
use App\I18n\FrozenTimeOnly;
use Cake\Database\Type\TimeType;
class TimeOnlyType extends TimeType
{
public function __construct($name)
{
parent::__construct($name);
$this->_setClassName(FrozenTimeOnly::class, \DateTimeImmutable::class);
}
}
It should be noted that currently this will set the data / time class twice, as the parent constructor will also call _setClassName()
where the given class will be instantiated.
Src / config / bootstrap.php
use App\Database\Type\TimeOnlyType;
Type::map('time', TimeOnlyType::class);
So what this will do is override the default type mapping TIME
to use a custom class \App\Database\Type\TimeOnlyType
, which in turn will use the class \App\I18n\TimeOnly
when converting database values ββto PHP objects, which, when converted to string, will use the time format.
see also
source to share
fact: cakePHP takes your time value as a Time Object, which extends carbon and dateTime, so you get a full date instance of dateTime :(
however, you can easily do automatic typing with your object. U only need to use Accessors and Mutators here: http://book.cakephp.org/3.0/en/orm/entities.html#accessors-mutators
source to share