We have moved our forum to GitHub Discussions. For questions about Phalcon v3/v4/v5 you can visit here and for Phalcon v6 here.

Snapshot functionality in models, and update() method

I am overriding the built-in update() method in Phalcon\Mvc\Model in order to do audit logging. So if I have a MyModel, it extends ModelBase which extends Phalcon\Mvc\Model. In ModelBase:

  public function update($data=false, $whiteList=false){

    date_default_timezone_set('America/New_York');

    $ret=parent::update($data,$whiteList);

    //acount for blank passed data array
    if(!$data){
      $data = $this->toArray();
    }

    $preupdatedata = $this->getSnapshotData();

    //create a new audit transaction row
    $tr = new AuditTransaction();
    $ts = new \DateTime();

    $identity = $this->getDI()->get('auth')->getIdentity();

    //assignment of variables
    $tr->assign ( array(
            'schema_name' => 'dsmc',
            'table_name' => $this->table_name,
            'table_id' => $this->id,
            'timestamp' => $ts->format('Y-m-d H:i:s:u'),
            'ip_address' => $this->getIP(),
            'user_id' => $identity['id'], //change to real user ID once authentication implemented
            'action_type' => 'U' //update
            ));
    $tr->create();

    foreach($data as $col_name => $datum){
      if($this->hasChanged($col_name)){
    $av = new AuditValues();
    $av->assign(array ( 
         'transaction_id' => $tr->id,
         'column_name' => $col_name,
         'new_value' => $datum,
         'old_value' => $preupdatedata[$col_name]));
    $av->create();
      }
    }
    return $ret;
  }

Since I am calling the update() on the second line, I assume that $this->getShapShotData() will contain the previous data values after the update occurs, is that correct? I am setting $this->keepSnapshots(true) in the ModelBase's initialize()...

If MyModel (which extends ModelBase) is using getters and setters, and I do setSomeField() does the value change immediately or only after an explicit call to update()? When I do currently in a controller:

$model = MyModel::findFirstById($someid);
$model->setSomeValue($value);
$model->update();

I get "Data passed to update() must be an array"

Any ideas why?

Maybe instead of overriding update you can hook into afterUpdate? Instead of re-inventing the wheel I reccomend you look at a bit cleaner of a solution. Infact this post has several different ways to tackle it:

https://blog.phalcon.io/post/47652831003/tutorial-creating-a-blameable-behavior-with-phalcon

public function notify($eventType, $model)
{
    //Fires 'logAfterUpdate' if the event is 'afterUpdate'
    if ($eventType == 'afterUpdate') {
        return $this->auditAfterUpdate($model);
    }
}


40.7k

I saw that post after I had already written a lot of my stuff :( Also I need to audit VIEWS as well and I have a ton of code around that so I don't want to ditch what I have done already...

If I use afterUpdate() will the contents of getSnapShotData() contain the pre-update values?