views:

240

answers:

6

Hi all,

If I have a person model with first_name and last_name, how do I create and display a full_name? I would like to display it at the top of my Edit and View views (i.e. "Edit Frank Luke") and other places. Simply dropping echoes to first_name and last_name isn't DRY.

I'm sorry if this is a very simple question, but nothing has yet worked.

Thank you, Frank Luke

Edit for clarity: Okay, I have a function on the person model.

function full_name() {
    return $this->Person->first_name . ' ' . $this->Person->last_name;
}

In the view, I call

echo $person['Person']['full_name']

This gives me a notice that I have an undefined index. What is the proper way to call the function from the view? Do I have to do it in the controller or elsewhere?

A: 

You would probably need to take the two fields that are returned from your database and concatenate them into one string variable that can then be displayed.

Chris
That's what I've been attempting. I can make the function just fine. It's calling it that hangs me out to dry. I should have been more clear.
Frank Luke
+1  A: 

The arrays set by the save() method only return fields in the datbase, they do not call model functions. To properly use the function above (located in your model), you will need to add the following:

to the controller, in the $action method:

$this->set( 'fullname', $this->Person->full_name();
// must have $this-Person->id set, or redefine the method to include $person_id

in the view,

echo $fullname;

Basically, you need to use the controller to gather the data from the model, and assign it to the controller. It's the same process as you have before, where you assign the returned data from the find() call to the variable in the view, except youre getting the data from a different source.

Travis Leleu
+2  A: 

If what you are wanting is just to display a full name, and never need to do any database actions (comparisons, lookups), I think you should just concatenate your fields in the view.

This would be more aligned with the MVC design pattern. In your example you just want to view information in your database in a different way.

Since the action of concatenating is simple you probably don't save much code by placing it in a separate function. I think its easiest to do just in the view file.

If you want to do more fancy things ( ie Change the caps, return a link to the user ) I would recommend creating an element which you call with the Users data.

Felix
This covered the needs. I went ahead with the element.
Frank Luke
+1  A: 

You must use afterFind callback for it.

+1  A: 

There are multiple ways of doing this. One way is to use the afterFind-function in a model-class. See: http://book.cakephp.org/view/681/afterFind.

BUT, this function does not handle nested data very well, instead, it doesn't handles it al all! Therefore I use the afterfind-function in the app_model that walks through the resultset

function afterFind($results, $primary=false){
 $name = isset($this->alias) ? $this->alias : $this->name;
 // see if the model wants to attach attributes
 if (method_exists($this, '_attachAttributes')){
  // check if array is not multidimensional by checking the key 'id'
  if (isset($results['id'])) {
   $results = $this->_attachAttributes($results);
  } else {
   // we want each row to have an array of required attributes
   for ($i = 0; $i < sizeof($results); $i++) {
    // check if this is a model, or if it is an array of models
    if (isset($results[$i][$name]) ){
     // this is the model we want, see if it's a single or array
     if (isset($results[$i][$name][0]) ){
      // run on every model
      for ($j = 0; $j < sizeof($results[$i][$name]); $j++) {
       $results[$i][$name][$j] = $this->_attachAttributes($results[$i][$name][$j]);
      }
     } else {
      $results[$i][$name] = $this->_attachAttributes($results[$i][$name]);
     }
    } else {
     if (isset($results[$i]['id'])) {
      $results[$i] = $this->_attachAttributes($results[$i]);
     }
    }
   }
  }
 }
 return $results;
}

And then I add a _attachAttributes-function in the model-class, for e.g. in your Person.php

function _attachAttributes($data) {
 if (isset($data['first_name']) && isset($data['last_name'])) {
  $data['full_name'] = sprintf("%s %s %s", $data['first_name'], $data['last_name']);
 }
 return $data;
}

This method can handle nested modelData, for e.g. Person hasMany Posts then this method can also attachAttributes inside the Post-model.

This method also keeps in mind that the linked models with other names than the className are fixed, because of the use of the alias and not only the name (which is the className).

blavla
A: 

http://old.nabble.com/Problems-with-CONCAT-function-td22640199.html http://teknoid.wordpress.com/2008/09/29/dealing-with-calculated-fields-in-cakephps-find/

Read the first one to find out how to use the 'fields' key i.e. find( 'all', array( 'fields' => array( )) to pass a CONCAT to the CakePHP query builder.

The second link shows you how to merge the numeric indexes that get returned when you use custom fields back into the appropriate location in the returned results.

This should of course be placed in a model function and called from there.

Abba Bryant