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?

+3


source to share


2 answers


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

    for TIME

    , 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

+8


source


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

0


source







All Articles