How do I achieve virtual attributes in CakePHP (using code, not SQL) as implemented in Ruby on Rails
Source: http://asciicasts.com/episodes/16-virtual-attributes
I'd like to achieve a similar setup as below, but in CakePHP and where the virtual attributes are created using code, not SQL (as documented at http://book.cakephp.org/view/1070/Additional-Methods-and-Properties#Using-virtualFields-1590).
class User < ActiveRecord:开发者_如何学JAVA:Base
# Getter
def full_name
[first_name, last_name].join(' ')
end
# Setter
def full_name=(name)
split = name.split(' ', 2)
self.first_name = split.first
self.last_name = split.last
end
end
As you've rightly mentioned, virtualFields are used to create extra attributes for models using SQL. For generating fields using code, you should try the afterFind
method:
function afterFind($results) {
foreach ($results as $key => $val) {
if (isset($val['User']['first_name']) && isset($val['User']['last_name'])) {
$results[$key]['User']['full_name'] = $this->formatName($val['User']['first_name'], $val['User']['last_name']);
}
}
return $results;
}
function formatName($firstName, $lastName) {
$firstName = trim($firstName);
$lastName = trim($lastName);
return $lastName . ', ' . $firstName;
}
You can read more on this from the book here. I'd assume you'll have to test this a little further, and probably include the afterFind
method's second parameter $primary
.
EDIT: I just realized that another way of doing this would be to include such functions directly in your model:
function getFullName($user = null) {
if ($user) {
$this->set($user);
}
return $this->data['User']['first_name'] . ' ' . $this->data['User']['last_name'];
}
And there's your getter!
You can use beforeSave and afterFind callback. Here is my code:
class User extends AppModel {
// Setter
function beforeSave() {
if(!empty($this->data['User']['full_name'])) {
list($this->data['User']['first_name'], $this->data['User']['last_name']) = explode(" ", $this->data['User']['full_name']);
}
return true
}
// Getter
function afterFind(array $results, bool $primary) {
foreach($results as $key => $result) {
$result['User']['full_name'] = $result['User']['first_name'] + " " + $result['User']['last_name'];
$results[$key] = $result;
}
return $results;
}
}
But I think SQL concat will be faster than PHP string concat. So I think (if you can) using virtual fields will be better.
精彩评论