我在MySQL数据库中将许多列定义为“时间”。也就是说,他们有时间,但没有日期。当CakePHP 3 ORM读取它们时,它们将被转换为Cake \ I18n \ Time对象(通过Cake \ Database \ Type \ TimeType类),但是结果中始终带有日期和时间,并且日期设置为当前日期。例如,如果值为“ 20:00:00”,debug($record['start_time'])将生成:
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忽略了这 只是 一个时间这一事实,更重要的是,有没有办法使它停止?
setToStringFormat
6/21/15 8:00 PM
$this->Time->format
日期/时间值都被强制转换为相同的基本结构,即DateTime或DateTimeImmutable对象,因此,仅日期值会自然地加上时间值(00:00:00),而仅时间值会附带日期(当前日期) 。
DateTime
DateTimeImmutable
00:00:00
CakePHP将根据SQL数据类型使用特定的子类,即
\Cake\I18n\Time
\Cake\I18n\FrozenTime
TIME
TIMESTAMP
DATETIME
\Cake\I18n\Date
\Cake\I18n\FrozenDate
DATE
在早期的CakePHP 3版本中,只有\Cake\I18n\Time。
如果有一个单独的仅用于时间类型的类,这将是很好的,它会设置适当的仅时间的默认输出格式,但是在添加类似的东西之前,您必须自己照顾输出格式。
如何显示此视图取决于您。您可以轻松使用类实例的i18nFormat()方法Time
i18nFormat()
Time
$record['start_time']->i18nFormat( [\IntlDateFormatter::NONE, \IntlDateFormatter::SHORT] )
或Time助手,仅显示时间部分
$this->Time->i18nFormat( $record['start_time'], [\IntlDateFormatter::NONE, \IntlDateFormatter::SHORT] )
猜想,如果bake根据列的类型生成类似的代码,那不会有什么坏处,您可能会 建议将其作为增强功能 。如前所述,对于仅时间列使用其他类(或选项)可能也值得考虑。
如果您希望在使用对象的字符串表示形式的任何地方都需要这种行为,而不必手动调用格式化程序,则可以使用带有重写属性的扩展\Cake\I18n\Time或\Cake\I18n\FrozenTime类$_toStringFormat,以便对日期进行相应的格式化。
$_toStringFormat
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'); // ...
现在,这几乎应该是自解释的,time正在映射到的列TimeType将App\I18n\FrozenTimeOnly代替默认值使用Cake\I18n\Time。
time
TimeType
App\I18n\FrozenTimeOnly
Cake\I18n\Time
DateTimeType::$dateTimeClass
为了解决这个问题,将需要一个自定义的数据库类型,这也非常简单。
src /数据库/类型/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()该实例,在此实例化给定类的实例。
_setClassName()
use App\Database\Type\TimeOnlyType; Type::map('time', TimeOnlyType::class);
因此,这将覆盖默认time类型映射以使用自定义\App\Database\Type\TimeOnlyType类,而自定义类将\App\I18n\TimeOnly在将数据库值转换为PHP对象时使用该类,当将其转换为字符串时,将使用仅时间格式。
\App\Database\Type\TimeOnlyType
\App\I18n\TimeOnly