In the recipe Using callbacks in behaviors we learnt how to implement different model callbacks to perform some tasks automatically. In this recipe we will continue that process and we will learn how to automatically save data that may not be provided in a save
operation.
We will use the Twitter example we have been using in this chapter, so that when a profile is saved, its Twitter URL and its last tweet are saved when creating a new record, or when updating an existing one.
We need a working TwitterAccountBehavior
together with its controllers, models, and views. Follow the recipe Using callbacks in behaviors (there's no need to enable caching in the behavior, so you can omit the There's more section).
Add two fields to the profiles table, url
and last_tweet
, by issuing the following SQL command:
ALTER TABLE `profiles` ADD COLUMN `url` VARCHAR(255) default NULL, ADD COLUMN `last_tweet` VARCHAR(140) default NULL;
app/models/behaviors/twitter_account.php
file and add the following beforeSave
implementation to the TwitterAccountBehavior
class:public function beforeSave($model) { $field = $this->settings[$model->alias]['field']; $twitter = null; if (!array_key_exists($field, $model->data[$model->alias]) && $model->exists()) { $twitter = $model->field($field, array( $model->primaryKey => $model->id )); } elseif (array_key_exists($field, $model->data[$model->alias])) { $twitter = $model->data[$model->alias][$field]; } $data = array( 'url' => !empty($twitter) ? 'http://twitter.com/' . $twitter : null, 'last_tweet' => null ); if (!empty($twitter)) { $tweets = $this->timeline($twitter, 1); if (!empty($tweets) && is_array($tweets)) { $data['last_tweet'] = $tweets[0]->text; } } $model->data[$model->alias] = array_merge( $model->data[$model->alias], $data ); $this->_addToWhitelist($model, array_keys($data)); return parent::beforeSave($model); }
url
and last_tweet
fields will be automatically populated. If we are instead modifying a profile, the last_tweet
field will be updated to reflect the latest tweet from the relevant account.The beforeSave
callback is triggered before a save operation is performed on a model, giving us the chance to add new fields to the set of fields that are about to be saved, or modify other field values.
We started by determining which Twitter account is linked to the profile being saved. If no Twitter account is specified in the data that is about to be saved, and if we are modifying an existing record (we use $model->exists()
for this check), we obtain the account specified in its twitter
field. If instead there's an account specified in the data to be saved, we use that instead.
Regardless of the type of save operation that is about to be performed (creating or updating a record), we set the last_tweet
field to the last tweet published by the specific Twitter account. However, we set the url
field to the appropriate URL-based, on the Twitter account only when we are creating a new record.
Once we have set the data to be saved in the $data
array, we append that data to the $model->data
property that contains all the information that will be saved. We then use the behavior's _addToWhitelist()
method, defined in CakePHP's ModelBehavior
class from which our behavior extends, so that if the developer has chosen to limit the save operation to only a specific set of fields, then our fields are guaranteed to be saved regardless of this restriction.
3.15.14.98