This is the simplified version of table in my project.
Table items
| id | name |
| ---- | ------ |
| 1 | Apple |
| 2 | Orange |
| 3 | Mango |
Table pricing_groups
| id | name | deleted |
| ---- | ------- | ------- |
| 1 | Reguler | 0 |
| 2 | VIP | 0 |
| 3 | VVIP | 1 |
Table price_lists
| id | item_id | group_id | price | date |
| ---- | ------- | -------- | ----- | ---------- |
| 1 | 1 | 1 | 100 | 2019-01-20 |
| 2 | 1 | 2 | 120 | 2019-01-20 |
| 3 | 1 | 1 | 110 | 2019-02-01 |
| 4 | 2 | 1 | 80 | 2019-01-31 |
| 5 | 2 | 3 | 120 | 2019-01-10 |
Items and PricingGroups are many to many relationship and the pivot table is price_lists
.
Models: Item
, PricingGroup
, PriceList
So I want to have an eloquent relation called prices
in model Item to get the price for each PricingGroups.
class Item extends Model {
public function prices() {
// what should I put here??
}
}
The output I want is like this:
"items": [
{
"id": 1,
"name": "Apple",
"prices": [
{
"id": 1,
"name": "Reguler",
"price": 110
},
{
"id": 2,
"name": "VIP",
"price": 120
}
]
},
{
"id": 2,
"name": "Orange",
"prices": [
{
"id": 1,
"name": "Reguler",
"price": 80
},
{
"id": 2,
"name": "VIP",
"price": 0
}
]
},
{
"id": 3,
"name": "Mango",
"prices": [
{
"id": 1,
"name": "Reguler",
"price": 0
},
{
"id": 2,
"name": "VIP",
"price": 0
}
]
}
]
Note:
price=0
if there is no record of the item in price_lists
. See Orange-VIP and Mango case. Is this possible?
You should have a look into the mutators for your object properties.
https://laravel.com/docs/5.7/eloquent-mutators
This way you can add an attribute named "Prices" and return them dynamical.
Get the newest price. See Apple-Reguler case.
You can customize your relationship query So you achieve data you want and also it's still a relationship (not like accessors):
//Item.php
public function prices()
{
// normal belongsToMany
return $this->belongsToMany(PricingGroup::class, 'price_lists', 'item_id', 'group_id')
// customize select statement
->selectRaw('pricing_groups.*, price_lists.price')
// order by item id
->orderByRaw('price_lists.price');
}
Output will be
select pricing_group.*, price_lists.price from "pricing_groups" inner join "price_lists" on "pricing_groups"."id" = "pric
e_lists"."group_id" where "price_lists"."item_id" = ? order by price_lists.price
Show active pricing groups with price=0 if there is no record of the item in price_lists. See Orange-VIP and Mango case.
I don't think it's even possible using eagerLoading.
You can do it this way:
/*define the relationship like this*/
public function price_groups(){
return $this->belongsToMany(PricingGroup::class,'price_lists','item_id','group_id')->withPivot(['price','date']);
}
public static function prices($date = null){
/*get all available pricing groups*/
$availablePricingGroups = PricingGroup::where('deleted',false)
->select('id','name')
->get()
->toArray();
/*eager load*/
$itemPriceGroups = self::with('price_groups')
->get()
->map(function($item) use ($date,$availablePricingGroups){
/*sort by date, latest date on top*/
$priceGroups = $item->price_groups->sortByDESC(
function($priceGroup){
return $priceGroup->pivot->date;
})
->filter(function($priceGroup) use ($date){
/*filter out deleted and greater than $date price group*/
return $priceGroup->deleted == false && $priceGroup->pivot->date <= ($date??date('Y-m-d'));
})->groupBy('id')
->map(function($priceGroup){
/*latest price group is still on the top*/
/*group them together then select the first price group*/
return $priceGroup->first();
})->toArray();
/*iterate through $availablePricingGroups and set its price*/
foreach($availablePricingGroups as $availablePricingGroup){
$price = 0;
foreach($priceGroups as $priceGroup){
if($priceGroup['id'] == $availablePricingGroup['id']){
$price = $priceGroup['pivot']['price'];
break;
}
}
$endResultPriceGroups[] = $availablePricingGroup + ['price' => $price];
}
return [
'id' => $item->id,
'name' => $item->name,
'prices' => $endResultPriceGroups,
];
});
return $itemPriceGroups;
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.