0

In Laravel PHP I have an object which needs some parameters updating. The object is updated and I can return or dd() the correct values. But when I ->save() it's as if the values haven't been changed. The ->save method works fine, but the way I'm updating the object values is obviously wrong somehow...

So using the following code I loop through an array of parameters to update and create an updated object (simplified example) :

      $account = Account::find('account_id');
      // ^returns something like (object)['user'=>['name'=>'jeff','age'=>'20']];

      $to_update = ['user.name':'john', 'user.age':'50'];

      // the following function converts exploded arrays of key names to php objects
      // ie user.name:"John" becomes user->name = john
      function get($path, $object, $value) {
        $temp = &$object;
        foreach($path as $var) {
            $temp =& $temp->$var;
        }
        $temp = $value;
      }

      foreach($to_update as $keys => $value){

        $key = explode(".", $keys);
        get($key, $account, $value);
      }

      // $account->save();

      return $account;

This returns a nice, updated object like :

+"user": +"name":"john" +"age":"50"

HOWEVER if I save that object, it doesn't save the updated values, only the old values. So changing the last two lines :

      $account->save();

      return $account;

results in

+"user": +"name":"jeff" +"age":"20" // these are the old values

So my question is - why does return $account give the correct, updated object, but $account->save(); return $account revert to the original values?

FYI: the following code works (but is too simple for my purposes) :

  $account = Account::find('account_id');
  // ^returns something like (object)['user'=>['name'=>'jeff','age'=>'20']];

  $account->user->name = "jim";
  $account->user->age = "100";

  $account->save();

  return $account;

+"user": +"name":"jim" +"age":"100"

The full dd output of $account BEFORE the save looks like this (this includes my updated values) :

        Account {#642
            +"id": "1234567890"
            +"object": "account"
            +"business_name": "my-business"
            +"business_primary_color": "#c2185b"
            +"business_url": "http://url.com"
            +"charges_enabled": true
            +"country": "GB"
            +"created": 1534491122
            +"debit_negative_balances": false
            +"decline_charge_on": StripeObject {#644
                +"avs_failure": false
                +"cvc_failure": false
            }
            +"default_currency": "gbp"
            +"details_submitted": false
            +"display_name": "display_name"
            +"email": "my_email@email.com"
            +"external_accounts": Collection {#643
                +"object": "list"
                +"data": []
                +"has_more": false
                +"total_count": 0
                +"url": "external_accounts_url"
            }
            +"legal_entity": StripeObject {#649
                +"additional_owners": []
                +"address": StripeObject {#655
                +"city": null
                +"country": "GB"
                +"line1": null
                +"line2": null
                +"postal_code": null
                +"state": null
                }
                +"business_name": null
                +"business_tax_id_provided": false
                +"dob": StripeObject {#656
                +"day": "01"
                +"month": "01"
                +"year": null
                }
                +"first_name": "john"
                +"last_name": "doe"
                +"personal_address": StripeObject {#659
                +"city": null
                +"country": "GB"
                +"line1": null
                +"line2": null
                +"postal_code": null
                +"state": null
                }
                +"type": "company"
                +"verification": StripeObject {#662
                +"details": null
                +"details_code": null
                +"document": null
                +"document_back": null
                +"status": "unverified"
                }
            }
            +"metadata": StripeObject {#652}
            +"payout_schedule": StripeObject {#665
                +"delay_days": 7
                +"interval": "daily"
            }
            +"payout_statement_descriptor": null
            +"payouts_enabled": false
            +"product_description": null
            +"statement_descriptor": "MY BUSINESS"
            +"support_email": null
            +"support_phone": null
            +"timezone": "Etc/UTC"
            +"tos_acceptance": StripeObject {#670
                +"date": 1535741539
                +"ip": "255.255.255.255"
                +"user_agent": null
            }
            +"type": "custom"
            +"verification": StripeObject {#673
                +"disabled_reason": null
                +"due_by": null
                +"fields_needed": array:6 [
                0 => "external_account"
                1 => "legal_entity.additional_owners"
                2 => "legal_entity.dob.day"
                3 => "legal_entity.dob.month"
                4 => "legal_entity.dob.year"
                5 => "legal_entity.last_name"
                ]
            }
            }
Leon
  • 1,851
  • 3
  • 21
  • 44
  • 2
    Can you post your full dd of $account right before the save? Probably you manipulate the wrong attriutes. Nevertheless I'm not fully sure why you chose such a fairly complex way to update the user of an account. As the account only seems to have 1 user you could simple query for the user at the very first instance and then update it directly from the request paramters like `$user->update($request->only(['name', 'age'])` – Frnak Sep 06 '18 at 12:14
  • 1
    check if this fields are fillable for model – ineersa Sep 06 '18 at 12:18
  • 1
    Account::create([$account]); may work if you unguarded all fields in the model? – Polaris Sep 06 '18 at 12:35
  • @FrankProvost - the first yellow box shows the dd of the object before the save, the second yellow box shows the dd after the save. It reverts to the original values! I have simplified the example, but the main points are : I have to set the values from the simple JSON provided ($to_update) as this is the point of the exercise, and I can only save using ->save() as this data from an API. I was wondering if there is something wrong around the line "get($key, $account, $value);" ...? – Leon Sep 06 '18 at 12:39
  • @ineersa the model does update those exact same fields if I do it in the way shown in the 3rd code example, so unguarded / fillable doesn't seem to be the issue – Leon Sep 06 '18 at 12:42
  • 1
    This is not the full dd of a eloquent model instance. A dd will output all the fields + methods of the model (e.g. https://laraveldaily.com/echoing-dd-vs-var_dump-vs-print_r/) – Frnak Sep 06 '18 at 12:44
  • @FrankProvost I have added the updated output, showing the type of object – Leon Sep 06 '18 at 12:53
  • 1
    oh well - I just realize: You are saving the account even though you are making changes to the user. You will probably need to use push instead of save - see this https://stackoverflow.com/questions/17035682/eloquent-push-and-save-difference – Frnak Sep 06 '18 at 12:56

2 Answers2

1

As you are updating inner entities but calling save on the outer entity it will only update the outer entity and then reload the current relations which have not been updated.

Therefore use $account->push() instead or just $account->user->save() in order to save the correct one.

Eloquent push() and save() difference

Frnak
  • 6,601
  • 5
  • 34
  • 67
  • That sounds about right! BUT I cannot use push() directly [call to undefined method push()]. Is there a way to "apply" my changes and THEN save, i wonder...? – Leon Sep 06 '18 at 13:00
  • $account->user->save(); also results in [call to undefined method save()] – Leon Sep 06 '18 at 13:02
  • if $accoun->user->save() results in undefined method then user does not return an eloquent model - what is the result of dd($account->user) – Frnak Sep 06 '18 at 13:10
  • It is a StripeObject (JSON) : StripeObject {#649 +"address": StripeObject {#655 +"city": null +"country": "GB" etc... – Leon Sep 06 '18 at 13:13
  • are you using laravel cashier ? I wasn't aware we are talking about a stripe integration where you actually want to update info on stripe side – Frnak Sep 06 '18 at 13:17
  • yes... sorry I was trying to keep it simple. I'm sure you are onto something in that I'm updating the inner entities and saving the outer entity... – Leon Sep 06 '18 at 13:25
1

You called save method to account object instead of user object in account to do it use $account->user->save(); or use it if your purpose is to update the same user details do as $account->user->update(['name'=>'jim','age'=>'100']);

Jayashree
  • 153
  • 1
  • 6