mafortis
mafortis

Reputation: 7128

Updating json column along with other columns in laravel

I would like to know how do you update JSON column data while there is other columns need to be updated as well.

As I saw samples in laravel website it's something like this for json column

DB::table('users')
            ->where('id', 1)
            ->update(['options->enabled' => true]);

but what about other columns?

here is what I have currently:

public function update(Request $request, $id)
    {
        $order = Order::find($id);
        $this->validate($request, array(
            'payment_id'=>'nullable',
            'orderstatus_id' => 'required|numeric',
            'address_id' => 'required|numeric',
        ));

        $order = Order::where('id',$id)->first();
        $order->payment_id = $request->input('payment_id');
        $order->orderstatus_id = $request->input('orderstatus_id');
        $order->address_id = $request->input('address_id');

        $order->save();

        return redirect()->route('orders.index',
            $order->id)->with('success',
            'Order updated successfully.');
    }

and I have column named product_name which is Json type column and in it I have data such sample below, where I want to edit quantity of products inside that for example.

{"29": {"id": 29, "name": "effewf", "price": 24524, "quantity": 3, "attributes": [], "conditions": []}, "37": {"id": 37, "name": "test product", "price": 456346, "quantity": 2, "attributes": [], "conditions": []}}

As you can see in this order I have 2 products, one with quantity of 3 and another with quantity of 2.

Upvotes: 1

Views: 4264

Answers (2)

Leith
Leith

Reputation: 3299

The Laravel documentation has a section on arrays and JSON. The way to do this would be to add the $casts property to your Order model:

protected $casts = [
    'product_name' => 'array',
];

In your blade views and controllers, you should be able to then access $order->product_name directly - no more need for doing any json_decode() calls.

When updating specific values, in your 'edit order' view, you'll probably want to have your form inputs named something similar to make it easy to map your updates, i.e. something similar to:

@foreach($order->product_name as $data) 
    <label>Name:</label>
    <input
      type="text"
      name="product_name[{{ $data['id'] }}][name]"
      value="{{ $data['name'] }}"
    >

    <label>Price:</label>
    <input
      type="text"
      name="product_name[{{ $data['id'] }}][price]"
      value="{{ $data['price'] }}"
    >

    <label>Quantity:</label>
    <input
      type="number"
      name="product_name[{{ $data['id'] }}][quantity]"
      value="{{ $data['quantity'] }}"
    >
@endforeach

This means that in your controller's update() method, you can use the new values fetched from the request input like normal. If you want to strictly follow the format from the documentation, you should also set it in a new variable rather than setting it directly, i.e.

public function update(Request $request, $id)
{
    $order = Order::find($id);

    // ... other usual stuff

    // get original data
    $new_product_name = $order->product_name;

    // contains all the inputs from the form as an array
    $input_product_name = $request->input('product_name');
    // loop over the product array
    foreach ($input_product_name as $data_id => $data) {
        // loop over each input for the product in the view form
        foreach ($data as $key => $value) {
             // set the new value
             $new_product_name[$data_id][$key] = $value;
        }
    }
    // set the new data (should automatically serialize into JSON for storage)
    $order->product_name = $new_product_name;

    $order->save();
}

Upvotes: 3

Alexey Mezenin
Alexey Mezenin

Reputation: 163788

The best way to handle this is to create a model and a table for this data.

But if you want to use JSON, you can use the casts property in the model:

protected $casts = [
    'product_name' => 'array',
];

Then, you'll be able to work with options as with an array:

$order = Order::where('id',$id)->first();
$order->payment_id = $request->input('payment_id');
$order->orderstatus_id = $request->input('orderstatus_id');
$order->address_id = $request->input('address_id');
$order->product_name[$request->product_id]['quantity'] = $request->new_product_quantity);
$order->save();

If you don't want to use casts, you can convert data manually:

$order->product_name = json_encode(
    json_decode($order->product_name, true)[$request->some_product_id]['quantity'] = $request->new_quantity
);

Upvotes: 1

Related Questions