refactor: update price handling in CuttingResultPriceResolver and HomepageService for improved data structure and consistency
Some checks are pending
linter / quality (push) Waiting to run
tests / ci (8.3) (push) Waiting to run
tests / ci (8.4) (push) Waiting to run
tests / ci (8.5) (push) Waiting to run

This commit is contained in:
Yoga Pangestu 2026-07-06 15:47:46 +07:00
parent 38d6f3a22b
commit bd51f9abe0
2 changed files with 58 additions and 26 deletions

View File

@ -53,7 +53,11 @@ public function latestPricesForVariant(int $productVariantId): array
$price = $this->resolve($productVariantId, $priceType);
if ($price !== null) {
$prices[] = $price;
$prices[] = [
'price_type' => $price->price_type->value,
'price' => (int) $price->price,
'price_formatted' => $price->price_formatted,
];
}
}
@ -63,9 +67,9 @@ public function latestPricesForVariant(int $productVariantId): array
public function latestPricesForVariants(array $variantIds): Collection
{
return $this->cacheRemember('prices:variants:'.md5(implode(',', $variantIds)), 900, function () use ($variantIds) {
$cached = $this->cacheRemember('prices:variants:'.md5(implode(',', $variantIds)), 900, function () use ($variantIds) {
if (empty($variantIds)) {
return collect();
return [];
}
$cuttingPrices = CuttingResultPrice::query()
@ -83,24 +87,34 @@ public function latestPricesForVariants(array $variantIds): Collection
->get()
->groupBy(fn (ProductPrice $price) => $price->variant_id.'-'.$price->type->value);
$results = collect();
// Store only plain arrays — never Eloquent models — to avoid
// __PHP_Incomplete_Class when Redis deserializes across requests.
$results = [];
foreach ($variantIds as $variantId) {
foreach (PriceType::cases() as $priceType) {
$key = $variantId.'-'.$priceType->value;
if ($cuttingPrices->has($key)) {
$results->push($cuttingPrices->get($key));
$cp = $cuttingPrices->get($key);
$results[$variantId][] = [
'price_type' => $cp->price_type->value,
'price' => (int) $cp->price,
'price_formatted' => $cp->price_formatted,
];
} elseif ($productPrices->has($key)) {
$pp = $productPrices->get($key)->first();
$cp = new CuttingResultPrice;
$cp->product_variant_id = $variantId;
$cp->price_type = $priceType;
$cp->price = $pp->price;
$results->push($cp);
$results[$variantId][] = [
'price_type' => $priceType->value,
'price' => (int) $pp->price,
'price_formatted' => 'Rp '.number_format((int) $pp->price, 0, ',', '.'),
];
}
}
}
return $results->groupBy('product_variant_id');
return $results;
});
// Rebuild as a Collection keyed by variant ID (matching original contract)
return collect(is_array($cached) ? $cached : [])->map(fn ($prices) => collect($prices));
}
}

View File

@ -2,6 +2,7 @@
namespace App\Services\System;
use App\Enums\PriceType;
use App\Models\Category;
use App\Models\Product;
use App\Models\SystemConfiguration;
@ -51,7 +52,7 @@ public function pageData(): array
});
}
private function getProducts()
private function getProducts(): array
{
$products = Product::getActiveWithVariantsAndCategories();
@ -61,22 +62,39 @@ private function getProducts()
$allPricesByVariant = $this->cuttingResultPriceResolver->latestPricesForVariants($allVariantIds);
// Convert entirely to plain arrays — never store Eloquent models in
// Redis, as PHP serialize/unserialize can produce __PHP_Incomplete_Class
// and json_encode may produce {} instead of [] for keyed collections.
return $products->map(function ($product) use ($allPricesByVariant) {
$product->variants->each(function ($variant) use ($allPricesByVariant) {
$variant->setAttribute('images', MediaPresenter::collection($variant, 'images'));
$variants = $product->variants->map(function ($variant) use ($allPricesByVariant) {
$variantPrices = $allPricesByVariant->get($variant->id, collect());
$variant->setAttribute(
'prices',
$variantPrices->map(fn ($price) => [
'type' => $price->price_type->value,
'type_label' => $price->price_type->label(),
'price' => (int) $price->price,
'price_formatted' => $price->price_formatted,
])->values()->all(),
);
});
return $product;
})->values();
return [
'id' => $variant->id,
'name' => $variant->name,
'stock' => $variant->stock,
'images' => MediaPresenter::collection($variant, 'images'),
'prices' => $variantPrices->map(fn ($price) => [
'type' => $price['price_type'],
'type_label' => PriceType::from($price['price_type'])->label(),
'price' => $price['price'],
'price_formatted' => $price['price_formatted'],
])->values()->all(),
];
})->values()->all();
return [
'id' => $product->id,
'name' => $product->name,
'description' => $product->description,
'slug' => $product->slug ?? null,
'categories' => $product->categories->map(fn ($cat) => [
'id' => $cat->id,
'name' => $cat->name,
'slug' => $cat->slug,
])->values()->all(),
'variants' => $variants,
];
})->values()->all();
}
}