togethere.cloud/private_html/userApi/UserActivityService.php

409 lines
17 KiB
PHP

<?php
class UserActivityService
{
private PDO $pdo;
private string $schema;
private array $tableCache = [];
private array $columnsCache = [];
public function __construct(PDO $pdo)
{
$this->pdo = $pdo;
$this->schema = (string)$this->pdo->query('SELECT DATABASE()')->fetchColumn();
}
public function getMyMatches(int $userId): array
{
if (!$this->hasTable('matches')) {
return [];
}
$matchesColumns = $this->getColumns('matches');
$idCol = $this->pickColumn($matchesColumns, ['ID', 'id', 'match_id']);
$team1Col = $this->pickColumn($matchesColumns, ['Team1_ID', 'team1_id']);
$team2Col = $this->pickColumn($matchesColumns, ['Team2_ID', 'team2_id']);
$startCol = $this->pickColumn($matchesColumns, ['StartTime', 'start_time', 'date', 'match_date']);
$statusCol = $this->pickColumn($matchesColumns, ['Status', 'status']);
$scoreCol = $this->pickColumn($matchesColumns, ['Score', 'score', 'result']);
$participantsCol = $this->pickColumn($matchesColumns, ['Participants', 'participants', 'user_ids', 'player_ids']);
$leagueNameCol = $this->pickColumn($matchesColumns, ['LeagueName', 'league_name', 'league', 'League']);
$matchTypeCol = $this->pickColumn($matchesColumns, ['MatchType', 'match_type']);
if (!$idCol) {
return [];
}
$select = ["m.`{$idCol}` AS match_id"];
if ($team1Col) {
$select[] = "m.`{$team1Col}` AS team1_id";
}
if ($team2Col) {
$select[] = "m.`{$team2Col}` AS team2_id";
}
if ($startCol) {
$select[] = "m.`{$startCol}` AS match_date";
}
if ($statusCol) {
$select[] = "m.`{$statusCol}` AS match_status";
}
if ($scoreCol) {
$select[] = "m.`{$scoreCol}` AS match_score";
}
if ($leagueNameCol) {
$select[] = "m.`{$leagueNameCol}` AS league_name";
}
if ($matchTypeCol) {
$select[] = "m.`{$matchTypeCol}` AS match_type";
}
if ($participantsCol) {
$select[] = "m.`{$participantsCol}` AS participants_raw";
}
$teamIds = $this->resolveUserTeamIds($userId);
$where = [];
$params = [':user_id' => $userId];
if ($team1Col && $team2Col) {
$teamChecks = ['(m.`' . $team1Col . '` = :user_id OR m.`' . $team2Col . '` = :user_id)'];
foreach ($teamIds as $index => $teamId) {
$key = ':team_' . $index;
$params[$key] = $teamId;
$teamChecks[] = '(m.`' . $team1Col . '` = ' . $key . ' OR m.`' . $team2Col . '` = ' . $key . ')';
}
$where[] = '(' . implode(' OR ', $teamChecks) . ')';
}
if ($participantsCol) {
$where[] = "CONCAT(',', REPLACE(REPLACE(REPLACE(COALESCE(m.`{$participantsCol}`, ''), '[', ''), ']', ''), ' ', ''), ',') LIKE :participant_like";
$params[':participant_like'] = '%,' . $userId . ',%';
}
if (empty($where)) {
return [];
}
$orderBy = $startCol ? "m.`{$startCol}` DESC" : "m.`{$idCol}` DESC";
$sql = 'SELECT ' . implode(', ', $select) . ' FROM `matches` m WHERE ' . implode(' OR ', $where) . ' ORDER BY ' . $orderBy . ' LIMIT 500';
$stmt = $this->pdo->prepare($sql);
$stmt->execute($params);
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
$result = [];
foreach ($rows as $row) {
$opponent = '';
if (isset($row['team1_id'], $row['team2_id'])) {
$team1Id = (int)$row['team1_id'];
$team2Id = (int)$row['team2_id'];
$opponentTeamId = $team1Id === $userId ? $team2Id : $team1Id;
if (in_array($team1Id, $teamIds, true)) {
$opponentTeamId = $team2Id;
}
if (in_array($team2Id, $teamIds, true)) {
$opponentTeamId = $team1Id;
}
$opponent = $opponentTeamId > 0 ? 'Drużyna #' . $opponentTeamId : '';
}
$result[] = [
'match_id' => (int)$row['match_id'],
'opponent' => $opponent,
'date' => !empty($row['match_date']) ? gmdate('Y-m-d\\TH:i:s\\Z', strtotime((string)$row['match_date'])) : null,
'status' => $this->normalizeStatus($row['match_status'] ?? ''),
'score' => $row['match_score'] ?? '',
'league' => $row['league_name'] ?? ($row['match_type'] ?? '')
];
}
return $result;
}
public function getMyTournaments(int $userId): array
{
if (!$this->hasTable('tournaments')) {
return [];
}
$tColumns = $this->getColumns('tournaments');
$idCol = $this->pickColumn($tColumns, ['id', 'ID', 'tournament_id']);
$nameCol = $this->pickColumn($tColumns, ['name', 'title', 'tournament_name']);
$startDateCol = $this->pickColumn($tColumns, ['start_date', 'startDate', 'start_time', 'created_at']);
$statusCol = $this->pickColumn($tColumns, ['status', 'state']);
$playedCol = $this->pickColumn($tColumns, ['matches_played', 'played_matches']);
$totalCol = $this->pickColumn($tColumns, ['total_matches', 'matches_total', 'matches_count']);
if (!$idCol) {
return [];
}
$membership = $this->resolveMembership('tournament');
$rows = [];
if ($membership !== null) {
$sql = "SELECT
t.`{$idCol}` AS tournament_id,
" . ($nameCol ? "t.`{$nameCol}`" : "''") . " AS tournament_name,
" . ($startDateCol ? "t.`{$startDateCol}`" : "NULL") . " AS start_date,
" . ($statusCol ? "t.`{$statusCol}`" : "''") . " AS tournament_status,
" . ($playedCol ? "COALESCE(t.`{$playedCol}`, 0)" : '0') . " AS matches_played,
" . ($totalCol ? "COALESCE(t.`{$totalCol}`, 0)" : '0') . " AS total_matches
FROM `{$membership['table']}` rel
INNER JOIN `tournaments` t ON t.`{$idCol}` = rel.`{$membership['entityColumn']}`
WHERE rel.`{$membership['userColumn']}` = :user_id
ORDER BY tournament_id DESC
LIMIT 500";
$stmt = $this->pdo->prepare($sql);
$stmt->execute([':user_id' => $userId]);
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
} else {
$participantsCol = $this->pickColumn($tColumns, ['participants', 'user_ids', 'player_ids']);
if (!$participantsCol) {
return [];
}
$sql = "SELECT
t.`{$idCol}` AS tournament_id,
" . ($nameCol ? "t.`{$nameCol}`" : "''") . " AS tournament_name,
" . ($startDateCol ? "t.`{$startDateCol}`" : "NULL") . " AS start_date,
" . ($statusCol ? "t.`{$statusCol}`" : "''") . " AS tournament_status,
" . ($playedCol ? "COALESCE(t.`{$playedCol}`, 0)" : '0') . " AS matches_played,
" . ($totalCol ? "COALESCE(t.`{$totalCol}`, 0)" : '0') . " AS total_matches
FROM `tournaments` t
WHERE CONCAT(',', REPLACE(REPLACE(REPLACE(COALESCE(t.`{$participantsCol}`, ''), '[', ''), ']', ''), ' ', ''), ',') LIKE :participant_like
ORDER BY tournament_id DESC
LIMIT 500";
$stmt = $this->pdo->prepare($sql);
$stmt->execute([':participant_like' => '%,' . $userId . ',%']);
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
}
return array_map(function (array $row): array {
return [
'tournament_id' => (int)$row['tournament_id'],
'name' => (string)($row['tournament_name'] ?? ''),
'start_date' => !empty($row['start_date']) ? substr((string)$row['start_date'], 0, 10) : null,
'status' => $this->normalizeStatus($row['tournament_status'] ?? ''),
'matches_played' => (int)($row['matches_played'] ?? 0),
'total_matches' => (int)($row['total_matches'] ?? 0)
];
}, $rows);
}
public function getMyLeagues(int $userId): array
{
if (!$this->hasTable('leagues')) {
return [];
}
$lColumns = $this->getColumns('leagues');
$idCol = $this->pickColumn($lColumns, ['id', 'ID', 'league_id']);
$nameCol = $this->pickColumn($lColumns, ['name', 'title', 'league_name']);
$seasonCol = $this->pickColumn($lColumns, ['season', 'season_name']);
$rankCol = $this->pickColumn($lColumns, ['rank', 'tier', 'division']);
$statusCol = $this->pickColumn($lColumns, ['status', 'state']);
$playedCol = $this->pickColumn($lColumns, ['matches_played', 'played_matches']);
$pointsCol = $this->pickColumn($lColumns, ['points', 'score_points']);
if (!$idCol) {
return [];
}
$membership = $this->resolveMembership('league');
$rows = [];
if ($membership !== null) {
$sql = "SELECT
l.`{$idCol}` AS league_id,
" . ($nameCol ? "l.`{$nameCol}`" : "''") . " AS league_name,
" . ($seasonCol ? "l.`{$seasonCol}`" : "''") . " AS season_name,
" . ($rankCol ? "l.`{$rankCol}`" : "''") . " AS league_rank,
" . ($statusCol ? "l.`{$statusCol}`" : "''") . " AS league_status,
" . ($playedCol ? "COALESCE(l.`{$playedCol}`, 0)" : '0') . " AS matches_played,
" . ($pointsCol ? "COALESCE(l.`{$pointsCol}`, 0)" : '0') . " AS points_total
FROM `{$membership['table']}` rel
INNER JOIN `leagues` l ON l.`{$idCol}` = rel.`{$membership['entityColumn']}`
WHERE rel.`{$membership['userColumn']}` = :user_id
ORDER BY league_id DESC
LIMIT 500";
$stmt = $this->pdo->prepare($sql);
$stmt->execute([':user_id' => $userId]);
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
} else {
$participantsCol = $this->pickColumn($lColumns, ['participants', 'user_ids', 'player_ids']);
if (!$participantsCol) {
return [];
}
$sql = "SELECT
l.`{$idCol}` AS league_id,
" . ($nameCol ? "l.`{$nameCol}`" : "''") . " AS league_name,
" . ($seasonCol ? "l.`{$seasonCol}`" : "''") . " AS season_name,
" . ($rankCol ? "l.`{$rankCol}`" : "''") . " AS league_rank,
" . ($statusCol ? "l.`{$statusCol}`" : "''") . " AS league_status,
" . ($playedCol ? "COALESCE(l.`{$playedCol}`, 0)" : '0') . " AS matches_played,
" . ($pointsCol ? "COALESCE(l.`{$pointsCol}`, 0)" : '0') . " AS points_total
FROM `leagues` l
WHERE CONCAT(',', REPLACE(REPLACE(REPLACE(COALESCE(l.`{$participantsCol}`, ''), '[', ''), ']', ''), ' ', ''), ',') LIKE :participant_like
ORDER BY league_id DESC
LIMIT 500";
$stmt = $this->pdo->prepare($sql);
$stmt->execute([':participant_like' => '%,' . $userId . ',%']);
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
}
return array_map(function (array $row): array {
return [
'league_id' => (int)$row['league_id'],
'name' => (string)($row['league_name'] ?? ''),
'season' => (string)($row['season_name'] ?? ''),
'rank' => (string)($row['league_rank'] ?? ''),
'status' => $this->normalizeStatus($row['league_status'] ?? ''),
'matches_played' => (int)($row['matches_played'] ?? 0),
'points' => (int)($row['points_total'] ?? 0)
];
}, $rows);
}
private function resolveUserTeamIds(int $userId): array
{
$candidates = [
['table' => 'team_members', 'team' => 'team_id', 'user' => 'user_id'],
['table' => 'teams_users', 'team' => 'team_id', 'user' => 'user_id'],
['table' => 'user_teams', 'team' => 'team_id', 'user' => 'user_id'],
['table' => 'team_user', 'team' => 'team_id', 'user' => 'user_id']
];
foreach ($candidates as $candidate) {
if (!$this->hasTable($candidate['table'])) {
continue;
}
$columns = $this->getColumns($candidate['table']);
if (!in_array($candidate['team'], $columns, true) || !in_array($candidate['user'], $columns, true)) {
continue;
}
$stmt = $this->pdo->prepare('SELECT `' . $candidate['team'] . '` FROM `' . $candidate['table'] . '` WHERE `' . $candidate['user'] . '` = :user_id');
$stmt->execute([':user_id' => $userId]);
$ids = $stmt->fetchAll(PDO::FETCH_COLUMN);
$ids = array_values(array_unique(array_map('intval', $ids)));
return array_values(array_filter($ids, fn($id) => $id > 0));
}
return [];
}
private function resolveMembership(string $entity): ?array
{
$map = [
'tournament' => [
['table' => 'tournament_members', 'entity' => 'tournament_id', 'user' => 'user_id'],
['table' => 'tournaments_users', 'entity' => 'tournament_id', 'user' => 'user_id'],
['table' => 'user_tournaments', 'entity' => 'tournament_id', 'user' => 'user_id'],
['table' => 'tournament_participants', 'entity' => 'tournament_id', 'user' => 'user_id']
],
'league' => [
['table' => 'league_members', 'entity' => 'league_id', 'user' => 'user_id'],
['table' => 'leagues_users', 'entity' => 'league_id', 'user' => 'user_id'],
['table' => 'user_leagues', 'entity' => 'league_id', 'user' => 'user_id'],
['table' => 'league_participants', 'entity' => 'league_id', 'user' => 'user_id']
]
];
if (!isset($map[$entity])) {
return null;
}
foreach ($map[$entity] as $candidate) {
if (!$this->hasTable($candidate['table'])) {
continue;
}
$columns = $this->getColumns($candidate['table']);
if (!in_array($candidate['entity'], $columns, true) || !in_array($candidate['user'], $columns, true)) {
continue;
}
return [
'table' => $candidate['table'],
'entityColumn' => $candidate['entity'],
'userColumn' => $candidate['user']
];
}
return null;
}
private function hasTable(string $table): bool
{
if (array_key_exists($table, $this->tableCache)) {
return $this->tableCache[$table];
}
$stmt = $this->pdo->prepare('SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = :schema AND table_name = :table');
$stmt->execute([
':schema' => $this->schema,
':table' => $table
]);
$exists = (int)$stmt->fetchColumn() > 0;
$this->tableCache[$table] = $exists;
return $exists;
}
private function getColumns(string $table): array
{
if (isset($this->columnsCache[$table])) {
return $this->columnsCache[$table];
}
if (!$this->hasTable($table)) {
$this->columnsCache[$table] = [];
return [];
}
$stmt = $this->pdo->prepare('SELECT COLUMN_NAME FROM information_schema.columns WHERE table_schema = :schema AND table_name = :table');
$stmt->execute([
':schema' => $this->schema,
':table' => $table
]);
$columns = $stmt->fetchAll(PDO::FETCH_COLUMN);
$this->columnsCache[$table] = is_array($columns) ? $columns : [];
return $this->columnsCache[$table];
}
private function pickColumn(array $columns, array $candidates): ?string
{
foreach ($candidates as $candidate) {
if (in_array($candidate, $columns, true)) {
return $candidate;
}
}
return null;
}
private function normalizeStatus(string $status): string
{
$status = mb_strtolower(trim($status));
return match ($status) {
'planned', 'planowany', 'zaplanowany' => 'zaplanowany',
'live', 'ongoing', 'trwający', 'in_progress' => 'trwający',
'end', 'ended', 'finished', 'zakończony' => 'zakończony',
default => $status
};
}
}