I am adding order to database. It works like this: When ordering is clicked, the order is created in the Order table, at the same time the product items are also added to the OrderItem table, via the order_id foreign key. But I don't know how to get the order_id, because it is added at the same time, and the Order id is increments.
public function save(array $data, int $id = null){
$idCurrent = Auth::id();
$orderItems = $data['orderItems'];
//add to Order
Order::updateOrCreate(
[
'id' => $id
],
[
'user_id' => $idCurrent,
'shipping_fee' => $data['shipping_fee'],
'total' => $data['total'],
'payment' => $data['payment'],
'status_id' => 1,
]
);
//add to OrderItem
foreach($orderItems as $item){
OrderItem::Create([
'order_id' => 222, //=> ?????????????
'product_id' => $item -> product_id,
'quantity' => $item->quantity,
]);
}
return true;
}
$order = Order::updateOrCreate(
[
'id' => $id
],
[
'user_id' => $idCurrent,
'shipping_fee' => $data['shipping_fee'],
'total' => $data['total'],
'payment' => $data['payment'],
'status_id' => 1,
]
);
//add to OrderItem
foreach($orderItems as $item){
OrderItem::Create([
'order_id' =>$order->id
'product_id' => $item -> product_id,
'quantity' => $item->quantity,
]);
}
return true;
Avoid multiple call to databases.
When you create order with
$order = Order::updateOrCreate(
[
'id' => $id
],
[
'user_id' => $idCurrent,
'shipping_fee' => $data['shipping_fee'],
'total' => $data['total'],
'payment' => $data['payment'],
'status_id' => 1,
]
);
next you should is to send just one request to database with
// create batch array
$insertOrderItems = [];
foreach($orderItems as $item){
$insertOrderItems[] = [
'product_id' => $item->product_id,
'quantity' => $item->quantity,
];
}
// insert all at once in batch mode making just one call to database
$order->orderItems()->create($insertOrderItems);
Presuming you have sorted relations in Order and OrderItem models.
Related
Hello i have this code in Laravel that updates existing many-to-many relationship tables so when i use the sync command the values update wrong, this is the code:
public function update(Request $request, $id)
{
$order = Order::where('id', $id)->first();
$request->validate([
'order_number' => 'required',
'client_id' => 'required',
'description' => 'required',
'productOrder' => 'required',
'productOrder.*.product_id' => 'required|distinct|exists:products,id',
'productOrder.*.amount' => 'required|numeric|min:1',
]);
$order->update($request->all());
foreach ($request->productOrder as $product) {
$values[] = [
'order_id' => $order->id,
'product_id' => $product['product_id'],
'amount' => $product['amount'],
];
$amount = Product::find($product['product_id']);
$totalValue = $product['amount'] + $amount->amount;
$amount->update(['amount' => $totalValue]);
}
$order->products()->sync($values); //the problem is here
$orders = Order::all();
$orders->load('client', 'products');
return view('orders/index', compact('orders'));
}
If i have 2 values like:
Product1 -> amount: 250
Product2 -> 100
And i updatet these existing values to
Product1 -> amount: 350
Product2 -> 200
The result will be
Product2 -> 200
Product2 -> 200
If i make this line of code dd($order->products()->sync($values)); i get this result
If i add a new product with the existing ones i get this result
From what im understanding the first result is replaced with the second one or removed, why does this happen?
So, you have this code:
public function update(Request $request, $id)
{
$order = Order::where('id', $id)->first();
$request->validate([
'order_number' => 'required',
'client_id' => 'required',
'description' => 'required',
'productOrder' => 'required',
'productOrder.*.product_id' => 'required|distinct|exists:products,id',
'productOrder.*.amount' => 'required|numeric|min:1',
]);
$order->update($request->all());
foreach ($request->productOrder as $product) {
$values[] = [
'order_id' => $order->id,
'product_id' => $product['product_id'],
'amount' => $product['amount'],
];
$amount = Product::find($product['product_id']);
$totalValue = $product['amount'] + $amount->amount;
$amount->update(['amount' => $totalValue]);
}
$order->products()->sync($values); //the problem is here
$orders = Order::all();
$orders->load('client', 'products');
return view('orders/index', compact('orders'));
}
The issue with it, is that sync is getting wrong IDs, because $values has numeric autoincrementals IDs: 0, 1, 2, etc.
What you need to pass to the sync is either an array of IDs [1, 2, 3], or an array of arrays (when you want to update columns related to that ID, for example: [1 => ['amount' => 100], 2, 3].
Let me try to modify your code to help you.
Let's assume you orders table and products table. You also have a pivot table called order_product table, so you store the relation in there. This order_product table has:
id
order_id
product_id
amount
So, your code should be like this:
public function update(Request $request, $id)
{
$validated = $request->validate([
'order_number' => 'required',
'client_id' => 'required',
'description' => 'required',
'productOrder' => 'required',
'productOrder.*.product_id' => 'required|distinct|exists:products,id',
'productOrder.*.amount' => 'required|numeric|min:1',
]);
$order = Order::find($id); // I would change this to use implicit binding
$order->update($validated); // Don't use $request->all(), you are using unvalidated values
foreach ($request->productOrder as $product) {
$values[$product['product_id']] = [
'amount' => $product['amount']
];
$amount = Product::find($product['product_id']);
$totalValue = $product['amount'] + $amount->amount;
$amount->update(['amount' => $totalValue]);
}
$order->products()->sync($values); // Now it will work
$orders = Order::all();
$orders->load('client', 'products');
return view('orders/index', compact('orders'));
}
I have JSON file and have data in it. I want to import all data in the database through DB seeders. I am getting an error Trying to get property name of non-object. I have multiple data how I can insert in the database?
public function run()
{
$json = File::get("public/kmz/WASASubdivisions.geojson");
$data = json_decode($json);
// dd($data);
foreach ($data as $obj){
Regions::create(array(
'name' => $obj[0]->Name,
'description' => $obj[0]->description,
'altitudeMode' => $obj[0]->altitudeMode,
'Town' => $obj[0]->Town,
'AC' => $obj[0]->AC,
'No_of_TW' => $obj[0]->No_of_TW,
'No' => $obj[0]->No,
'DC'=> $obj[0]->DC,
'HH_2017' => $obj[0]->HH_2017,
'FID' => $obj[0]->FID,
'Area_ha' => $obj[0]->Area_ha,
'Field_1' => $obj[0]->Field_1,
'Pop_Dens' => $obj[0]->Pop_Dens,
'Id' => $obj[0]->Id,
'Pop_2017' => $obj[0]->Pop_2017,
'Area_Sq'=> $obj[0]->Area_Sq,
));
}
}
Sample Json Format
31 => {#837
+"type": "Feature"
+"properties": {#838
+"Name": "Gujjar Pura"
+"description": null
+"altitudeMode": "clampToGround"
+"Town": "Shalimar Town"
+"AC": "31"
+"No_of_TW": "11"
+"No": "13"
+"DC": "38"
+"HH_2017": "30478"
+"FID": "31"
+"Area_ha": "648.327"
+"Field_1": "Gujjar Pura"
+"Pop_Dens": "54063.141167"
+"Id": "0"
+"Pop_2017": "196619"
+"Area_Sq": "3.63684"
}
+"geometry": {#839
+"type": "MultiPolygon"
+"coordinates": array:1 [
0 => array:1 [
0 => array:169 [ …169]
]
]
}
}
Let's support I have a model Post and I want to save additional data in JSON format in the posts table. In that case, we can use property $casts in Laravel. Which will cast our field value to whatever we gave.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
protected $table='posts';
protected $fillable = ['user_id', 'title', 'short_description', 'description', 'status', 'json_data'];
/**
* The attributes that should be cast to native types.
*
* #var array
*/
protected $casts = [
'json_data' => 'array',
];
}
Now we want to save data something like this
$data = [
'user_id' => 1,
'title' => 'abc',
'short_description' => 'test',
'description' => 'test',
'status' => true,
'json_data' => [
'additional_info' => '',
'post_image' => '',
...
],
];
$item = new Post;
$item->fill($data)->save();
This will save your json_data array values to JSON in the database. But when you will get data from the database it will convert that to array automatically.
For reference read this
since i am not a big fan of processing the json as a object
So the json_decode will accept the second arg so
$json = File::get("public/kmz/WASASubdivisions.geojson");
$data = json_decode($json,true);
dd($data);
foreach ($data as $obj)
{
Regions::create(array(
'name' => $obj['Name'],
'description' => $obj['description'],
'altitudeMode' => $obj['altitudeMode'],
'Town' => $obj['Town'],
'AC' => $obj['AC'],
'No_of_TW' => $obj['No_of_TW'],
'No' => $obj['No'],
'DC'=> $obj['DC'],
'HH_2017' => $obj['HH_2017'],
'FID' => $obj['FID'],
'Area_ha' => $obj['Area_ha'],
'Field_1' => $obj['Field_1'],
'Pop_Dens' => $obj['Pop_Dens'],
'Id' => $obj['Id'],
'Pop_2017' => $obj['Pop_2017'],
'Area_Sq'=> $obj['Area_Sq'],
));
}
Can You Post the dd() result and fileds sets of the table
public function run()
{
$json = File::get("public/kmz/WASASubdivisions.geojson");
$data = json_decode($json);
dd($data);
foreach ($data as $obj){
Regions::create(array(
'name' => $obj->Name,
'description' => $obj->description,
'altitudeMode' => $obj->altitudeMode,
'Town' => $obj->Town,
'AC' => $obj->AC,
'No_of_TW' => $obj->No_of_TW,
'No' => $obj->No,
'DC'=> $obj->DC,
'HH_2017' => $obj->HH_2017,
'FID' => $obj->FID,
'Area_ha' => $obj->Area_ha,
'Field_1' => $obj->Field_1,
'Pop_Dens' => $obj->Pop_Dens,
'Id' => $obj->Id,
'Pop_2017' => $obj->Pop_2017,
'Area_Sq'=> $obj->Area_Sq,
));
}
}
The attributes are under the properties key, but you're referencing them from the root of the object. e.g. $obj[0]->Name should be $obj[0]->properties->Name, etc.
I am working with a purchase ordering app. I have two tables, the orders table, and order_items. I would like to order_items to grab the id of orders which is in a single action. apology if I wasn't able to explain it clearly. here's my store function.
public function store(Request $request) {
$orders = $request->only(
'user_id',
'status_id',
'currency_id',
'company_id',
'purchase_no',
'notes',
'delivery_date',
'publish'
);
$orders['grandtotal'] = (float) str_replace(',', '', $request->grandtotal);
$orders = Orders::create($orders);
$input = $request->all();
for($i=0; $i<= count($input['quantity']); $i++) {
if(empty($input['quantity'][$i]) || !is_numeric($input['quantity'][$i])) continue;
$items = [
'order_id' => $input['order_id'][$i],
'product_id' => $input['product_id'][$i],
'product_code' => $input['product_code'][$i],
'product_name' => $input['product_name'][$i],
'cost' => $input['cost'][$i],
'quantity' => intval($input['quantity'][$i]),
'total_cost' => (float) str_replace(',', '', $input['total_cost'][$i]),
];
Orderitems::create($items);
}
return redirect()->route('orders.index');
}
what should I do to achieve this process? thank you so much in advance!
Just replace $input['order_id'][$i] with $orders->id, It might help you.
$items = [
'order_id' => $orders->id,
'product_id' => $input['product_id'][$i],
'product_code' => $input['product_code'][$i],
'product_name' => $input['product_name'][$i],
'cost' => $input['cost'][$i],
'quantity' => intval($input['quantity'][$i]),
'total_cost' => (float) str_replace(',', '', $input['total_cost'][$i]),
];
I have cart on my web store and so far everything works perfectly but I said when I try decrement the product quantity to product, the all product in my database will decrement Not just products in cart.
Here is my ordercontroller :
public function postOrder(Request $request) {
$validator = Validator::make($request->all(), [
'first_name' => 'required|max:30|min:2',
'last_name' => 'required|max:30|min:2',
'address' => 'required|max:50|min:4',
'address_2' => 'max:50|min:4',
'city' => 'required|max:50|min:3',
'state' => 'required|',
'zip' => 'required|max:11|min:4',
'full_name' => 'required|max:30|min:2',
]);
if ($validator->fails()) {
return redirect('/checkout')
->withErrors($validator)
->withInput();
}
$first_name = Input::get('first_name');
$last_name = Input::get('last_name');
$address = Input::get('address');
$address_2 = Input::get('address_2');
$city = Input::get('city');
$state = Input::get('state');
$zip = Input::get('zip');
$full_name = Input::get('full_name');
$user_id = Auth::user()->id;
$cart_products = Cart::with('products')->where('user_id', '=', $user_id)->get();
$cart_total = Cart::with('products')->where('user_id', '=', $user_id)->sum('total')
$charge_amount = number_format($cart_total, 2) * 100;
$order = Order::create (
array(
'user_id' => $user_id,
'first_name' => $first_name,
'last_name' => $last_name,
'address' => $address,
'address_2' => $address_2,
'city' => $city,
'state' => $state,
'zip' => $zip,
'total' => $cart_total,
'full_name' => $full_name,
));
foreach ($cart_products as $order_products) {
$order->orderItems()->attach($order_products->product_id, array(
'qty' => $order_products->qty,
'price' => $order_products->products->price,
'reduced_price' => $order_products->products->reduced_price,
'total' => $order_products->products->price * $order_products->qty,
'total_reduced' => $order_products->products->reduced_price * $order_products->qty,
));
}
// in the fact all product will decrement Not just products in cart
\DB::table('products')->decrement('product_qty', $order_products->qty);
Cart::where('user_id', '=', $user_id)->delete();
flash()->success('Success', 'Your order was processed successfully.');
return redirect()->route('cart');
}
I use program \DB::table('products')->decrement('product_qty', $order_products->qty);; for the decrement but in the fact all product will decrement Not just products in cart
The decrement you are using updates all records, as you have observed because you didn't constrain it to a specific record. You want to do this in your loop:
DB::table('products')
->where('id', '=', $order_products->product_id)
->decrement('product_qty', $order_products->qty);
I have 4 extra attributes ('product_id', 'quantity', 'discount_percent', 'discount_amount') in my pivot table, but my values for these are always 0 when I store, while the rest is populated properly. Any ideas?
Invoice model
public function productversion()
{
return $this->belongsToMany('App\Productversion')->withPivot('product_id', 'quantity', 'discount_percent', 'discount_amount')->withTimestamps();
}
Productversion model
public function invoice()
{
return $this->belongsToMany('App\Invoice')->withPivot('product_id', 'quantity', 'discount_percent', 'discount_amount')->withTimestamps();
}
Controller (store)
$invoice->productversion()->attach($productversionid, ['product_id' => $productid], ['quantity' => $qty], ['discount_percent' => $discountprc], ['discount_amount' => $discountamt]);
Just one array will do:
$invoice->productversion()->attach($productversionid, [
'product_id' => $productid,
'quantity' => $qty,
'discount_percent' => $discountprc,
'discount_amount' => $discountamt
]);
In addition to #jeff's method, you can attach or sync multiple elements with pivot attributes providing a multidimensional array that has ids as keys.
$attach_data[$productversionid] = [
'product_id' => $productid,
'quantity' => $qty,
'discount_percent' => $discountprc,
'discount_amount' => $discountamt
];
Then you can $invoice->productversion()->attach($attach_data).
Substantially you can pass an array like
[
'relation_id' => [
// pivot data
],
'relation_id' => [
// pivot data
],
// ...
]