Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Yii composite primary keys with isNewRecord

Tags:

php

mysql

yii

I have a mysql table with composite keys ( user_id , category_id ); I am trying to update the last access for these records as following

$userCategory = new UserCategory;
$userCategory->user_id = 1;
$userCategory->category_id = 15;
echo $userCategory->isNewRecord; //always true
$userCategory->last_access = Now();

$userCategory->save();

The {$userCategory->isNewRecord} and when I try to save() the MySQL generates a duplicate error for the composite Primary keys.

I also added this to UserCategory model but didn't help

public function primaryKey() {
        return array('user_id', 'category_id');
    }

****Update: Sorry for the confusion. My question is how to achieve the same result as "ON DUPLICATE KEY UPDATE" in the Yii framework. In other words, how to do the insert or update in one SQL query. if you look at the source code for save()

public function save($runValidation=true,$attributes=null)
{
    if(!$runValidation || $this->validate($attributes))
        //checking if new record
        return $this->getIsNewRecord() ? $this->insert($attributes) : $this->update($attributes);**
    else
        return false;
}
like image 774
Gadelkareem Avatar asked Mar 04 '13 12:03

Gadelkareem


1 Answers

Actually, the problem is that if isNewRecord is always true, it means that Yii is going to use an INSERT statement instead of an UPDATE statement when saving the model to the database.. that is why you always get the duplicate pk error, even if it's composite.

Here is the official documentation about IsNewRecord . So, the problem is that you're using

$userCategory = new UserCategory; //Always a new record, tries to INSERT

So to resolve this you have to find the record and evaluate if it is found before saving it, instead. Documentation can also be read Here about the find() family of methods and their return value, the return values of the find() methods vary slightly on their nature:

find..() returns the record found or NULL if no record is found.

findAll..() returns an array containing all the records found or an empty array if no records are found.

You can use this return value to differentiate wether a primary key exists or not:

$userCategory = UserCategory::model()->findByAttributes(array('user_id '=>1,'category_id '=>15));
// if user does not exist, you need to create it
if ($userCategory == NULL) {
     $userCategory = new UserCategory;
     $userCategory->user_id = 1;
     $userCategory->category_id = 15;
}
echo $userCategory->isNewRecord; //you will see the difference if it does exist or not exist
$userCategory->last_access = Now();
$userCategory->save();

This will ensure that the framework uses the INSERT or UPDATE statement correctly, avoiding the duplicate PK error you're getting.

Edit: Enhanced the example code to properly populate the record when it's new.

like image 138
Snivs Avatar answered Oct 25 '22 06:10

Snivs