【问题标题】:CakePHP 3 time column gets date addedCakePHP 3时间列获取添加日期
【发布时间】:2015-09-06 18:38:27
【问题描述】:

我的 MySQL 数据库中有许多列定义为“时间”。也就是说,他们有时间,但没有日期。当它们被 CakePHP 3 ORM 读取时,它们被转换为 Cake\I18n\Time 对象(通过 Cake\Database\Type\TimeType 类),但结果中总是包含日期和时间,日期设置为当前日期。例如,如果值为“20:00:00”,debug($record['start_time']) 将生成:

object(Cake\I18n\Time) {
    'time' => '2015-06-21T20:00:00+0000',
    'timezone' => 'UTC',
    'fixedNowTime' => false
}

当我在模板中回显它时(没有使用setToStringFormat),我得到类似6/21/15 8:00 PM 的东西。当然,我可以使用$this->Time->format 将其恢复为仅限时间的格式,但我需要这样做似乎很奇怪。为什么 Cake 忽略了这只是次的事实,更重要的是,有没有办法让它停止?

【问题讨论】:

    标签: mysql date time orm cakephp-3.0


    【解决方案1】:

    日期/时间值都被转换为相同的基本结构,即DateTimeDateTimeImmutable 对象,因此自然地仅日期值将添加时间值 (00:00:00),而时间-only 值带有日期(当前日期)。

    CakePHP 将根据 SQL 数据类型使用特定的子类,即

    • \Cake\I18n\Time\Cake\I18n\FrozenTime 用于 TIMETIMESTAMPDATETIME
    • \Cake\I18n\Date\Cake\I18n\FrozenDateDATE

    在早期的 CakePHP 3 版本中,只有 \Cake\I18n\Time

    如果有一个单独的类用于仅时间类型会很好,它会设置适当的仅时间默认输出格式,但在添加类似的东西之前,您必须注意自己输出格式。

    在您的视图中格式化

    如何在视图中显示它取决于您。您可以轻松使用Time 类实例的i18nFormat() 方法

    $record['start_time']->i18nFormat(
        [\IntlDateFormatter::NONE, \IntlDateFormatter::SHORT]
    )
    

    Time 助手,仅显示时间部分

    $this->Time->i18nFormat(
        $record['start_time'],
        [\IntlDateFormatter::NONE, \IntlDateFormatter::SHORT]
    )
    

    如果 bake 会根据列的类型生成类似的代码,你可能想suggest that as an enhancement。如前所述,为仅时间列使用其他类(或选项)可能也值得考虑。

    使用自定义时间类

    如果您希望在使用对象的字符串表示的任何地方都有这种行为,而不必手动调用格式化程序,那么您可以使用扩展的 \Cake\I18n\Time\Cake\I18n\FrozenTime 类,并覆盖 @ 987654343@ 属性,以便它相应地格式化日期。

    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'); 
    // ...
    

    这应该是不言自明的,被映射到 TimeTypetime 列现在将使用 App\I18n\FrozenTimeOnly 而不是默认的 Cake\I18n\Time

    DateTimeType::$dateTimeClass 已弃用

    为了解决这个问题,需要一个自定义的数据库类型,这也很简单。

    src/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);
        }
    }
    

    应该注意的是,目前这将实例化一个数据/时间类两次,因为父构造函数也会调用_setClassName(),这是实例化给定类的实例的地方。

    src/config/bootstrap.php

    use App\Database\Type\TimeOnlyType;
    Type::map('time', TimeOnlyType::class);
    

    因此,这将覆盖默认的 time 类型映射以使用自定义的 \App\Database\Type\TimeOnlyType 类,当将数据库值转换为 PHP 对象时,该类又将使用 \App\I18n\TimeOnly 类,当转换为字符串,将使用仅时间格式。

    另见

    【讨论】:

    • 复制并粘贴它,它第一次完美运行! (好吧,一旦我正确命名了我的文件......)
    【解决方案2】:

    事实是 cakePHP 将你的时间值作为时间对象执行,它扩展了碳和日期时间,所以你得到一个完整的 dateTime 实例,包括日期:(

    但是,您可以轻松地对您的实体执行自动设置。你只需要使用 Accessors & Mutators 在这里描述:http://book.cakephp.org/3.0/en/orm/entities.html#accessors-mutators

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-12-03
      • 1970-01-01
      • 2014-12-21
      • 2016-01-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多