Laravel createMany error on nested relation - laravel

This is in relation to this question. I'm having this error:
TypeError
Illuminate\Database\Grammar::parameterize(): Argument #1 ($values) must be of type array, int given, called in /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Query/Grammars/Grammar.php on line 920
While inserting data using createMany. This is the form request data:
{
"name": "My Order",
"orders": [
{
"date": "2022-05-17",
"product_id": [1],
"price": 1
},
{
"start_date": "2022-05-18",
"product_id": [2],
"price": 2
}
]
}
This is the store method:
$order = auth()->user()->orders()->create($request->validated());
$order_subs = $order->subOrders()->createMany($request->orders);
$order_sub_items = $request->only('orders')['orders'];
foreach ($order_subs as $key => $value) {
$value->subOrderProducts()->createMany([$order_sub_items[$key]);
}
However, if the product_id is not an array, it will store properly. Sample form request data:
{
"name": "My Order",
"orders": [
{
"date": "2022-05-17",
"product_id": 1,
"price": 1
},
{
"start_date": "2022-05-18",
"product_id": 2,
"price": 2
}
]
}
How to fix this error?

Related

Filter Data with Pivot Table Laravel Eloquent

I want to filter users based on their subscription_status which s stored in a pivot table.
I have Three tables users , subscription_packages , subscription_package_user
$user=User::with(['studentDetails','subscriptionsSatus.courses'])
->withPagination($offset,$perPage)
->get()
->sortBy('first_name')->values();
this code return the response is
[
{
"id": 44,
"first_name": "Abcd Test",
"last_name": "Test lastname",
"student_details": null,
"subscriptions_satus": [
{
"id": 1,
"name": "Gold",
"price": 3000,
"user_id": "2"
"pivot": {
"user_id": 44,
"subscription_package_id": 1,
"subscription_status": "on_free_trial",
"expires_on": null,
"id": 9
},
"courses": [
{
"id": 18,
"title": "English Grammar for Class 3",
"price": 400,
"strikethrough_price": null,
"status": "draft",
"user_id": 2,
"image": "http://127.0.0.1:8000/courses/1615702915.png",
"description": null,
"pivot": {
"subscription_package_id": 1,
"course_id": 18,
}
}
]
}
]
}]
i want to return only users who having subscription_status =$filter.
$filter='acive'or 'on_free_trail'
my model is
public function subscriptionsSatus()
{
return $this->belongsToMany(SubscriptionPackage::class)->withTimestamps()->withPivot('subscription_status','expires_on','id');
}
I havetried
$filter=$request->input('filter')??"active";
$user=User::with(['studentDetails','subscriptionsStatus.courses'])
->whereHas('subscriptionsStatus', function($query) use($filter){
$query->wherePivot('subscription_status','=',$filter);
})
->withPagination($offset,$perPage)
->get()
->sortBy('first_name')->values();
But Got error Column not found 'pivot'
You need to use wherePivot along with the orWhere like below:
public function subscriptionsStatus()
{
return $this->belongsToMany(SubscriptionPackage::class)
->withTimestamps()
->withPivot('subscription_status','expires_on','id')
->wherePivot(function($q){
return $q->where('subscription_status','=','active')
->orWhere('subscription_status','=','on_free_trail');
});
}
Update
Or in your controller:
$user=User::with(['studentDetails','subscriptionsStatus.courses'])
->whereHas('subscriptionsStatus', function($query) use($filter){
$query->withPivot('subscription_status')
->wherePivot('subscription_status','=',$filter);
})
->withPagination($offset,$perPage)
->get()
->sortBy('first_name')->values();

change hasManyThrough() relation attribute name through accessor

I have 3 Models
Campaign PK(id)
CampaignMedium FK(campaign_id)
AccountReceivable FK(campaign_medium_id) (has an amount column)
Controller function:
public function all()
{
return Campaign::with(['customer', 'receivedPayments'])->get();
}
In Campaign Model relationships are defined as follows:
public function customer()
{
return $this->belongsTo(Customer::class);
}
public function accountReceivable()
{
return $this->hasManyThrough(AccountReceivable::class, CampaignMedium::class);
}
public function receivedPayments()
{
return $this->accountReceivable()
->selectRaw('sum(account_receivables.amount) as total')
->groupBy('campaign_id');
}
public function getReceivedPaymentsAttribute()
{
if (!array_key_exists('receivedPayments', $this->relations)) {
$this->load('receivedPayments');
}
$relation = $this->getRelation('receivedPayments')->first();
return ($relation) ? $relation->total : 0;
}
Final Output:
{
"data": [
{
"id": 8,
"name": "example",
"image": "campaign/90375849f6c3cc6b0e542a0e3e6295b890375849f6c3cc6b0e542a0e3e6295b8.jpeg",
"amount": 10,
"description": "saddsa",
"start_at": "2019-02-12 00:00:00",
"end_at": "2019-02-12 00:00:00",
"due_at": "2019-02-12 00:00:00",
"status": "active",
"customer": {
"id": 1,
"name": "test",
"email": "info#test.com",
"image": "customer/ec812116705ff3ae85298234fe6c4e97ec812116705ff3ae85298234fe6c4e97.jpeg",
"address": "sample address"
},
"received_payments": [
{
"total": "700",
"laravel_through_key": 8
}
]
},
{
"id": 9,
"name": "example",
"image": "campaign/fff9fadc92a809513dc28134379851aafff9fadc92a809513dc28134379851aa.jpeg",
"amount": 10,
"description": "saddsa",
"start_at": "2019-02-12 00:00:00",
"end_at": "2019-02-12 00:00:00",
"due_at": "2019-02-12 00:00:00",
"status": "active",
"customer": {
"id": 1,
"name": "test",
"email": "info#test.com",
"image": "customer/ec812116705ff3ae85298234fe6c4e97ec812116705ff3ae85298234fe6c4e97.jpeg",
"address": "sample address"
},
"received_payments": []
}
]
}
summary: trying to get the sum of AccountReceivable amount attribute, which is working fine but the getReceivedPaymentsAttribute() isn't working which needs to return the total value only. also can anyone please help me to explain why laravel_through_key is added with received_payments?
I've never tried to use an attribute modifier to modify a relation this way. You are overriding the expected result of receivedPayments(). You might be better off to define a separate attribute like so:
public function getSumReceivedPaymentsAttribute()
{
// ...your code...
}
Now you can access the attribute using $model->sum_received_payments or always preload it using:
// model.php
protected $appends = ['sum_received_payments'];

Laravel - Sort array by string value first and then date

I need help to sort array by couple of logics
[
{
"id": 1,
"status": "pending",
"date": "2019-08-01"
},
{
"id": 2,
"status": "delivered",
"date": "2019-08-01"
},
{
"id": 3,
"status": "pending",
"date": "2019-08-03"
},
{
"id": 4,
"status": "delivered",
"date": "2019-08-03"
},
{
"id": 5,
"status": "delivered",
"date": "2019-08-02"
}
]
what I want to do is to sort the array to status pending show first, and then sort it by the date descending
I already test to using sortByDesc from laravel collection but the array looks like sorted it by just 1 function
$collection = $collection->sortByDesc('date')->sortByDesc(function ($row, $key) {
if($row['status'] == 'pending'){
return 1;
}else{
return 0;
}
});
My expected final result look like this :
[
{
"id": 3,
"status": "pending",
"date": "2019-08-03"
},
{
"id": 1,
"status": "pending",
"date": "2019-08-01"
},
{
"id": 4,
"status": "delivered",
"date": "2019-08-03"
},
{
"id": 5,
"status": "delivered",
"date": "2019-08-02"
},
{
"id": 2,
"status": "delivered",
"date": "2019-08-01"
}
]
Few solutions:
Use a custom callback and return an array source
$products->sortBy(function($product) {
return [$product->param1, $product->param2];
});
This will sort a collection by param2 first, and then by param1
Use a custom callback and return a composite property to sort on source
$posts = $posts->sortBy(function($post) {
return sprintf('%-12s%s', $post->column1, $post->column2);
});
Sort your array by column 1, then split it up by column 2 and then merge it again (untested).
$collection->sortByDesc('date');
$collection->groupBy('status');
$collection->keyBy('status');
EDIT: Also I'm not sure if sortByDesc('date') works with date strings.
Your expected result can be achieved like this.
$sorted = $collection
->sortByDesc('date')
->sortBy(function ($item) {
return 'pending' == $item['status'] ? 0 : 1;
})
->values();
To be more precise:
$collection= $collection->sort(
function ($a, $b) {
if(($a->status== $b->status) &&($a->status== 'pending')){
return ($a->date >= $b->date) ? -1 : 1;
}elseif($a->status== 'pending' && ($a->status!= $b->status)){
return 1;
}else{
return ($a->date <= $b->date) ? 1 : -1;
}
}
);
$collection= $collection->sortByDesc('status');

how to return a json response based on database relationship

I'm quite new to Laravel,
Let's say I have 2 tables: main_sport and sub_sport. These two tables have a one-to-many relationship. 1 sport can have many sub sports.
I want the following json format
{
"success": "1",
"sports": [
"id": 1,
"name_of_categories": "Popular Sports",
"sub_sports:[
{
"id": 1,
"name_sub_sport_category": "Badminton"
},
{
"id": 2,
"name_sub_sport_category": "Football"
},
{
"id": 3,
"name_sub_sport_category": "Cricket"
},
]
]
"sports":[
"id": 2,
"name_of_categories": "Team Sports",
"sub_sports:[
{
"id": 4,
"name_sub_sport_category": "Badminton"
},
{
"id": 5,
"name_sub_sport_category": "Football"
},
]
]
}
I try for this function and i am getting following result
public function fetch()
{
$query= DB::table('details')
->join('table_sub_sport_category','table_sub_sport_category.id','=','details.sub_id')
->join('table_main_sport_category','table_main_sport_category.id','=','details.main_id')
->select(DB::raw('table_main_sport_category.id as id'),'table_main_sport_category.name_of_categories','table_sub_sport_category.name_sub_sport_category')
->get()
return response()->json(['success' =>'1','data'=>$query]);
}
{
"success": "1",
"data": [
{
"id": 1,
"name_of_categories": "Popular Sports",
"name_sub_sport_category": "Badminton"
},
{
"id": 1,
"name_of_categories": "Popular Sports",
"name_sub_sport_category": "Football"
},
{
"id": 1,
"name_of_categories": "Popular Sports",
"name_sub_sport_category": "Cricket"
},
]
}
Could you help me to get the desired result?
You should define sub_sport in the main sport Model like this:
class Sport extends Model{
public function sub_sport(){
return $this->hasMany(SubSport::class);
}
}
And in your controller you should write this:
$data = Sport::with('sub_sport')->get();
Use below code
$query= DB::table('details')
->join('table_sub_sport_category','table_sub_sport_category.id','=','details.sub_id')
->join('table_main_sport_category','table_main_sport_category.id','=','details.main_id')
->select(DB::raw('table_main_sport_category.id as id'),'table_main_sport_category.name_of_categories','table_sub_sport_category.name_sub_sport_category')
->get()
return Response::json([
'status' => 'error',
'sports' => $query
], 200);

How to join output of models in Laravel?

I have the following code:
$orders = OrderProduct::where(function ($query) use ($request) {
})->with('order_products')->orderBy('status', 'desc')->paginate(50)->toArray();
And order_products function is:
public function order_products()
{
return $this->hasMany("App\Order", "order_id", "order_id");
}
It gives me output result:
{
"user_id": "1",
"created_at": "2016-12-18 14:06:11",
"status": "2",
"note": "34535345",
"order_id": "2",
"address": "Kiev",
"courier_id": null,
"payment_type": "0",
"order_products": [
{
"id": 73,
"product_id": "1265",
"amount": "1"
},
{
"id": 74,
"product_id": "1266",
"amount": "1"
}
]
I need to join order_products with products_details, that to give title of product for each order like as:
"order_products": [
{
"id": 73,
"product_id": "1265",
"amount": "1",
"title": "Product name"
},
{
"id": 74,
"product_id": "1266",
"amount": "1",
"title": "Product name"
}
]
Instead this I get a new model output in response:
"products_details": [
{}, {}
]
How can I join two with models?
without joining, just using your first code:
in order_products, override the toArray() method.
function toArray() {
return [
id => $this->id,
product_id => $this->product_id,
amount => $this->amount,
title => $this->details->name
];
}
wich $this->details->name is the relation between order_products and products_details

Resources