*/ private static array $columnExists = []; protected $fillable = [ 'tld', 'register_price', 'renew_price', 'transfer_price', 'currency', 'is_override', 'is_featured', 'is_active', 'sort_order', ]; protected $casts = [ 'register_price' => 'integer', 'renew_price' => 'integer', 'transfer_price' => 'integer', 'is_override' => 'boolean', 'is_featured' => 'boolean', 'is_active' => 'boolean', 'sort_order' => 'integer', ]; /** * Get active pricing override for a TLD. */ public static function forTld(string $tld): ?self { $tld = ltrim(strtolower(trim($tld)), '.'); return Cache::remember( "domain_pricing:{$tld}", now()->addHours(1), function () use ($tld) { $query = static::where('tld', $tld); if (static::hasColumn('is_active')) { $query->where('is_active', true); } return $query->first(); } ); } /** * Get all active price overrides. * * @return array */ public static function getOverrides(): array { return Cache::remember( 'domain_pricing:overrides', now()->addHours(1), function () { $query = static::query(); if (static::hasColumn('is_active')) { $query->where('is_active', true); } // Older installs may have used this table only for manual overrides. if (static::hasColumn('is_override')) { $query->where('is_override', true); } return $query->get() ->keyBy('tld') ->map(fn ($p) => [ 'register' => $p->register_price, 'renew' => $p->renew_price, 'transfer' => $p->transfer_price, 'is_override' => static::hasColumn('is_override') ? (bool) $p->is_override : true, ]) ->all(); } ); } /** * Get all active TLDs with pricing. */ public static function activeTlds(): array { return Cache::remember( 'domain_pricing:active_tlds', now()->addHours(1), function () { $query = static::query(); if (static::hasColumn('is_active')) { $query->where('is_active', true); } if (static::hasColumn('sort_order')) { $query->orderBy('sort_order'); } return $query->orderBy('tld')->pluck('tld')->all(); } ); } /** * Get featured TLDs for search. */ public static function featuredTlds(): array { return Cache::remember( 'domain_pricing:featured_tlds', now()->addHours(1), function () { $query = static::query(); if (static::hasColumn('is_active')) { $query->where('is_active', true); } if (static::hasColumn('is_featured')) { $query->where('is_featured', true); } if (static::hasColumn('sort_order')) { $query->orderBy('sort_order'); } $tlds = $query->orderBy('tld')->pluck('tld')->all(); return $tlds !== [] ? $tlds : static::activeTlds(); } ); } /** * Get pricing map for multiple TLDs. * * @return array */ public static function pricingMap(array $tlds = []): array { $query = static::query(); if (static::hasColumn('is_active')) { $query->where('is_active', true); } if (! empty($tlds)) { $query->whereIn('tld', array_map(fn ($t) => ltrim(strtolower($t), '.'), $tlds)); } return $query->get()->keyBy('tld')->map(fn ($p) => [ 'register' => $p->register_price, 'renew' => $p->renew_price, 'transfer' => $p->transfer_price, 'currency' => $p->currency, ])->all(); } /** * Clear pricing cache. */ public static function clearCache(): void { Cache::forget('domain_pricing:active_tlds'); Cache::forget('domain_pricing:featured_tlds'); Cache::forget('domain_pricing:overrides'); foreach (static::pluck('tld') as $tld) { Cache::forget("domain_pricing:{$tld}"); } } /** * Format price for display. */ public function formatRegisterPrice(): string { return $this->formatPrice($this->register_price); } public function formatRenewPrice(): string { return $this->formatPrice($this->renew_price); } public function formatTransferPrice(): string { return $this->formatPrice($this->transfer_price); } private function formatPrice(int $amountMinor): string { $symbol = $this->currency === 'GHS' ? 'GH₵' : $this->currency; return $symbol . ' ' . number_format($amountMinor / 100, 2); } private static function hasColumn(string $column): bool { $cacheKey = static::class . ':' . $column; if (! array_key_exists($cacheKey, self::$columnExists)) { self::$columnExists[$cacheKey] = Schema::hasColumn((new static)->getTable(), $column); } return self::$columnExists[$cacheKey]; } }