model ->select($select) ->where('languages.is_active', true) ->whereExists(function ($query) { $query->select(DB::raw(1)) ->from('feed_languages') ->join('feeds', 'feeds.id', '=', 'feed_languages.feed_id') ->whereColumn('feed_languages.language_id', 'languages.id') ->where('feeds.is_active', true) ->where('feed_languages.is_active', true); }) ->whereExists(function ($query) { $query->select(DB::raw(1)) ->from('platform_channels') ->whereColumn('platform_channels.language_id', 'languages.id') ->where('platform_channels.is_active', true); }) ->orderBy('name') ->get(); } /** * Find feeds by language with efficient joins */ public function findFeedsByLanguage( int $languageId, ?string $search = null, array $select = ['feeds.*'], int $perPage = 15 ): LengthAwarePaginator { $query = DB::table('feeds') ->join('feed_languages', 'feeds.id', '=', 'feed_languages.feed_id') ->where('feed_languages.language_id', $languageId) ->where('feeds.is_active', true) ->where('feed_languages.is_active', true) ->select($select); if ($search) { $query->where(function ($q) use ($search) { $q->where('feeds.name', 'like', "%{$search}%") ->orWhere('feeds.url', 'like', "%{$search}%"); }); } return $query->orderBy('feeds.name') ->paginate(min($perPage, 100)); } /** * Find channels by language with efficient joins */ public function findChannelsByLanguage( int $languageId, ?string $search = null, array $select = ['platform_channels.*'], int $perPage = 15, bool $withPlatformInstance = true ): LengthAwarePaginator { $query = DB::table('platform_channels'); if ($withPlatformInstance) { $query->join('platform_instances', 'platform_channels.platform_instance_id', '=', 'platform_instances.id') ->addSelect([ 'platform_instances.id as platform_instance_id', 'platform_instances.name as platform_instance_name', 'platform_instances.url as platform_instance_url' ]); } $query->where('platform_channels.language_id', $languageId) ->where('platform_channels.is_active', true) ->select(array_merge($select, $withPlatformInstance ? [] : [])); if ($search) { $query->where(function ($q) use ($search) { $q->where('platform_channels.name', 'like', "%{$search}%") ->orWhere('platform_channels.display_name', 'like', "%{$search}%"); }); } return $query->orderBy('platform_channels.name') ->paginate(min($perPage, 100)); } /** * Get language statistics with single optimized query */ public function getLanguageStatistics(int $languageId): object { return DB::selectOne(" SELECT (SELECT COUNT(*) FROM feed_languages fl JOIN feeds f ON f.id = fl.feed_id WHERE fl.language_id = ? AND fl.is_active = 1 AND f.is_active = 1) as active_feeds_count, (SELECT COUNT(*) FROM platform_channels pc WHERE pc.language_id = ? AND pc.is_active = 1) as active_channels_count, (SELECT COUNT(*) FROM routes r WHERE r.language_id = ? AND r.is_active = 1) as active_routes_count ", [$languageId, $languageId, $languageId]); } /** * Get comprehensive language usage summary */ public function getLanguageUsageSummary(): array { $results = DB::select(" SELECT l.id, l.short_code, l.name, l.native_name, l.is_active, COALESCE(feed_stats.active_feeds, 0) as active_feeds_count, COALESCE(channel_stats.active_channels, 0) as active_channels_count, COALESCE(route_stats.active_routes, 0) as active_routes_count, CASE WHEN COALESCE(feed_stats.active_feeds, 0) > 0 AND COALESCE(channel_stats.active_channels, 0) > 0 THEN 1 ELSE 0 END as can_create_routes FROM languages l LEFT JOIN ( SELECT fl.language_id, COUNT(*) as active_feeds FROM feed_languages fl INNER JOIN feeds f ON f.id = fl.feed_id WHERE fl.is_active = 1 AND f.is_active = 1 GROUP BY fl.language_id ) feed_stats ON feed_stats.language_id = l.id LEFT JOIN ( SELECT pc.language_id, COUNT(*) as active_channels FROM platform_channels pc WHERE pc.is_active = 1 GROUP BY pc.language_id ) channel_stats ON channel_stats.language_id = l.id LEFT JOIN ( SELECT r.language_id, COUNT(*) as active_routes FROM routes r WHERE r.is_active = 1 GROUP BY r.language_id ) route_stats ON route_stats.language_id = l.id ORDER BY l.name "); return array_map(fn($row) => (array)$row, $results); } /** * Find common languages between feed and channel with optimized query */ public function findCommonLanguages(int $feedId, int $channelId): array { $results = DB::select(" SELECT DISTINCT l.id, l.short_code, l.name, l.native_name FROM languages l INNER JOIN feed_languages fl ON fl.language_id = l.id INNER JOIN feeds f ON f.id = fl.feed_id INNER JOIN platform_channels pc ON pc.language_id = l.id WHERE f.id = ? AND pc.id = ? AND l.is_active = 1 AND f.is_active = 1 AND fl.is_active = 1 AND pc.is_active = 1 ORDER BY l.name ", [$feedId, $channelId]); return array_map(fn($row) => (array)$row, $results); } /** * Check if language can be used for routes with optimized query */ public function canLanguageBeUsedForRoutes(int $languageId): bool { $result = DB::selectOne(" SELECT EXISTS(SELECT 1 FROM feed_languages fl JOIN feeds f ON f.id = fl.feed_id WHERE fl.language_id = ? AND fl.is_active = 1 AND f.is_active = 1) as has_feeds, EXISTS(SELECT 1 FROM platform_channels pc WHERE pc.language_id = ? AND pc.is_active = 1) as has_channels ", [$languageId, $languageId]); return $result->has_feeds && $result->has_channels; } /** * Get active languages with optional counts */ public function findActiveLanguages( bool $withCounts = false, array $select = ['*'] ): Collection { $query = $this->model->where('is_active', true); if ($withCounts) { $query->withCounts(); } if ($select !== ['*'] && !empty($select)) { $query->select($select); } return $query->orderBy('name')->get(); } /** * Batch check language availability for multiple language IDs */ public function batchCheckLanguageAvailability(array $languageIds): array { if (empty($languageIds)) { return []; } $placeholders = str_repeat('?,', count($languageIds) - 1) . '?'; $results = DB::select(" SELECT l.id, EXISTS(SELECT 1 FROM feed_languages fl JOIN feeds f ON f.id = fl.feed_id WHERE fl.language_id = l.id AND fl.is_active = 1 AND f.is_active = 1) as has_feeds, EXISTS(SELECT 1 FROM platform_channels pc WHERE pc.language_id = l.id AND pc.is_active = 1) as has_channels FROM languages l WHERE l.id IN ({$placeholders}) AND l.is_active = 1 ", $languageIds); $availability = []; foreach ($results as $result) { $availability[$result->id] = $result->has_feeds && $result->has_channels; } return $availability; } /** * Get language with relationship counts for specific language */ public function findWithCounts(int $languageId): ?Language { return $this->model ->withCounts() ->find($languageId); } /** * Search languages by name or code */ public function search( string $term, bool $activeOnly = true, array $select = ['*'] ): Collection { $query = $this->model->select($select) ->where(function ($q) use ($term) { $q->where('name', 'like', "%{$term}%") ->orWhere('native_name', 'like', "%{$term}%") ->orWhere('short_code', 'like', "%{$term}%"); }); if ($activeOnly) { $query->where('is_active', true); } return $query->orderBy('name')->get(); } }