You are Here: Articles » Using afterFind() to create pseudofields in CakePHP

Using afterFind() to create pseudofields in CakePHP

CakePHP provides a useful model function, afterFind(), which can be used to manipulate results returned from any find(), findAll() or findBy<field>() query.

Tagged with CakePHP and Web Development
Posted on 6/5/07 by Paul Herron

One useful application of this feature is in merging data from two or more database fields into one pseudofield. In the example below, afterFind() is added to a User model. A foreach statement takes the firstName and lastName fields for each user and creates a new field, fullName.

  1. <?php
  2. class User extends AppModel
  3. {
  4.     var $name = 'User';
  5.    
  6.     function afterFind($results) {
  7.         // For any results returned from the 'User' model, take 'firstName' and 'lastName' and use them to produce a 'fullName' pseudofield.
  8.         foreach ($results as $key => $val) {
  9.             if (isset($val['User']['firstName']) && isset($val['User']['lastName'])) {
  10.                 $results[$key]['User']['fullName'] = $val['User']['firstName'] . ' ' . $val['User']['lastName']
  11.             }
  12.         }
  13.       return $results;
  14.     }
  15. }
  16. ?>

CakePHP makes $results available automatically, and automatically deals with them when they're returned from the afterFind(), so this function should work 'as is'.

All being well, a find(), findAll() or findBy() query in the controller will now give an array structure like this:

  1. [User] => Array
  2.     (
  3.     [0] =>
  4.         (
  5.         [firstName] => Graeme
  6.         [lastName] => Garden
  7.         [fullName] => Graeme Garden
  8.         )
  9.        
  10.     [1] =>
  11.         (
  12.         [firstName] => Tim
  13.         [lastName] => Brooke-Taylor
  14.         [fullName] => Tim Brooke-Taylor
  15.         )
  16.     )

afterFind() can result in significantly tidier code, and puts this kind of processing where it belongs - in the model. It's also a useful workaround for inserting more than one field into a generateList() statement. The label parameter in generateList() can only be sourced from one field, but this can be the pseudofield generated in the example above.

  1. $this->set('users', $this->User->generateList(null,null,null,'{n}.User.id','{n}.User.fullName'));

This would set a $users array for use in the view, and could be used be used to output a select box with each option set to a user's full name.

Comments

Tane Piper wrote on 18/7/07:

Hey - great article!  Works a treat in my application for generateList and having more than one value!

Phil McGuire wrote on 31/7/07:

Thanks for the article! Just what I needed but there's a syntax error in it just so you know.

 

if (isset($val['User']['firstName']) && (isset($val['User']['lastName'])) {

should be:

if (isset($val['User']['firstName']) && isset($val['User']['lastName'])) {

 

Thanks! 

Paul Herron wrote on 25/8/07:

Hi Phil,

Glad you found it useful!

Thanks for the info on the mistake - that's amended now. 

Mike wrote on 24/6/08:

Hey.

Nice tip, I was struggling to find out how to do this for a while, but it works like a charm.

Thank, Mike.

zoli wrote on 25/10/08:

Thanks, very useful article!

 Wouldn't need such inventions if CakePHP would be a true OOP framework, but... c'est la vie. I suggest using Ruby on Rails instead.

Bennigraf wrote on 3/11/08:

Hi there!

Thanks for your hint - I came across by chance and it helped me alot already, although it's kind of old. I just discovered one problem: When only one result is returned (both on purpose using find('first') and just using conditions) cake creates the $results-array without the numeric indizes for which your way doesn't sets the fullname, since $key is already 'User' and val contains the indizes 'firstName' and 'lastName' directly.

 Any Ideas on how to work around this except adding another if (like if(isset($var['firstName'] && ...))?

Greetings, Benni. 

Nate Klaiber wrote on 7/11/08:

I would agree with zoli. This is a lot of extra work to get a 'full_name' method. If CakePHP would be truly OOP, then I could have an instance method - and I wouldn't need any extra loops to iterate over and add such methods. I just can't see how this is a good design decision.

dogmatic wrote on 29/4/09:

@Nate

if you think its not so good why not supply a better solution then?

Heryudi Ganesha wrote on 28/7/09:

Hi, thanks for the tips! But when I'm using it like, example:

 

if ($val['Posting']['amount'] == 1) {

 

This gives me following notice:

Undefined index:  Posting [APP\models\posting.php, line 38]

Line 38: if ($val['Posting']['amount'] == 1) {

 

The logic in the afterFind callback works perfectly the way it's supposed to do.

 

Any idea why cakephp display the notice?

Atea Webdevelopment wrote on 12/4/10:

Any clues on what I need to do to sort on a pseudofield?

 

Should I add a custom Mysql query?

I need to sort on someting like this:

COALESCE(price_month_action, price_month_regular) AS price_month_least

 

 

Leave a Comment

CAPTCHA[Refresh]

« Articles

Article Tags

Show all articles, or just those tagged as:

Feed

The articles RSS feed is available.

Elsewhom

See More…

Back to top.