Justin
Justin

Reputation: 2924

In CakePHP, how can you determine if a field was changed in an edit action?

I'm using the cacheCounter in CakePHP, which increments a counter for related fields.

Example, I have a Person table a Source table. Person.source_id maps to a row in the Source table. Each person has one Source, and each Source has none or many Person rows.

cacheCounter is working great when I change the value of a source on a person. It increments Source.Person_Count. Cool.

But when it increments, it adds it to the destination source for a person, but doesn't remove it from the old value. I tried updateCacheControl() in afterSave, but that didn't do anything.

So then I wrote some code in my model for afterSave that would subtract the source source_id, but it always did this even when I wasn't even changing the source_id. (So the count went negative).

My question: Is there a way to tell if a field was changed in the model in CakePHP?

Upvotes: 11

Views: 9950

Answers (7)

Sebastian Sperandio
Sebastian Sperandio

Reputation: 184

You could use ->isDirty() in the entity to see if a field has been modified.

// Prior to 3.5 use dirty()
$article->isDirty('title');

check the doc: https://book.cakephp.org/3/en/orm/entities.html#checking-if-an-entity-has-been-modified

Upvotes: 1

Vinayak Phal
Vinayak Phal

Reputation: 8919

With reference to Alexander Morland Answer.

How about this instead of looping through it in before filter.

$result = array_diff_assoc($this->old[$this->alias],$this->data[$this->alias]);

You will get key as well as value also.

Upvotes: 8

Alexander Morland
Alexander Morland

Reputation: 6434

To monitor changes in a field, you can use this logic in your model with no changes elsewhere required:

function beforeSave() {
    $this->recursive = -1;
    $this->old = $this->find(array($this->primaryKey => $this->id));
    if ($this->old){
        $changed_fields = array();
        foreach ($this->data[$this->alias] as $key =>$value) {
            if ($this->old[$this->alias][$key] != $value) {
                $changed_fields[] = $key;
            }
        }
    }
    // $changed_fields is an array of fields that changed
    return true;
}

Upvotes: 18

Sajib Hassan
Sajib Hassan

Reputation: 11

You can call getAffectedRows() on any model class.

From class Model :

/**
 * Returns the number of rows affected by the last query
 *
 * @return int Number of rows
 * @access public
 */
    function getAffectedRows() {
        $db =& ConnectionManager::getDataSource($this->useDbConfig);
        return $db->lastAffected();
    }

Upvotes: -1

neilcrookes
neilcrookes

Reputation: 4203

In the edit view, include another hidden field for the field you want to monitor but suffix the field name with something like "_prev" and set the value to the current value of the field you want to monitor. Then in your controller's edit action, do something if the two fields are not equal. e.g.

echo $form->input('field_to_monitor');
echo $form->hidden('field_to_monitor_prev', array('value'=>$form->value('field_to_monitor')));

Upvotes: 0

neilcrookes
neilcrookes

Reputation: 4203

Edits happen infrequently, so another select before you do the update is no big deal, so, fetch the record before you save, save it, compare the data submitted in the edit form with the data you fetched from the db before you saved it, if its different, do something.

Upvotes: 0

Till
Till

Reputation: 22408

See if the "save" uses some sort of DBAL call that returns "affected rows", usually this is how you can judge if the last query changed data, or if it didn't. Because if it didn't, the affected rows after an UPDATE-statement are 0.

Upvotes: -1

Related Questions