www.webdeveloper.com
Results 1 to 9 of 9

Thread: [RESOLVED] CakePHP saving makes me want to cry

Hybrid View

  1. #1
    Join Date
    Aug 2007
    Location
    London
    Posts
    410

    resolved [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");
    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.

  2. #2
    Join Date
    Nov 2008
    Posts
    2,477
    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.
    The first rule of Tautology Club is the first rule of Tautology Club.

  3. #3
    Join Date
    Aug 2007
    Location
    London
    Posts
    410
    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:

    PHP Code:
    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;

    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'
    If I use $this->data["Host"]["id"] and

    Code:
    SQL Error: 1062: Duplicate entry '1-15' for key 'unique_host'
    if I use $this->id.

  4. #4
    Join Date
    Aug 2007
    Location
    London
    Posts
    410
    Code is changed slightly to:

    PHP Code:
    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;

    But still no luck.

  5. #5
    Join Date
    Nov 2008
    Posts
    2,477
    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).
    The first rule of Tautology Club is the first rule of Tautology Club.

  6. #6
    Join Date
    Aug 2007
    Location
    London
    Posts
    410
    First time around I tried doing a saveAll from a related model. Next I tried doing it from
    PHP Code:
    $this->Model1->Model2->saveAll($data["Model1"]["Model2"]) 
    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?

  7. #7
    Join Date
    Nov 2008
    Posts
    2,477
    Quote Originally Posted by blue-eye-labs View Post
    First time around I tried doing a saveAll from a related model. Next I tried doing it from
    PHP Code:
    $this->Model1->Model2->saveAll($data["Model1"]["Model2"]) 
    and that didn't work either...
    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.
    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?
    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.
    The first rule of Tautology Club is the first rule of Tautology Club.

  8. #8
    Join Date
    Aug 2007
    Location
    London
    Posts
    410
    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
    PHP Code:
    $this->model1->model2->save($data_item_from_loop); 
    but it didn't work either.

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

    (Thanks as always)

  9. #9
    Join Date
    Aug 2007
    Location
    London
    Posts
    410
    Hurrah! Hurrah! Hurrah!

    It works and it isn't even too dirty!

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

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
HTML5 Development Center



Recent Articles