If Exists Update Else Insert

Hey, guys. Hope you got some vision on my issue.

There’s a unique key in my table, which is being formed out from other model values before being set. Sequently, if this key exists, I need to update this record, otherwise I need to create it.

I’m not the only one with this issue, but everywhere I searched I saw something like this:


$model = Transactions::model()->find( "uuid = :uuid",array(':uuid'=>$uuid_string) ); 

if ($model == null) {

$model = new Transactions;

}

For my particular case, this seems to be kind of lame. Isn’t there a way to solve this problem via rules() or another model methods or settings?


$model = Transactions::model()->find( "uuid = :uuid",array(':uuid'=>$uuid_string) ); 

if ($model == null) {

  $model = new Transactions;

  $model->uuid = $uuid_string;

}

//update set needed values

$model->save();



save() will insert new record or update existing one if find() returned such record.

Thank you for your reply redguy, but where possible, i’d rather avoid using find(). I’m making the uuid with beforesave() handler, so I just want to fill my model properties and save(). Than, I want my model to check itself before saving and update the existing record. What do I do?

Why do you want to check the model before saving, what do you want to check?

In my opinion you can easily pre-calculate the id in the controller action before

saving. Then use the find()-function to check whether the id exists and if so,

update the model.

Do you want to update the id of the new model, of the of the existing one?

I do not really understand why you want to avoid find, when you have an index on your

id, this might not decrease the performance too much.

Perhaps I misunderstand you, then, please let me know, but this is what sounds most

desirable to me. Although, I do not know whether this is the most neat solution.

Naturally, to check if a record exists you must use find().

Sorry for long reply, I can’t make more than 3 posts per day. I’m creating my models from different places, so everytime I create it I need to check if record already exists. And if does exist, I need to update the existing record, instead of inserting the new one.

And I don’t want to duplicate uuid calculating and model filling code.

I could write a special function and use it to add/update my records, but I don’t like this way because it seems not to be neat enough :) So I wonder if Yii has built-in tools to do this task (like “unique” validator in rules() or something).

And if it hasn’t, I’ll use find(). Thanks.

Sorry for being so obscure, English is not my native.

I just want a good tidy way to get my task done:

I want to fill model’s properties and just save(). Then I want to calculate uuid and do some other operations in BeforeSave() handler, and then I want my model to check if this uuid already exists, and if it does, update the record.

It seems to me that there’s no way to do it clean and neat, but let me know if I’m wrong, please.

Thanks.

The beforeSave() method isn’t the right place to do this. You should probably create your own method within your model class (or a behavior if you need to reuse it) and encapsulate the logic within that. Your action would end up looking something like this:




$model = new Transactions;


if (isset($_POST['Transactions']))

{

    $model->attributes = $_POST['Transactions'];


    if ($model->createOrUpdate())

    {

        // Flash message, redirect, etc.

    }

}


// Render



[Edit: just saw the post of Keith and that is exactly what I meant]

Dear Nkizza,

What might be a solution for you is to create the function customSave() in your model,

which itself ends with the $this->save();.

Then you can use $model->customSave(); every time you want to save the model. In your

customSave() you can then do the find action and create or update the model. Is this

neat enough for you?

Do you use the beforeSave() functionality since you create your models in different

controller actions and hence want to ‘group’ the general uuid calculation?

Besides, you can either way use the unique validator as rule in your model,

but I think it is better to use find() instead of catch the error of uniqueness.

Good luck.

Thanks, sounds nice, I’m thinking about it. I could do something like




$model = new Transactions;

//...model operations

$model = $model->customSave();


public function customSave() {

$existingModel = self::model()->find('uuid = :uuid', array(':uuid'=>$this->uuid));

$modelForSave = $this;

if ($existingModel != null) {

$existingModel->attributes = $this->attributes;

$modelForSave = $existingModel;

}

$modelForSave->save();

return $modelForSave;

}



At least, I can replace save() method in my Transactions class with my own logic. Thank you, gentlemen :)

UPD: CActiveRecord has insert() and update() public methods I didn’t know about.

So,




public function save() {

    $existingModel = self::model()->find('uuid = :uuid', array(':uuid'=>$this->uuid));

    $result = false;

    if ($existingModel == null) {

        $result = $this->insert();

    } else {

        $this->setIsNewRecord(false);

        $this->setPrimaryKey($existingModel->id);


        $result = $this->update();

    }

    return $result;

}