fedi-feed-router/backend/src/Domains/Settings/Repositories/LanguageRepository.php
2025-08-16 10:47:50 +02:00

289 lines
No EOL
10 KiB
PHP

<?php
namespace Domains\Settings\Repositories;
use Domains\Settings\Models\Language;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\DB;
use Illuminate\Pagination\LengthAwarePaginator;
class LanguageRepository
{
public function __construct(
private Language $model
) {}
/**
* Find languages available for route creation with optimized query
*/
public function findAvailableForRoutes(array $select = ['*']): Collection
{
return $this->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();
}
}