3

In my code I am trying to create a lock entity when a controller function is called. Once I create the new entity I save this in the database. Once the controller function finishes the rest of its logic I update the lock entity before I return the redirect. However when I update the entity and then save again it will always insert a new database row rather than update the existing entity.

Things I have tried so far.

  • I called $entity->isNew(false);
  • I used find() method to get entity before update and save
  • Used patchEntity method before save()

Both of these methods should update isNew() to signal save() to update the entry rather than insert a new entry, however I am always getting a new row added to the database.

Here is the relavent code.

This is the logic inside of my controller function

//Inside of edit function of controller

$editLockTable = TableRegistry::get('TableLocks');
$editLock = newEntity($userId, $postId);
$editLock->lock();
if(!$editLockTable->save($editLock)){
    Throw new \Exception("Error with saving lock");
}
.
. // Some other controller function code
.
$editLock->unlock();
$editLock->isNew(false);
if(!editLockTable->save($editLock)){
     Throw new \Exception("Error with saving unlock");
}
//return redirect

Here is the logic inside my Entity class

//Inside of Entity class for EditLock

public function lock($userId, $postId){
    $this->user_id = $userId;
    $this->post_id = $postId;
    $this->start_time = Time::now();
    $this->is_locked = true;
    $this->expire_time = Time::now()->modify('+10 minutes');
}

public function unlock(){
    $this->end_time = Time::now();
    $this->is_locked = false;

edit_locks table definition

CREATE TABLE 'edit_locks' (
     'id' int(11) NOT NULL AUTO_INCREMENT,
     'post_id' int(11) NOT NULL,
     'user_id' int(11) NOT NULL,
     'is_locked' tinyint(1) DEFAULT '0',
     'start_time' datetime DEFAULT '0000-00-00 00:00:00',
     'end_time' datetime DEFAULT '0000-00-00 00:00:00',
     'expires_time' datetime DEFAULT '0000-00-00 00:00:00',
     'renews' int(11) DEFAULT 0,
     PRIMARY KEY ('id'),
     KEY 'fk_post_id' ('post_id'),
     CONSTRAINT 'fk_post_id' FOREIGN KEY ('post_id') REFERENCES 'posts'('id')
     ENGINE=InnoDB DEFAULT CHARSET=latin1
)

What I am getting in my database after controller function finishes

id|post_id|user_id|is_locked|start_time|end_time|expires_time|renews
1 | 999 | 32 | 1 | 2017-09-14 ... | 0000-00-00 ... | 2017-09-14 ... | 0
2 | 999 | 32 | 0 | 2017-09-14 ... | 2017-09-14 ... | 2017-09-14 ... | 0

What I want in my database after controller function finishes

id|post_id|user_id|is_locked|start_time|end_time|expires_time|renews
1 | 999 | 32 | 0 | 2017-09-14 ... | 2017-09-14 ... | 2017-09-14 ... | 0

With both is_locked and end_time updated and not a new row

Zackary Murphy
  • 421
  • 5
  • 10
user2860682
  • 89
  • 2
  • 7
  • Check if your entity isDirty(), if not flag one field as dirty using setDirty(). Table::save() won't save the entity if it's clean because it's seen as unchanged. – floriank Sep 14 '17 at 20:53
  • So I set the dirty flag on a field. In my debug logs I can see isNew() == false and dirty == true, however I am still getting a separate row inserted into the table rather than an update. – user2860682 Sep 15 '17 at 12:02
  • Hey just curious if my answer helped at all or if you still needed help on this. – KaffineAddict Oct 09 '17 at 16:48

1 Answers1

1

Your primary key is listed as ID and you are not setting that anywhere it doesn't look like. If your primary key doesn't match you will not be able to update a record. Why not do something like.

$editLock = editLockTable->findByUserIdAndPostId($userId, $postId);
if($editLock == null) { $editLock = newEntity($userId, $postId); }

Better yet you could do a findOrCreate call as well that would let you handle both situations in one call. findOrCreate will create an entity with the specified conditions if a record is not found.

KaffineAddict
  • 436
  • 2
  • 11