['except' => ''], 'specialties' => ['except' => []], 'designStyle' => ['except' => ''], 'foundedYearFrom' => ['except' => ''], 'foundedYearTo' => ['except' => ''], 'minInnovationScore' => ['except' => ''], 'maxInnovationScore' => ['except' => ''], 'minActiveYears' => ['except' => ''], 'maxActiveYears' => ['except' => ''], 'sortBy' => ['except' => 'name'], 'sortDirection' => ['except' => 'asc'], 'viewMode' => ['except' => 'grid'], 'page' => ['except' => 1], ]; /** * Component initialization */ public function mount(): void { $this->loadPortfolioStatistics(); $this->loadInnovationTimeline(); $this->loadCollaborationNetworks(); } /** * Load creative portfolio statistics with caching */ protected function loadPortfolioStatistics(): void { $this->portfolioStats = Cache::remember( 'designers.portfolio.stats', now()->addHours(6), fn() => $this->calculatePortfolioStatistics() ); } /** * Load innovation timeline data with caching */ protected function loadInnovationTimeline(): void { $this->innovationTimeline = Cache::remember( 'designers.innovation.timeline', now()->addHours(12), fn() => $this->calculateInnovationTimeline() ); } /** * Load collaboration networks with caching */ protected function loadCollaborationNetworks(): void { $this->collaborationNetworks = Cache::remember( 'designers.collaboration.networks', now()->addHours(6), fn() => $this->calculateCollaborationNetworks() ); } /** * Calculate comprehensive portfolio statistics */ protected function calculatePortfolioStatistics(): array { return [ 'total_designers' => Designer::active()->count(), 'coaster_designers' => Designer::active()->specialty('roller_coaster')->count(), 'dark_ride_designers' => Designer::active()->specialty('dark_ride')->count(), 'themed_experience_designers' => Designer::active()->specialty('themed_experience')->count(), 'water_attraction_designers' => Designer::active()->specialty('water_attraction')->count(), 'specialties_distribution' => Designer::active() ->select('specialty', DB::raw('count(*) as count')) ->whereNotNull('specialty') ->groupBy('specialty') ->orderByDesc('count') ->get() ->pluck('count', 'specialty') ->toArray(), 'average_innovation_score' => Designer::active() ->whereNotNull('innovation_score') ->avg('innovation_score'), 'total_designs' => Designer::active() ->withCount('rides') ->get() ->sum('rides_count'), 'top_innovators' => Designer::active() ->orderByDesc('innovation_score') ->take(5) ->get(['name', 'innovation_score', 'specialty']) ->toArray(), 'design_styles' => Designer::active() ->select('design_style', DB::raw('count(*) as count')) ->whereNotNull('design_style') ->groupBy('design_style') ->orderByDesc('count') ->get() ->pluck('count', 'design_style') ->toArray(), ]; } /** * Calculate innovation timeline data */ protected function calculateInnovationTimeline(): array { $timelineData = Designer::active() ->whereNotNull('founded_year') ->whereNotNull('innovation_score') ->select('founded_year', 'innovation_score', 'name', 'specialty') ->orderBy('founded_year') ->get() ->groupBy(function($designer) { return floor($designer->founded_year / 10) * 10; // Group by decade }) ->map(function($decade) { return [ 'count' => $decade->count(), 'avg_innovation' => $decade->avg('innovation_score'), 'top_designer' => $decade->sortByDesc('innovation_score')->first(), 'specialties' => $decade->countBy('specialty')->toArray() ]; }); return [ 'timeline' => $timelineData->toArray(), 'innovation_milestones' => Designer::active() ->where('innovation_score', '>=', 8.5) ->orderByDesc('innovation_score') ->take(10) ->get(['name', 'founded_year', 'innovation_score', 'specialty']) ->toArray(), 'breakthrough_years' => Designer::active() ->whereNotNull('founded_year') ->select('founded_year', DB::raw('count(*) as new_designers'), DB::raw('avg(innovation_score) as avg_innovation')) ->groupBy('founded_year') ->having('new_designers', '>=', 2) ->orderByDesc('avg_innovation') ->take(5) ->get() ->toArray(), ]; } /** * Calculate collaboration networks */ protected function calculateCollaborationNetworks(): array { return [ 'collaboration_pairs' => Designer::active() ->whereHas('rides', function($query) { $query->whereHas('park', function($parkQuery) { $parkQuery->whereHas('rides', function($rideQuery) { $rideQuery->whereNotNull('designer_id'); }); }); }) ->with(['rides.park.rides.designer']) ->get() ->flatMap(function($designer) { return $designer->rides->flatMap(function($ride) use ($designer) { return $ride->park->rides ->where('designer_id', '!=', $designer->id) ->whereNotNull('designer_id') ->pluck('designer.name') ->map(function($collaborator) use ($designer, $ride) { return [ 'designer' => $designer->name, 'collaborator' => $collaborator, 'park' => $ride->park->name ]; }); }); }) ->groupBy(function($item) { $names = [$item['designer'], $item['collaborator']]; sort($names); return implode(' + ', $names); }) ->map(function($collaborations) { return [ 'count' => $collaborations->count(), 'parks' => $collaborations->pluck('park')->unique()->values()->toArray() ]; }) ->sortByDesc('count') ->take(10) ->toArray(), 'network_hubs' => Designer::active() ->withCount('rides') ->having('rides_count', '>=', 3) ->orderByDesc('rides_count') ->take(10) ->get(['name', 'specialty', 'rides_count']) ->toArray(), 'cross_specialty_projects' => Designer::active() ->whereHas('rides', function($query) { $query->whereHas('park', function($parkQuery) { $parkQuery->whereHas('rides', function($rideQuery) { $rideQuery->whereHas('designer', function($designerQuery) { $designerQuery->whereColumn('specialty', '!=', 'designers.specialty'); }); }); }); }) ->with(['rides.park']) ->get() ->flatMap(function($designer) { return $designer->rides->map(function($ride) use ($designer) { return [ 'designer' => $designer->name, 'specialty' => $designer->specialty, 'park' => $ride->park->name, 'ride' => $ride->name ]; }); }) ->take(15) ->toArray(), ]; } /** * Django parity creative portfolio search functionality */ public function creativePortfolioSearch($query, $specialties = []) { return Designer::query() ->when($query, function ($q) use ($query) { $terms = explode(' ', trim($query)); foreach ($terms as $term) { if (strlen($term) >= 2) { $q->where(function ($subQuery) use ($term) { $subQuery->where('name', 'ilike', "%{$term}%") ->orWhere('description', 'ilike', "%{$term}%") ->orWhere('specialty', 'ilike', "%{$term}%") ->orWhere('design_style', 'ilike', "%{$term}%") ->orWhere('headquarters', 'ilike', "%{$term}%") ->orWhereHas('rides', function($rideQuery) use ($term) { $rideQuery->where('name', 'ilike', "%{$term}%") ->orWhere('category', 'ilike', "%{$term}%"); }) ->orWhereHas('rides.park', function($parkQuery) use ($term) { $parkQuery->where('name', 'ilike', "%{$term}%"); }); }); } } }) ->when($specialties, function ($q) use ($specialties) { $q->whereIn('specialty', $specialties); }) ->active() ->with(['rides:id,designer_id,name,category,park_id', 'rides.park:id,name']) ->withCount(['rides']); } /** * Apply creative and innovation filters */ public function applyCreativeFilters($query) { return $query ->when($this->designStyle, fn($q, $style) => $q->where('design_style', $style)) ->when($this->foundedYearFrom, fn($q, $year) => $q->where('founded_year', '>=', $year)) ->when($this->foundedYearTo, fn($q, $year) => $q->where('founded_year', '<=', $year)) ->when($this->minInnovationScore, fn($q, $score) => $q->where('innovation_score', '>=', $score)) ->when($this->maxInnovationScore, fn($q, $score) => $q->where('innovation_score', '<=', $score)) ->when($this->minActiveYears, fn($q, $years) => $q->where('active_years', '>=', $years)) ->when($this->maxActiveYears, fn($q, $years) => $q->where('active_years', '<=', $years)); } /** * Get designers with optimized caching */ public function getDesignersProperty() { $cacheKey = "designers.listing." . md5(serialize([ 'search' => $this->search, 'specialties' => $this->specialties, 'designStyle' => $this->designStyle, 'foundedYearFrom' => $this->foundedYearFrom, 'foundedYearTo' => $this->foundedYearTo, 'minInnovationScore' => $this->minInnovationScore, 'maxInnovationScore' => $this->maxInnovationScore, 'minActiveYears' => $this->minActiveYears, 'maxActiveYears' => $this->maxActiveYears, 'sortBy' => $this->sortBy, 'sortDirection' => $this->sortDirection, 'page' => $this->getPage(), 'perPage' => $this->perPage, ])); return Cache::remember($cacheKey, now()->addMinutes(30), function() { $query = $this->creativePortfolioSearch($this->search, $this->specialties); $query = $this->applyCreativeFilters($query); // Apply sorting switch ($this->sortBy) { case 'name': $query->orderBy('name', $this->sortDirection); break; case 'founded_year': $query->orderBy('founded_year', $this->sortDirection); break; case 'innovation_score': $query->orderBy('innovation_score', $this->sortDirection); break; case 'designed_rides_count': $query->orderBy('rides_count', $this->sortDirection); break; case 'active_years': $query->orderBy('active_years', $this->sortDirection); break; default: $query->orderBy('name', 'asc'); } return $query->paginate($this->perPage); }); } /** * Update search and reset pagination */ public function updatedSearch(): void { $this->resetPage(); $this->invalidateCache(); } /** * Update specialties filter and reset pagination */ public function updatedSpecialties(): void { $this->resetPage(); $this->invalidateCache(); } /** * Update any filter and reset pagination */ public function updatedDesignStyle(): void { $this->resetPage(); $this->invalidateCache(); } public function updatedFoundedYearFrom(): void { $this->resetPage(); $this->invalidateCache(); } public function updatedFoundedYearTo(): void { $this->resetPage(); $this->invalidateCache(); } public function updatedMinInnovationScore(): void { $this->resetPage(); $this->invalidateCache(); } public function updatedMaxInnovationScore(): void { $this->resetPage(); $this->invalidateCache(); } public function updatedMinActiveYears(): void { $this->resetPage(); $this->invalidateCache(); } public function updatedMaxActiveYears(): void { $this->resetPage(); $this->invalidateCache(); } /** * Sort by specific column */ public function sortBy(string $column): void { if ($this->sortBy === $column) { $this->sortDirection = $this->sortDirection === 'asc' ? 'desc' : 'asc'; } else { $this->sortBy = $column; $this->sortDirection = 'asc'; } $this->resetPage(); $this->invalidateCache(); } /** * Change view mode */ public function setViewMode(string $mode): void { $this->viewMode = $mode; } /** * Clear all filters */ public function clearFilters(): void { $this->search = ''; $this->specialties = []; $this->designStyle = ''; $this->foundedYearFrom = ''; $this->foundedYearTo = ''; $this->minInnovationScore = ''; $this->maxInnovationScore = ''; $this->minActiveYears = ''; $this->maxActiveYears = ''; $this->sortBy = 'name'; $this->sortDirection = 'asc'; $this->resetPage(); $this->invalidateCache(); } /** * Toggle specialty filter */ public function toggleSpecialtyFilter(string $specialty): void { if (in_array($specialty, $this->specialties)) { $this->specialties = array_values(array_diff($this->specialties, [$specialty])); } else { $this->specialties[] = $specialty; } $this->resetPage(); $this->invalidateCache(); } /** * Invalidate component cache */ protected function invalidateCache(): void { Cache::forget('designers.portfolio.stats'); Cache::forget('designers.innovation.timeline'); Cache::forget('designers.collaboration.networks'); // Clear listing cache pattern - simplified approach $cacheKeys = [ 'designers.listing.*' ]; foreach ($cacheKeys as $pattern) { Cache::forget($pattern); } } /** * Get cache key for this component */ protected function getCacheKey(string $suffix = ''): string { return 'thrillwiki.' . class_basename(static::class) . '.' . $suffix; } /** * Remember data with caching */ protected function remember(string $key, $callback, int $ttl = 3600) { return Cache::remember($this->getCacheKey($key), $ttl, $callback); } /** * Render the component */ public function render() { return view('livewire.designers-listing-universal', [ 'designers' => $this->designers, 'portfolioStats' => $this->portfolioStats, 'innovationTimeline' => $this->innovationTimeline, 'collaborationNetworks' => $this->collaborationNetworks, ]); } }