How to put Combined Fields Into CakePHP's Model->generateList()
Posted by Tim Koschützki, on Aug 09, 2007 - in PHP & CakePHP » DataSources, Models & Behaviors
Deprecated post
The authors of this post have marked it as deprecated. This means the information displayed is most likely outdated, inaccurate, boring or a combination of all three.
Policy: We never delete deprecated posts, but they are not listed in our categories or show up in the search anymore.
Comments: You can continue to leave comments on this post, but please consult Google or our search first if you want to get an answer ; ).
Hi folks. Two days ago, someone on #cakephp had the problem of getting combined values out of the Model->generateList() function in CakePHP. I advised him on doing some Set::extract() things, which at the end of the day got rather complicated. As a result, I was conscience-stricken. : ] Here is a much more elegant solution I could come up with.
What is Model->generateList() good for in the first place?
Suppose you want to build a selectTag in cake 1.2 using data from your users table. The options of the select tag shall contain the user IDs, while the captions shall be the first names of the users. It's very easy to do.
In your controller:
-
$this->set('users', $this->User->generateList(null, null, null,'{n}.User.id', '{n}.User.first_name'));
In your view:
Cake will automagically populate the select field as necessary.
The Problem
Now your project lead comes in and tells you there are 20 users named "Jeff" and 15 named "Peter" in the application, so your select field is not worthy at all. You need to supply both the user's first_name and last_name combined. You got owned! :/ Because generateList does not do that for you.
-
$this->set('users', $this->User->generateList(null, null, null,'{n}.User.id', '{n}.User.first_name {n}.User.last_name''));
..will not work. Althrough it would be cool. ; )
The Solution
Tinkered a bit around and here is where I got to. Place the following code in your app_model.php file:
-
function myGenerateList($conditions = null, $order = null, $limit = null, $keyPath = null, $valuePath = null, $separator = '') {
-
if ($keyPath == null && $valuePath == null && $this->hasField($this->displayField)) {
-
} else {
-
$fields = null;
-
}
-
$recursive = $this->recursive;
-
$result = $this->findAll($conditions, $fields, $order, $limit);
-
$this->recursive = $recursive;
-
-
if(!$result) {
-
return false;
-
}
-
-
if ($keyPath == null) {
-
$keyPath = '{n}.' . $this->name . '.' . $this->primaryKey;
-
}
-
-
if ($valuePath == null) {
-
$valuePath = '{n}.' . $this->name . '.' . $this->displayField;
-
}
-
-
// extract the keys as normal
-
-
-
-
// explode the value path by our delimiter
-
-
$i = 0;
-
foreach($tmpVals as $tmpVal) {
-
// extract the data for each path sibling
-
-
// and insert it at the appropriate position in our final value array
-
// use the separator when we need to append the values
-
foreach($vals as $key => $value) {
-
$finalVals[$key] = $value;
-
} else {
-
$finalVals[$key] .= $separator.$value;
-
}
-
}
-
$i++;
-
}
-
-
-
$return = array_combine($keys, $finalVals);
-
return $return;
-
}
-
return null;
-
}
Now, in your controller put in this:
-
$this->set('users', $users = $this->User->myGenerateList(null, 'User.id ASC', null,'{n}.User.id', '{n}.User.first_name#{n}.User.last_name', ' '));
The Difference To The Normal generateList()
There are five differences:
- Path siblings are separated by a '#'. Examples: {n}.User.first_name#{n}.User.last_name, {n}.Model.field1#{n}.Model.field2
- You can use as many path siblings as you like: {n}.User.first_name#{n}.User.last_name#{n}.User.about_me#{n}.User.cool_field
- The last parameter is the separator between the values outputted. You can use any form of string.
- You cannot supply 'id ASC' as the ordering, because id might be ambigious. Use Model.id for your ordering needs.
- You cannot use $groupPath with this. Might implement this later.
Have fun with this and please let me know about issues. : ]