When evolving a Laravel application to support multiple pricing variants (like product tiers, regions, or customer types), here's a clean refactoring pattern that maintains backward compatibility while enabling complex pricing structures.
## The Challenge
You start with single-variant pricing:
“`php
public function fetchPricing($inventory)
{
$config = $inventory->api_config_standard;
$response = $this->client->getPricing($config[“product_id”]);
return $response->prices;
}
“`
Now you need to support premium, standard, and budget variants – each with different pricing.
## The Solution: Reference Extraction Pattern
Create a helper method that extracts all configured variants:
“`php
private function getVariants($inventory): Collection
{
return collect($inventory->getAllApiConfigs())
->mapWithKeys(fn($config) => [$this->getVariantKey($config) => $config]);
}
private function getVariantKey($config): string
{
return $config[“tier”] . “_” . $config[“region”];
}
“`
Then refactor your pricing method to loop through all variants:
“`php
public function fetchAdvancedPricing($inventory): Collection
{
$allPricing = collect();
$variants = $this->getVariants($inventory);
foreach ($variants as $variantKey => $config) {
$response = $this->client->getPricing($config[“product_id”]);
foreach ($response->dates as $date) {
$allPricing->push(new DatePrice(
prices: collect([new VariantPrice($config, $date->price)]),
date: $date->value
));
}
}
// Group dates with same pricing across all variants
return $allPricing->groupBy(fn($dp) => $dp->date)
->map(fn($group) => new DatePrice(
prices: $group->flatMap(fn($dp) => $dp->prices),
date: $group->first()->date
));
}
“`
## Default Pricing Fallback
Some dates might not have pricing for certain variants. Create a fallback:
“`php
private function getDefaultPrices($variants, $allPricing): Collection
{
$prices = $allPricing->flatMap(fn($dp) => $dp->prices);
return $variants->map(function($config) use ($prices) {
return $prices
->where(“variant_key”, $this->getVariantKey($config))
->sortBy(“price”)
->first() ?? new VariantPrice($config, null);
});
}
“`
## Benefits
– **Backward compatible:** Single variant still works (collection of 1)
– **Flexible:** Add new variants without changing core logic
– **Clean:** Separation of concerns (extraction, fetching, grouping)
This pattern works for any multi-dimensional pricing: age groups, membership tiers, regional pricing, seasonal rates, etc.
Leave a Reply