How to increment quantity of laravel model without creating a copy - laravel

I'm working on trying to create a cart system in laravel, where selecting an item on a menu will add it as a cart item. If the item already exists on the cart, it should just increase the quantity. I have this almost entirely working, except that the solution I've worked out makes it so that in the case of needing to increment the quantity, it will also recreate the cart item, so that there is one both with and without the incremented quantity. I've put a lot of mental energy into struggling with this, and was hoping someone might be able to help. Here is the relevant code, in the controller for creating the cart item.
$cartItems = Cartitem::all();
if($cartItems->isEmpty()){
$cartItem = new Cartitem([
'name' => $request->name,
'image_url' => $request->image_url,
'description' => $request->description,
'price' => $request->price,
'quantity' => 1
]);
$cartItem->save();
} else {
forEach($cartItems as $item){
if($request->name != $item->name){
$cartItem = new Cartitem([
'name' => $request->name,
'image_url' => $request->image_url,
'description' => $request->description,
'price' => $request->price,
'quantity' => 1
]);
$cartItem->save();
} else {
++$item->quantity;
$item->save();
}
}
}

$oldItem = Cartitem::where('name', $request->name)->first();
if ($oldItem) {
$oldItem->increment('quantity');
}
else {
$newItem = new Cartitem([
'name' => $request->name,
'image_url' => $request->image_url,
'description' => $request->description,
'price' => $request->price,
'quantity' => 1
]);
$newItem->save();
}

Related

How to use createMany

I am new to Laravel and I have many arrays that I want to insert in database with createMany() this is my code what I have done so far:
public function store(Request $request)
{
$request->validate([
'order_number' => 'required',
'client' => 'required',
'products' => 'required',
'amount' => 'required',
'description' => 'required',
]);
for($i = 0; $i < count($request->products); $i++)
{
$values[] = [
'order_number' => $request->order_number,
'client' => $request->client,
'products' => $request->products[$i],
'amount' => $request->amount[$i],
'description' => $request->description,
];
}
dd($values);
Order::createMany($values);
return redirect('/')->with('msg', 'Order Saved successfully!');
}
I saw on Internet and documentation examples like this:
createMany on createMany in Laravel?
Documentation
But I don't understand how it works.
This is how the values show up:
createMany() only works on relationships, what you should be using is insert()
So Order::insert($values);
You can read more on insert here: https://laravel.com/docs/9.x/queries#insert-statements
Because you want the timestamps to be updated then what you can do is this:
foreach($values as $value){
Order::create($value);
}
Since you are modifying the array before creating, you can always just add the updated_at and created_at
$values[] = [
'order_number' => $request->order_number,
'client' => $request->client,
'products' => $request->products[$i],
'amount' => $request->amount[$i],
'description' => $request->description,
'updated_at' => now(),
'created_at' => now(),
];
If you using Laravel 8+ try to use upsert
Order::upsert($values,'order_number');

Pagination with many to many relationships

I have products, categories and category_product (pivot) tables in my database.
I want to return the category info and products with pagination in the same response.
I know I can use Product::with('categories')->pagination(20),
but I don't want to attach the category to each product.
What is the proper way to get products belong to a specific category?
I have tried that but I can't get the pagination with that:
$category = Category::where('slug', $slug)->first();
$products = $category->products()->paginate(20);
return response()->json([
'category' => new CategoryResource($category),
'products' => ProductResource::collection($products),
]);
Here is my ProductResource
return [
'id' => $this->id,
'name' => $this->name,
'description' => $this->description,
'code' => $this->code,
'image' => $this->image,
'quantity' => $this->quantity,
'price' => $this->price,
'slug' => $this->slug,
'sort_order' => $this->sort_order,
'created_at' => $this->created_at,
'updated_at' => $this->updated_at,
'categories' => CategoryResource::collection($this->whenLoaded('categories')),
];
This looks like an issue with the way data is returned from the Collection.
The easiest solution is:
return response()->json([
'category' => new CategoryResource($category),
'products' => ProductResource::collection($products)->response()->getData(true),
]);
You can try as below
$category = Category::where('slug', $slug)
->with('products', function($query) {
$query->paginate(20);
})
->first();
return response()->json([
'category' => new CategoryResource($category),
'products' => ProductResource::collection($category->products),
]);
Hope this is what you are looking for.

How is it possible to retrieve the id of a Model right after it was created in the same controller function?

Let me show you my code, and place comments for you guys to better understand:
$homework = new Homework([ // I create Homework (And I indeed want to get the ID of the one that was just created).
'subject_id' => $request->subject_id,
'user_id' => auth()->user()->id,
'title' => $request->name,
'image' => $path,
'progress' => $request->progress,
'description' => $request->description,
'duedate' => $request->date
]);
$homework->save(); // I save it
$homeworkid = Homework::where('id', $id)->first(); // I try to retrieve it, but I'm not sure how to get it as I need to define `$id`.
$progress = newProgress([
'user_id' => auth()->user()->id,
'homework_id' => $homeworkid, // I need this for the relationship to work.
'title' => 'Initial Progress',
'description' => 'This progress is auto-generated when you create an assignment',
'username' => auth()->user()->name,
'progress' => $homeworkid->progress
]);
$progress->save(); // I save the progress
Well, as you saw, I'm trying to retrieve the ID of Homework right after it was created, but I'm not sure how to define $id in order to get it.
There is no need to instantiate a new model and saving it if your are not doing anything between instantiating and saving, you can use the create method instead:
$homework = Homework::create([
'subject_id' => $request->subject_id,
'user_id' => auth()->user()->id,
'title' => $request->name,
'image' => $path,
'progress' => $request->progress,
'description' => $request->description,
'duedate' => $request->date
]);
$homework->id; // get the id
After saving / creating the model you can access the id like you normally would:
$homework->id
What you then could do is setup the relationships between your models so you can do the following after creating a new homework:
$homework->newProgress()->create([
'user_id' => auth()->user()->id,
'title' => 'Initial Progress',
'description' => 'This progress is auto-generated when you create an assignment',
'username' => auth()->user()->name,
'progress' => $homework->progress
]);
This way you don't have to pass the homework id when creating a new newProgress, laravel will pass it automatically for you.
This is very simple for you. No need to complex it.
$homework->save(); // I save it
After this line just use only
$progress = newProgress([
'user_id' => auth()->user()->id,
'homework_id' => $homework->id, // I need this for the relationship to work.
'title' => 'Initial Progress',
'description' => 'This progress is auto-generated when you create an assignment',
'username' => auth()->user()->name,
'progress' => $homework->progress
]);
You don't no need this line of code
$homeworkid = Homework::where('id', $id)->first(); // I try to retrieve it, but I'm not sure how to get it as I need to define `$id`.
$data = $homework->save();
Get the ID this way: $data->id

Using isDirty in Laravel

I'm using the isDirty() method in my controller to check if any field is changed. Then I am saving the old data of a field and the new data in a table. The code is working fine; however, how can I optimize this code?
By using the below code, I will have to write each field name again and again. If request->all() has 20 fields, but I want to check six fields if they are modified, how can I pass only 6 fields in the below code, without repeating?
Controller
if ($teacher->isDirty('field1')) {
$new_data = $teacher->field1;
$old_data = $teacher->getOriginal('field1');
DB::table('teacher_logs')->insert(
[
'user_id' => $user->id,
'teacher_id' => $teacher->id,
'old_value' => $old_data,
'new_value' => $new_data,
'column_changed' => "First Name",
]);
}
You can set a list of what fields you want to be checking for then you can loop through the dirty fields and build your insert records.
use Illuminate\Support\Arr;
...
$fields = [
'field1' => 'First Name',
'field2' => '...',
...
];
$dirtied = Arr::only($teacher->getDirty(), array_keys($fields));
$inserts = [];
foreach ($dirtied as $key => $value) {
$inserts[] = [
'user_id' => $user->id,
'teacher_id' => $teacher->id,
'old_value' => $teacher->getOriginal($key),
'new_value' => $value,
'column_changed' => $fields[$key];
];
}
DB::table(...)->insert($inserts);
i tried following code after getting idea by lagbox in comments, and i have found solution to my problem.
$dirty = $teacher->getDirty('field1','field2','field3');
foreach ($dirty as $field => $newdata)
{
$olddata = $teacher->getOriginal($field);
if ($olddata != $newdata)
{
DB::table('teacher_logs')->insert(
['user_id' => $user->id,
'teacher_id' => $teacher->id,
'old_value' => $olddata,
'new_value' => $newdata,
'column_changed' => "changed",
]);
}
}

Getting data into array

I'm working on some e-commerce website based on merchant. There is problem comping in submitting order. the problem is when i'm selecting same merchant that time order will be stored successfully, but when i'm selecting multiple product from different merchant that time my function through error of Undefined offset:1. Here is my function.
public function post_order(){
$data = Input::all();
$count = count($data['invoice_no']);
$order = array();
for($i=0; $i<$count; $i++){
if(!empty($data['invoice_no'][$i])){
array_push($order, array(
'order_no' => $data['order_no'][$i],
'invoice_prefix' => $data['invoice_prefix'][$i],
'invoice_no' => $data['invoice_no'][$i],
'merchant_id' => $data['merchant_id'][$i],
'customer_id' => $data['customer_id'][$i],
'buytokri_order' => $data['order_name'][$i],
'name' => $data['name'][$i],
'pincode' => $data['pincode'][$i],
'address' => $data['address'][$i],
'landmark' => $data['landmark'][$i],
'city' => $data['city'][$i],
'state' => $data['state'][$i],
'country' => $data['country'][$i],
'mobile' => $data['mobile'][$i],
'subtotal' => $data['selling_price'][$i],
'payment_type' => $data['payment_type'][$i],
'txn_id' => $data['txn'][$i],
'shipping' => $data['shipping'][$i],
'total' => $data['subtotal'][$i]
));
}
}
Order::insert($order);
$var = $data['order_no'];
foreach ($var as $vars) {
$id = DB::table('ads_order')->where('order_no', $vars)->get();
}
$count = count($data['invoice_no']);
$orderhistory = array();
for($i=0; $i<=$count; $i++){
if(!empty($data['invoice_no'][$i])){
array_push($orderhistory, array(
'order_id' => $id[$i]->id,
'merchant_id' => $data['merchant_id'][$i],
'customer_id' => $data['customer_id'][$i],
'order_status' => $data['order_status'][$i],
'comment' => $data['comment'][$i],
'notify' => $data['notify'][$i],
'default' => $data['default'][$i],
'status' => $data['status'][$i]
));
}
}
Orderhistory::insert($orderhistory);
return Redirect::intended('/ordersuccess');
}

Resources