在列表Cakephp3中将Date设置为keyField


Set Date as keyField in list Cakephp 3

我使用列表从模型中获取数据,它在中运行良好

这个例子来自Cakephp文档

$query = $articles->find('list', [
    'keyField' => 'slug',
    'valueField' => 'title'
]);
$data = $query->toArray();

我有一张名为假日的桌子

id[int]| date[date]| name[varchar(200)]| created[datetime]

所以想要一个以日期为关键字、以假日为值的列表像这样的

[
    '2016-01-01'=>'New Year',
    '2016-01-26'=>'Republic Day',
]

所以我通过蛋糕烘焙创建了模型,并用这个代码实现了

$holidays = TableRegistry::get('Holidays');
$holidays = $holidays->find('list',[
    'keyField' => 'date',
    'valueField'=>'name',
])->toArray();

但它给了我错误

偏移类型非法InvalidArgumentException

当我将keyField从date改为name时,效果非常好。

这是的日志

2016-04-29 04:26:41错误:〔InvalidArgumentException〕偏移量非法type请求URL:/sfworxerp/api/atteances/getMonthAttendanceData堆栈跟踪:F: ''public_html''sfworxerp''vendor''cakehp''cakehp''src''Collection''Iterator''MapReduce.php(160):Cake''Collection''Iterator''MapReduce::emit()F: ''public_html''sfworxerp''vendor''cakehp''cakehp''src''CollectionTrait.php(386):Cake''Collection''Iterator''MapReduce->emit("新年",对象(Cake''I18n''FrozenDate))F: ''public_html''sfworxerp''vendor''cakehp''cakehp''src''Collection''Iterator''MapReduce.php(177):Cake''ORM''ResultSet->Cake''Collection{closure}(对象(App''Model''Entity''Holiday),0,对象(Cake''Collection''Iterator''MapReduce)F: ''public_html''sfworxerp''vendor''cakehp''cakehp''src''Collection''Iterator''MapReduce.php(132):Cake''Collection''Iterator''MapReduce->_execute()[内部函数]:Cake''Collection''Iterator''MapReduce->getIterator()F: ''public_html''sfworxerp''vendor''cakehp''cakehp''src''Collection.php(50):IteratorIterator->__construct(对象(Cake''Collection''Iterator''MapReduce))F: ''public_html''sfworxerp''vendor''cakehp''cakehp''src''CollectionTrait.php(405):Cake''Collection''Collection->__construct(对象(Cake''Cllection''Iterator''MapReduce))F: ''public_html''sfworxerp''vendor''cakehp''cakehp''src''ORM''Table.php(1062):Cake''ORM''ResultSet->组合("日期"、"名称"、NULL)F: ''public_html''sfworxerp''vendor''cakehp''cakehp''src''Datasource''QueryTrait.php(490):Cake''ORM''Table->Cake''ORM{closure}(对象(Cake''ORM''ResultSet))F: ''public_html''sfworxerp''vendor''cakehp''cakehp''src''ORM''Query.php(1141):Cake''ORM''Query->_applyDecorators(对象(Cake''ORM''ResultSet))F: ''public_html''sfworxerp''vendor''cakehp''cakehp''src''Datasource''QueryTrait.php(272):Cake''ORM''Query->_decorateResults(对象(Cake''ORM''ResultSet))F: ''public_html''sfworxerp''vendor''cakehp''cakehp''src''ORM''Query.php(871):Cake''ORM''Query->_all()F: ''public_html''sfworxerp''vendor''cakehp''cakehp''src''Datasource''QueryTrait.php(288):Cake''ORM''Query->all()F: ''public_html''sfworxerp''src''Controller''Api''AAttendancesController.php(133):Cake''ORM''Query->toArray()[内部函数]:App''Controller''Api''AAttendancesController->getMonthAttendanceData()F: ''public_html''sfworxerp''vendor''cakehp''cakehp''src''Controller''Controller.php(429):call_user_func_array(数组,数组)F: ''public_html''sfworxerp''vendor''cakehp''cakehp''src''Routing''Dispatcher.php(114):Cake''Controller''Controller->invokeAction()F: ''public_html''sfworxerp''vendor''cakehp''cakehp''src''Routing''Dispatcher.php(87):Cake''Routing''Dispatcher->_invoke(对象(App''Controller''Api''AAttendancesController))F: ''public_html''sfworxerp''webroot''index.php(37):Cake''Routing''Dispatcher->dispatch(Object(Cake''Network''Request),对象(Cake''Network''Response)){main}

任何帮助都将不胜感激

问题:

问题是,对于"日期"字段,CakePHP 3返回一个对象,而不是字符串:

'date' => object(Cake'I18n'FrozenDate) {
    'time' => '1997-01-03T00:00:00+00:00',
    'timezone' => 'UTC',
    'fixedNowTime' => false
},

尝试将其用作密钥是不起作用的,并且会抛出您所看到的错误。

如何处理:

根据CakePHP书中的这个区域,为了适应这一点,你可以:

使用闭包访问列表查找中的实体赋值器方法。

TLDR执行此操作:

$query = $articles->find('list', [
    'keyField' => function ($e) {
         return $e->date->format('Y-m-d');
     },
    'valueField' => 'title'
]);

工作原理说明:

基本上,它将每个实体(在您的案例中是每篇文章)的值放入变量$e中,并允许您使用/修改它的数据,并返回要用作键(或值)字段的字符串。在上面的例子中,它获取date对象,并将其格式化为字符串,然后返回用作键。

我尝试了一个类似的例子,但我得到了相同的错误。

查看错误堆栈似乎与cake返回Time对象而不是字符串这一事实有关。

我找到了一个变通方法:你可以在你的实体中创建一个虚拟字段

Holyday实体

protected function _getFormattedDate()
{
    if(isset($this->date))
        return $this->date->format('Y-m-d');
    return null;
}

所以你可以做

$holidays = $holidays->find('list',[
    'keyField' => 'formatted_date',
    'valueField'=>'name',
])->toArray();

您还可以使用Dave的建议来创建一个自定义查找器。

假期表

public function findDate(Query $query, array $options)
{
    $options['keyField'] = function ($e) {
        if(isset($e->date))
            return $e->date->format('Y-m-d');
        return null;
    };
    $options['valueField'] = 'name';
    return  $this->findList($query, $options);
}

我刚刚添加了一个关于是否设置日期字段的控件,否则可能会出现错误。

控制器

$holidays->find('date')->toArray();