/    Sign up×
Community /Pin to ProfileBookmark

[RESOLVED] CakePHP saving makes me want to cry

And this is probably because I am misunderstanding horribly, but please (think of the children?)

Anyway, here we go.

I have a page which edits associated models links to the current model (has many actually). I pass in a data array into save all like so:

[CODE]
array => 0 => array(“name”=>”One”), 1=> array(“name”=>”Two”);
[/CODE]

for argument’s sake. Since the names are unique (it’s actually more complex than this) I check for that name, if it exists I set the “id” field in the data to the id of the record in the table (because I want to update not to insert).

Needless to say, this doesn’t work. There are two things that go wrong:

1) I have to cycle through each item and use save() because saveAll() is only taking the first item in the array.

2) No matter how I try and set the ID I can’t get it to do anything except insert. How do I make it update?

Any ideas would be most welcome.

to post a comment
PHP

8 Comments(s)

Copy linkTweet thisAlerts:
@MindzaiApr 16.2010 — Not sure I fully understand your issue - can you post your code (the relevant bits of the view and controller in particular)? Also if you are trying to enforce uniqueness, you can use standard model validation for this. There is predefined rule for enforcing unique values.
Copy linkTweet thisAlerts:
@blue-eye-labsauthorApr 17.2010 — Uniqueness is enforced in the tables (so thank you for that, I will implement this) but that is not so much my problem as how to trigger update instead of save.

Basically I've been doing this:

[code=php]
function beforeSave() {
$host = $this->find("first", array("condition"=>array(
"project_id" => $this->data["Host"]["project_id"],
"institution_id" => $this->data["Host"]["institution_id"]
)));
if($host) {
$this->id = $host["Host"]["id"];
}

return true;
}
[/code]


What I want is that if this particular "Host" exists (i.e. a record with the same project_id and institution_id) then that record should be updated (because there is some information which could have changed and is in $this->data["Host"]).

I had previously tried using $this->data["Host"]["id"] instead of $this->id but it didn't work either. It always tries to insert rather than update. Therefore I get the following SQL error:

[CODE]
SQL Error: 1062: Duplicate entry '1' for key 'PRIMARY'
[/CODE]


If I use $this->data["Host"]["id"] and

[CODE]
SQL Error: 1062: Duplicate entry '1-15' for key 'unique_host'
[/CODE]


if I use $this->id.
Copy linkTweet thisAlerts:
@blue-eye-labsauthorApr 17.2010 — Code is changed slightly to:

[code=php]
function beforeSave() {
$host = $this->find("first", array("condition"=>array(
"project_id" => $this->data["Host"]["project_id"],
"institution_id" => $this->data["Host"]["institution_id"]
)));
if($host) {
$this->data["Host"]["id"] = $host["Host"]["id"];
}

$this->set($this->data["Host"]);

return true;
}

[/code]


But still no luck.
Copy linkTweet thisAlerts:
@MindzaiApr 17.2010 — Are you trying to run this by calling saveAll from a related model? If so, you will probably find that cake is internally storing the data array at the moment you call saveAll, so even though you modify $model->data in beforeSave, these changes are effectively ignored, meaning the FK is never set. You can test for this by using debug($this->data) and comparing it to the SQL log. If that is the issue you can try moving this logic to the controller (as dirty as that solution makes me feel), or else to the beforeSave of the main model (which IIRC is not affected).
Copy linkTweet thisAlerts:
@blue-eye-labsauthorApr 18.2010 — First time around I tried doing a saveAll from a related model. Next I tried doing it from [code=php]$this->Model1->Model2->saveAll($data["Model1"]["Model2"])[/code] and that didn't work either...

I'm now back to trying it from a related model.

The weird thing is that it sets the ID fine (because I get the primary key error) but it uses insert and not update for some bizarre reason.

Maybe I should just make a "clean up data" function for each model and save the data that comes out of that?
Copy linkTweet thisAlerts:
@MindzaiApr 18.2010 — First time around I tried doing a saveAll from a related model. Next I tried doing it from [code=php]$this->Model1->Model2->saveAll($data["Model1"]["Model2"])[/code] and that didn't work either...[/quote]

That's what I meant by saving via a related model.


The weird thing is that it sets the ID fine (because I get the primary key error) but it uses insert and not update for some bizarre reason.
[/quote]


Yes, even though it appears to set it be set, the moment you call saveAll, cake internally saves the data state right then, so anything you do in beforeSave is ignored. I've never seen this documented anywhere, I had to dig through the source code to find it out - you're not the only one who's lost hours to this "feature"!

Maybe I should just make a "clean up data" function for each model and save the data that comes out of that?[/QUOTE]

That's what I end up doing usually. It's a bit messy and I don't really like it, but it does the job. The other option is just not to use saveAll - it's a bit of a nasty function really.
Copy linkTweet thisAlerts:
@blue-eye-labsauthorApr 19.2010 — I'm glad you had to dig through the source rather than me. I did it once and it was not fun. The documentation is very sketchy in this area.

So I think I'll create the data cleaning function in my models because that seems to be the way forward.

I think I have to use save all because otherwise I have to make a foreach loop when I want to save this data which is a pain.

Having said that, I did try using a foreach loop and [code=php]$this->model1->model2->save($data_item_from_loop);[/code] but it didn't work either.

I'll post here whether this new way works or not.

(Thanks as always)
Copy linkTweet thisAlerts:
@blue-eye-labsauthorApr 19.2010 — Hurrah! Hurrah! Hurrah!

It works and it isn't even too dirty!

Thanks Mindzai, although I'm sure I'll have more problems soon ?
×

Success!

Help @blue-eye-labs spread the word by sharing this article on Twitter...

Tweet This
Sign in
Forgot password?
Sign in with TwitchSign in with GithubCreate Account
about: ({
version: 0.1.9 BETA 5.22,
whats_new: community page,
up_next: more Davinci•003 tasks,
coming_soon: events calendar,
social: @webDeveloperHQ
});

legal: ({
terms: of use,
privacy: policy
});
changelog: (
version: 0.1.9,
notes: added community page

version: 0.1.8,
notes: added Davinci•003

version: 0.1.7,
notes: upvote answers to bounties

version: 0.1.6,
notes: article editor refresh
)...
recent_tips: (
tipper: @AriseFacilitySolutions09,
tipped: article
amount: 1000 SATS,

tipper: @Yussuf4331,
tipped: article
amount: 1000 SATS,

tipper: @darkwebsites540,
tipped: article
amount: 10 SATS,
)...