Pagination with many to many relationships - laravel

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.

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');

How to increment quantity of laravel model without creating a copy

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();
}

Laravel Phpunit testing a request that take give output based on the request

I'm still new to laravel and I have a simple app and aSo I have a route that will store data based on the request in my controller.
public funtion store(Request $request, $id){
if ($request->has('work_experiences')) {
WorkExperience::create([
'user_id' => $user->id,
'position' => $request->work_experiences['position'],
'company' => $request->work_experiences['company'],
'start_date' => $request->work_experiences['start_date'],
'end_date' => $request->work_experiences['end_date'],
]);
}
if ($request->has('education')) {
Education::create([
'user_id' => $user->id,
'degree' => $request->education['degree'],
'university' => $request->education['university'],
'start_date' => $request->education['start_date'],
'end_date' => $request->education['end_date'],
]);
}
if ($request->has('job_interests')) {
JobInterest::create([
'user_id' => $user->id,
'job_position' => $request->job_interests['position'],
]);
}}
}
and in my test
public function test_authenticated_user_can_edit_education_profile()
{
$this->withoutExceptionHandling();
$user = User::factory()->create();
$this->actingAs($user);
$response = $this->post('/candidate' . '/' . $user->id, [
'user_id' => $user->id,
'position' => 'position',
'company' => 'company',
'start_date' => Carbon::now(),
'end_date' => Carbon::now(),
]);
$this->assertCount(1, WorkExperience::all());
}
when I run the test, the assertCount seems to fail because the response didn't work/insert the data to DB. where do I do wrong?
Well, the test is right.
It should fail because there is no work_experiences key in your request data.
The test request should look like:
$response = $this->post('/candidate' . '/' . $user->id, [
'work_experiences' => [
'user_id' => $user->id,
'position' => 'position',
'company' => 'company',
'start_date' => Carbon::now(),
'end_date' => Carbon::now(),
]
]);
So your data should go under a work_experiences key such that $request->has('work_experiences') returns true and executes the WorkExperience::create() statement.
Currently your endpoint only allows for a single "work experience" to be created. Seeing that you've named it work_experiences I assume you'd want to pass in an array/collection of "work experiences" - but that won't work with the current implementation; you'll have to loop over them instead - something like this:
if ($request->has('work_experiences')) {
foreach ($request->input('work_experiences') as $experience) {
WorkExperience::create([
'user_id' => $request->user()->id,
'position' => $experience['position'],
'company' => $experience['company'],
'start_date' => $experience['start_date'],
'end_date' => $experience['end_date'],
]);
}
}
And then your test should look something like this:
$response = $this->post('/candidate' . '/' . $user->id, [
'work_experiences' => [
[
'user_id' => $user->id,
'position' => 'position',
'company' => 'company',
'start_date' => Carbon::now(),
'end_date' => Carbon::now(),
],
// more "work experiences"
]
]);

update function is not working

I am trying to update my database for a user by this code , but it is not working . there is no change by the way!
public function update( Request $request)
{
$request->user()->tasks()->where('id', '=', $request->id)->update([
'name' => $request->title,
'body' => $request->body,
]);
return redirect('/request');
}
Try code and update database:
App\User::find($request->id)->tasks()->update([
'name' => $request->title,
'body' => $request->body
]);
return redirect('/request');
If you already know the id of the task, make it easy on yourself.
Task::find($request->id)->update([
'name' => $request->title,
'body' => $request->body
]);

How can I maintain foreign keys when seeding database with Faker?

Below is my model factory.
$factory->define(App\Business::class, function (Faker\Generator $faker){
return [
'name' => $faker->bs,
'slug' => $faker->slug,
'address' => $faker->streetAddress,
'phone_no' => $faker->phoneNumber,
'mobile_no' => $faker->phoneNumber,
'email' => $faker->companyEmail,
'website' => $faker->domainName,
'latitude' => $faker->latitude,
'longitude' => $faker->longitude,
'location' => $faker->city,
'business_days_from' => $faker->dayOfWeek,
'business_days_to' => $faker->dayOfWeek,
'description' => $faker->text,
'user_id' => $faker->factory(App\User::class),
];
});
and This my database seeder class
class DatabaseSeeder extends Seeder
{
public function run()
{
factory(App\Business::class, 300)->create();
}
}
But when I execute php artisan db:seed ...it does not work..
What should be the workaround here..any help would be appreciated..
you can get all ids using pluck (lists is depricated for laravel >= 5.2)
$userIds = User::all()->pluck('id')->toArray();
and get a random id for FK column:
'user_id' => $faker->randomElement($userIds)
You may also attach relationships to models using Closure attributes in your factory definitions.
'title' => $faker->title,
'content' => $faker->paragraph,
'user_id' => function () {
return factory(App\User::class)->create()->id;
}
I just found the workaround .. I replaced
'user_id' => $faker->factory(App\User::class),
with
'user_id' => $faker->randomElement(User::lists('id')->toArray()),
and that solves the problem for now..

Resources