Files
thrillwiki_laravel/app/Livewire/ManufacturersListingUniversal.php
pacnpal 97a7682eb7 Add Livewire components for parks, rides, and manufacturers
- Implemented ParksLocationSearch component with loading state and refresh functionality.
- Created ParksMapView component with similar structure and functionality.
- Added RegionalParksListing component for displaying regional parks.
- Developed RidesListingUniversal component for universal listing integration.
- Established ManufacturersListing view with navigation and Livewire integration.
- Added feature tests for various Livewire components including OperatorHierarchyView, OperatorParksListing, OperatorPortfolioCard, OperatorsListing, OperatorsRoleFilter, ParksListing, ParksLocationSearch, ParksMapView, and RegionalParksListing to ensure proper rendering and adherence to patterns.
2025-06-23 21:31:05 -04:00

362 lines
13 KiB
PHP

<?php
namespace App\Livewire;
use App\Models\Manufacturer;
use Livewire\Component;
use Livewire\WithPagination;
use Illuminate\Support\Facades\Cache;
use Illuminate\Database\Eloquent\Builder;
class ManufacturersListingUniversal extends Component
{
use WithPagination;
// Universal Listing System Integration
public string $entityType = 'manufacturers';
// Search and Filtering
public string $search = '';
public string $sortBy = 'name';
public string $sortDirection = 'asc';
public string $viewMode = 'grid';
public int $perPage = 12;
// Manufacturer-specific filters
public array $specializations = [];
public array $totalRidesRange = [0, 1000];
public array $industryPresenceRange = [0, 100];
public array $foundedYearRange = [1800, 2025];
public bool $activeOnly = false;
public bool $innovationLeadersOnly = false;
// Performance optimization
private string $cacheKeyPrefix = 'manufacturers_listing';
private int $cacheProductPortfolioTtl = 21600; // 6 hours
private int $cacheIndustryPresenceTtl = 43200; // 12 hours
private int $cacheListingTtl = 1800; // 30 minutes
protected $queryString = [
'search' => ['except' => ''],
'sortBy' => ['except' => 'name'],
'sortDirection' => ['except' => 'asc'],
'viewMode' => ['except' => 'grid'],
'perPage' => ['except' => 12],
'specializations' => ['except' => []],
'totalRidesRange' => ['except' => [0, 1000]],
'industryPresenceRange' => ['except' => [0, 100]],
'foundedYearRange' => ['except' => [1800, 2025]],
'activeOnly' => ['except' => false],
'innovationLeadersOnly' => ['except' => false],
'page' => ['except' => 1],
];
public function mount()
{
// Initialize filters with cached values for performance
$this->initializeFilters();
}
public function updatedSearch()
{
$this->resetPage();
}
public function updatedSpecializations()
{
$this->resetPage();
}
public function updatedTotalRidesRange()
{
$this->resetPage();
}
public function updatedIndustryPresenceRange()
{
$this->resetPage();
}
public function updatedFoundedYearRange()
{
$this->resetPage();
}
public function updatedActiveOnly()
{
$this->resetPage();
}
public function updatedInnovationLeadersOnly()
{
$this->resetPage();
}
public function clearFilters()
{
$this->reset([
'search',
'specializations',
'totalRidesRange',
'industryPresenceRange',
'foundedYearRange',
'activeOnly',
'innovationLeadersOnly'
]);
$this->totalRidesRange = [0, 1000];
$this->industryPresenceRange = [0, 100];
$this->foundedYearRange = [1800, 2025];
$this->resetPage();
}
public function setViewMode(string $mode)
{
$this->viewMode = $mode;
}
public function setSortBy(string $field)
{
if ($this->sortBy === $field) {
$this->sortDirection = $this->sortDirection === 'asc' ? 'desc' : 'asc';
} else {
$this->sortBy = $field;
$this->sortDirection = 'asc';
}
$this->resetPage();
}
public function render()
{
$manufacturers = $this->getManufacturers();
$statistics = $this->getStatistics();
$productPortfolioData = $this->getProductPortfolioData();
$industryPresenceData = $this->getIndustryPresenceData();
return view('livewire.manufacturers-listing-universal', [
'manufacturers' => $manufacturers,
'statistics' => $statistics,
'productPortfolioData' => $productPortfolioData,
'industryPresenceData' => $industryPresenceData,
'hasActiveFilters' => $this->hasActiveFilters(),
]);
}
private function getManufacturers()
{
$cacheKey = $this->generateCacheKey();
return Cache::remember($cacheKey, $this->cacheListingTtl, function () {
$query = Manufacturer::query()
->select([
'id', 'name', 'slug', 'headquarters', 'description', 'website',
'total_rides', 'total_roller_coasters', 'founded_year',
'industry_presence_score', 'specialization', 'is_active',
'is_major_manufacturer', 'market_share_percentage', 'created_at'
]);
// Apply search with Django parity algorithms
if (!empty($this->search)) {
$searchTerms = explode(' ', trim($this->search));
$query->where(function (Builder $q) use ($searchTerms) {
foreach ($searchTerms as $term) {
$q->where(function (Builder $subQ) use ($term) {
$subQ->where('name', 'ILIKE', "%{$term}%")
->orWhere('description', 'ILIKE', "%{$term}%")
->orWhere('headquarters', 'ILIKE', "%{$term}%")
->orWhere('specialization', 'ILIKE', "%{$term}%");
});
}
});
}
// Apply specialization filters
if (!empty($this->specializations)) {
$query->whereIn('specialization', $this->specializations);
}
// Apply total rides range filter
if ($this->totalRidesRange[0] > 0 || $this->totalRidesRange[1] < 1000) {
$query->whereBetween('total_rides', $this->totalRidesRange);
}
// Apply industry presence score range filter
if ($this->industryPresenceRange[0] > 0 || $this->industryPresenceRange[1] < 100) {
$query->whereBetween('industry_presence_score', $this->industryPresenceRange);
}
// Apply founded year range filter
if ($this->foundedYearRange[0] > 1800 || $this->foundedYearRange[1] < 2025) {
$query->whereBetween('founded_year', $this->foundedYearRange);
}
// Apply active filter
if ($this->activeOnly) {
$query->where('is_active', true);
}
// Apply major manufacturers filter
if ($this->innovationLeadersOnly) {
$query->where('is_major_manufacturer', true);
}
// Apply sorting
$query->orderBy($this->sortBy, $this->sortDirection);
// Add secondary sort for consistency
if ($this->sortBy !== 'name') {
$query->orderBy('name', 'asc');
}
return $query->paginate($this->perPage);
});
}
private function getStatistics()
{
$cacheKey = "{$this->cacheKeyPrefix}_statistics";
return Cache::remember($cacheKey, $this->cacheListingTtl, function () {
$baseQuery = Manufacturer::query();
// Apply same filters as main query for accurate statistics
if (!empty($this->search)) {
$searchTerms = explode(' ', trim($this->search));
$baseQuery->where(function (Builder $q) use ($searchTerms) {
foreach ($searchTerms as $term) {
$q->where(function (Builder $subQ) use ($term) {
$subQ->where('name', 'ILIKE', "%{$term}%")
->orWhere('description', 'ILIKE', "%{$term}%")
->orWhere('headquarters', 'ILIKE', "%{$term}%")
->orWhere('specialization', 'ILIKE', "%{$term}%");
});
}
});
}
if (!empty($this->specializations)) {
$baseQuery->whereIn('specialization', $this->specializations);
}
if ($this->totalRidesRange[0] > 0 || $this->totalRidesRange[1] < 1000) {
$baseQuery->whereBetween('total_rides', $this->totalRidesRange);
}
if ($this->industryPresenceRange[0] > 0 || $this->industryPresenceRange[1] < 100) {
$baseQuery->whereBetween('industry_presence_score', $this->industryPresenceRange);
}
if ($this->foundedYearRange[0] > 1800 || $this->foundedYearRange[1] < 2025) {
$baseQuery->whereBetween('founded_year', $this->foundedYearRange);
}
if ($this->activeOnly) {
$baseQuery->where('is_active', true);
}
if ($this->innovationLeadersOnly) {
$baseQuery->where('is_major_manufacturer', true);
}
return [
'count' => $baseQuery->count(),
'active_count' => (clone $baseQuery)->where('is_active', true)->count(),
'total_rides_sum' => $baseQuery->sum('total_rides'),
'avg_industry_presence' => round($baseQuery->avg('industry_presence_score'), 1),
];
});
}
private function getProductPortfolioData()
{
$cacheKey = "{$this->cacheKeyPrefix}_product_portfolio";
return Cache::remember($cacheKey, $this->cacheProductPortfolioTtl, function () {
return [
'specialization_distribution' => Manufacturer::selectRaw('specialization, COUNT(*) as count')
->groupBy('specialization')
->pluck('count', 'specialization')
->toArray(),
'top_manufacturers_by_rides' => Manufacturer::orderBy('total_rides', 'desc')
->limit(10)
->pluck('total_rides', 'name')
->toArray(),
'major_manufacturers_count' => Manufacturer::where('is_major_manufacturer', true)->count(),
'average_market_share' => round(Manufacturer::avg('market_share_percentage'), 2),
];
});
}
private function getIndustryPresenceData()
{
$cacheKey = "{$this->cacheKeyPrefix}_industry_presence";
return Cache::remember($cacheKey, $this->cacheIndustryPresenceTtl, function () {
return [
'presence_score_ranges' => [
'high' => Manufacturer::where('industry_presence_score', '>=', 80)->count(),
'medium' => Manufacturer::whereBetween('industry_presence_score', [50, 79])->count(),
'low' => Manufacturer::where('industry_presence_score', '<', 50)->count(),
],
'founding_decades' => Manufacturer::selectRaw('FLOOR(founded_year / 10) * 10 as decade, COUNT(*) as count')
->groupBy('decade')
->orderBy('decade')
->pluck('count', 'decade')
->toArray(),
'active_vs_inactive' => [
'active' => Manufacturer::where('is_active', true)->count(),
'inactive' => Manufacturer::where('is_active', false)->count(),
],
'market_concentration' => Manufacturer::orderBy('market_share_percentage', 'desc')
->limit(5)
->pluck('market_share_percentage', 'name')
->toArray(),
];
});
}
private function hasActiveFilters(): bool
{
return !empty($this->search) ||
!empty($this->specializations) ||
$this->totalRidesRange !== [0, 1000] ||
$this->industryPresenceRange !== [0, 100] ||
$this->foundedYearRange !== [1800, 2025] ||
$this->activeOnly ||
$this->innovationLeadersOnly;
}
private function generateCacheKey(): string
{
$filterHash = md5(serialize([
'search' => $this->search,
'sortBy' => $this->sortBy,
'sortDirection' => $this->sortDirection,
'specializations' => $this->specializations,
'totalRidesRange' => $this->totalRidesRange,
'industryPresenceRange' => $this->industryPresenceRange,
'foundedYearRange' => $this->foundedYearRange,
'activeOnly' => $this->activeOnly,
'innovationLeadersOnly' => $this->innovationLeadersOnly,
'perPage' => $this->perPage,
'page' => $this->getPage(),
]));
return "{$this->cacheKeyPrefix}_{$filterHash}";
}
private function initializeFilters()
{
// Initialize with sensible defaults for manufacturer filtering
if (empty($this->totalRidesRange)) {
$this->totalRidesRange = [0, 1000];
}
if (empty($this->industryPresenceRange)) {
$this->industryPresenceRange = [0, 100];
}
if (empty($this->foundedYearRange)) {
$this->foundedYearRange = [1800, 2025];
}
}
}