Reputation: 2625
I have used list to get data from the model and it works well
This example is from Cakephp docs
$query = $articles->find('list', [
'keyField' => 'slug',
'valueField' => 'title'
]);
$data = $query->toArray();
I have a table name holidays
id[int] | date[date] | name[varchar(200)] | created[datetime]
So want a list which has date as the key and holiday as value Somthing like this
[
'2016-01-01'=>'New Year',
'2016-01-26'=>'Republic Day',
]
So i created model by cake bake and used this code to achive it
$holidays = TableRegistry::get('Holidays');
$holidays = $holidays->find('list',[
'keyField' => 'date',
'valueField'=>'name',
])->toArray();
But its giving me error
Illegal offset type InvalidArgumentException
When i change the keyField from date with name it works great.
Here is the logs
2016-04-29 04:26:41 Error: [InvalidArgumentException] Illegal offset type Request URL: /sfworxerp/api/attendances/getMonthAttendanceData Stack Trace: F:\public_html\sfworxerp\vendor\cakephp\cakephp\src\Collection\Iterator\MapReduce.php(160): Cake\Collection\Iterator\MapReduce::emit() F:\public_html\sfworxerp\vendor\cakephp\cakephp\src\Collection\CollectionTrait.php(386): Cake\Collection\Iterator\MapReduce->emit('New Year', Object(Cake\I18n\FrozenDate)) F:\public_html\sfworxerp\vendor\cakephp\cakephp\src\Collection\Iterator\MapReduce.php(177): Cake\ORM\ResultSet->Cake\Collection{closure}(Object(App\Model\Entity\Holiday), 0, Object(Cake\Collection\Iterator\MapReduce)) F:\public_html\sfworxerp\vendor\cakephp\cakephp\src\Collection\Iterator\MapReduce.php(132): Cake\Collection\Iterator\MapReduce->_execute() [internal function]: Cake\Collection\Iterator\MapReduce->getIterator() F:\public_html\sfworxerp\vendor\cakephp\cakephp\src\Collection\Collection.php(50): IteratorIterator->__construct(Object(Cake\Collection\Iterator\MapReduce)) F:\public_html\sfworxerp\vendor\cakephp\cakephp\src\Collection\CollectionTrait.php(405): Cake\Collection\Collection->__construct(Object(Cake\Collection\Iterator\MapReduce)) F:\public_html\sfworxerp\vendor\cakephp\cakephp\src\ORM\Table.php(1062): Cake\ORM\ResultSet->combine('date', 'name', NULL) F:\public_html\sfworxerp\vendor\cakephp\cakephp\src\Datasource\QueryTrait.php(490): Cake\ORM\Table->Cake\ORM{closure}(Object(Cake\ORM\ResultSet)) F:\public_html\sfworxerp\vendor\cakephp\cakephp\src\ORM\Query.php(1141): Cake\ORM\Query->_applyDecorators(Object(Cake\ORM\ResultSet)) F:\public_html\sfworxerp\vendor\cakephp\cakephp\src\Datasource\QueryTrait.php(272): Cake\ORM\Query->_decorateResults(Object(Cake\ORM\ResultSet)) F:\public_html\sfworxerp\vendor\cakephp\cakephp\src\ORM\Query.php(871): Cake\ORM\Query->_all() F:\public_html\sfworxerp\vendor\cakephp\cakephp\src\Datasource\QueryTrait.php(288): Cake\ORM\Query->all() F:\public_html\sfworxerp\src\Controller\Api\AttendancesController.php(133): Cake\ORM\Query->toArray() [internal function]: App\Controller\Api\AttendancesController->getMonthAttendanceData() F:\public_html\sfworxerp\vendor\cakephp\cakephp\src\Controller\Controller.php(429): call_user_func_array(Array, Array) F:\public_html\sfworxerp\vendor\cakephp\cakephp\src\Routing\Dispatcher.php(114): Cake\Controller\Controller->invokeAction() F:\public_html\sfworxerp\vendor\cakephp\cakephp\src\Routing\Dispatcher.php(87): Cake\Routing\Dispatcher->_invoke(Object(App\Controller\Api\AttendancesController)) F:\public_html\sfworxerp\webroot\index.php(37): Cake\Routing\Dispatcher->dispatch(Object(Cake\Network\Request), Object(Cake\Network\Response)) {main}
Any help is highly appreciated
Upvotes: 4
Views: 2806
Reputation: 9398
I tried a similar example and I got your same error.
Looking at the error stack seems it's related to the fact that cake returns a Time object and not a string.
I found a workaround: you can created a virtual field in your entity
Holyday Entity
protected function _getFormattedDate()
{
if(isset($this->date))
return $this->date->format('Y-m-d');
return null;
}
so you can do
$holidays = $holidays->find('list',[
'keyField' => 'formatted_date',
'valueField'=>'name',
])->toArray();
you can also use Dave's suggestion to create a custom finder.
HolidaysTable
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);
}
I just added a control on whether date field is set otherwise you could get an error.
controller
$holidays->find('date')->toArray();
Upvotes: 1
Reputation: 29121
The Problem:
The problem is, for 'date' fields, CakePHP 3 returns an object, not a string:
'date' => object(Cake\I18n\FrozenDate) {
'time' => '1997-01-03T00:00:00+00:00',
'timezone' => 'UTC',
'fixedNowTime' => false
},
Trying to use that as the key doesn't work, and throws the error you're seeing.
How to handle:
Per this area in the CakePHP book, to accommodate this, you can:
use closures to access entity mutator methods in your list finds.
TLDR Do this:
$query = $articles->find('list', [
'keyField' => function ($e) {
return $e->date->format('Y-m-d');
},
'valueField' => 'title'
]);
Explanation for how it works:
Basically, it puts the value of each entity (in your case each article) into the variable $e
, and allows you to use/modify it's data, and return the string you want to use as the key (or value) field. In the case above, it's getting the date
object, and formatting it into a string before returning it to be used as the key.
Upvotes: 8