phpjsonlaravellaravel-6

Laravel: Update a nested json object


I have a column in my db for saving a users' settings. This is what the data structure looks like:

{"email":{"subscriptions":"{\"Foo\":true,\"Bar\":false}"}}

I am using a vue toggle to change the status of each property (true/false). Everything seems to be working, however when I save, I am wiping out the structure and saving the updated values like this:

{\"Foo\":true,\"Bar\":false}"}

php

$user = auth()->user();
$array = json_decode($user->preferences['email']['subscriptions'], true);
dd($array);

The above gets me:

array:2 [
    "Foo" => true
    "Bar" => false
]

So far so good...

$preferences = array_merge($array, $request->all());

dd($preferences);

Gets me:

array:2 [
    "Foo" => true
    "Bar" => true
]

Great - the values are now picking up the values passed in from the axios request. Next up; update the user's data:

$user->update(compact('preferences'));

Now my data looks like this:

{"Foo":true,"Bar":true}

The values are no-longer nested; I've wiped out email and subscriptions.

I've tried this:

$user->update([$user->preferences['email']['subscriptions'] => json_encode($preferences)]);

But it doesn't seem to save the data. How can I use the $preferences variable to update the data - and keep the data nested correctly?


Solution

  • You can create an array with the structure you want the resulting json to have. So, for this json:

    {
        "email":{
            "subscriptions":{
                    "Foo":true,
                    "Bar":false
            }
        }
    }
    

    you can create an array like this:

    [
        'email' => [
            'subscriptions' => [
                'Foo' => true,
                'Bar' => false
            ]
        ]
    ]
    

    an then, encode the entire structure:

    json_encode([ 
        'email' => [ 
            'subscriptions' => [
                'Foo' => true, 
                'Bar' => false
            ] 
        ] 
    ]);
    

    So, in your code, as you already have the nested array in the $preferences variable, I think this should work:

    $json_preferences = json_encode([ 
        'email' => [ 
            'subscriptions' => $preferences 
        ] 
    ]);
    

    Then you can update the user 'preferences' attribute (just for example):

    User::where('id', auth()->user()->id)->update(['preferences' => $json_preferences]);
    

    or

    $user = auth()->user();
    $user->preferences = $json_preferences;
    $user->save();