160 lines
8.3 KiB
PHP
160 lines
8.3 KiB
PHP
<?php
|
|
|
|
namespace App\Controllers;
|
|
|
|
use App\Core\Database;
|
|
use App\Repositories\SheetTemplateRepository;
|
|
|
|
final class ScoresheetExportController
|
|
{
|
|
public function ltv26(array $params): void
|
|
{
|
|
$matchId = (int) $params['id'];
|
|
$db = Database::connection();
|
|
$templateRow = (new SheetTemplateRepository())->resolveForMatch($matchId);
|
|
if (!$templateRow) {
|
|
$template = require __DIR__ . '/../../config/templates/ltv26_scoresheet.php';
|
|
} else {
|
|
$template = json_decode($templateRow['config_json'], true);
|
|
$template = is_array($template) ? $template : [];
|
|
$template['image'] = $templateRow['image_path'];
|
|
$template['width'] = (int) $templateRow['page_width'];
|
|
$template['height'] = (int) $templateRow['page_height'];
|
|
}
|
|
$match = $this->match($db, $matchId);
|
|
$sets = $this->rows($db, 'SELECT * FROM match_sets WHERE match_id = :id ORDER BY set_number', $matchId);
|
|
$homePlayers = $this->players($db, (int) $match['home_team_id']);
|
|
$awayPlayers = $this->players($db, (int) $match['away_team_id']);
|
|
$signatures = $this->rows($db, 'SELECT * FROM referee_signatures WHERE match_id = :id ORDER BY signed_at DESC', $matchId);
|
|
|
|
header('Content-Type: text/html; charset=utf-8');
|
|
header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
|
|
if ($templateRow) {
|
|
$payload = json_encode(['match_id' => $matchId, 'template_id' => $templateRow['id'], 'time' => time()]);
|
|
$db->prepare(
|
|
'INSERT INTO match_sheet_exports (match_id, sheet_template_id, export_type, export_hash)
|
|
VALUES (:match_id, :sheet_template_id, "html", :export_hash)'
|
|
)->execute([
|
|
'match_id' => $matchId,
|
|
'sheet_template_id' => $templateRow['id'],
|
|
'export_hash' => hash('sha256', $payload),
|
|
]);
|
|
}
|
|
echo $this->html($template, $match, $sets, $homePlayers, $awayPlayers, $signatures);
|
|
}
|
|
|
|
private function html(array $template, array $match, array $sets, array $homePlayers, array $awayPlayers, array $signatures): string
|
|
{
|
|
$fields = [
|
|
'tournament' => $match['tournament_name'],
|
|
'match_code' => '#' . $match['id'],
|
|
'date' => $match['scheduled_at'] ? date('d/m/Y', strtotime($match['scheduled_at'])) : '',
|
|
'time' => $match['scheduled_at'] ? date('H:i', strtotime($match['scheduled_at'])) : '',
|
|
'court' => $match['court_name'] ?? '',
|
|
'home_team' => $match['home_team'],
|
|
'away_team' => $match['away_team'],
|
|
'home_sets' => (string) $match['home_sets'],
|
|
'away_sets' => (string) $match['away_sets'],
|
|
'referee_signature' => $signatures[0]['signer_name'] ?? '',
|
|
];
|
|
|
|
$items = [];
|
|
foreach ($fields as $key => $value) {
|
|
if (isset($template['fields'][$key])) {
|
|
$items[] = $this->box($template, $template['fields'][$key], $value);
|
|
}
|
|
}
|
|
foreach ($sets as $index => $set) {
|
|
if (!isset($template['result_rows'][$index], $template['result_columns'])) {
|
|
continue;
|
|
}
|
|
$row = $template['result_rows'][$index];
|
|
$cols = $template['result_columns'];
|
|
$items[] = $this->box($template, ['x' => $cols['home_pt']['x'], 'y' => $row['y'], 'w' => $cols['home_pt']['w'], 'size' => 11, 'align' => 'center'], (string) $set['home_points']);
|
|
$items[] = $this->box($template, ['x' => $cols['set']['x'], 'y' => $row['y'], 'w' => $cols['set']['w'], 'size' => 11, 'align' => 'center'], $set['home_points'] . ' - ' . $set['away_points']);
|
|
$items[] = $this->box($template, ['x' => $cols['away_pt']['x'], 'y' => $row['y'], 'w' => $cols['away_pt']['w'], 'size' => 11, 'align' => 'center'], (string) $set['away_points']);
|
|
}
|
|
if (!empty($template['home_players'])) {
|
|
$items = array_merge($items, $this->playerBoxes($template, $template['home_players'], $homePlayers));
|
|
}
|
|
if (!empty($template['away_players'])) {
|
|
$items = array_merge($items, $this->playerBoxes($template, $template['away_players'], $awayPlayers));
|
|
}
|
|
|
|
$image = htmlspecialchars($template['image'], ENT_QUOTES);
|
|
return '<!doctype html><html><head><meta charset="utf-8"><title>Planilla LTV 26</title>'
|
|
. '<style>@page{size:landscape;margin:0}body{margin:0;background:#e5e7eb;padding:16px}.sheet{position:relative;width:min(100%,'
|
|
. (int) $template['width'] . 'px);margin:0 auto;background:#fff;box-shadow:0 18px 60px rgba(15,23,42,.25)}.sheet-img{display:block;width:100%;height:auto}.txt{position:absolute;font-family:Arial,sans-serif;font-weight:700;color:#111;white-space:nowrap;overflow:hidden;line-height:1.1}.toolbar{position:fixed;right:16px;top:16px;z-index:3}.toolbar button{border:0;border-radius:6px;background:#16a34a;color:white;font-weight:800;padding:10px 14px}.missing{padding:24px;color:#991b1b;font-family:Arial;font-weight:700}@media print{body{background:#fff;padding:0}.sheet{width:100vw;max-width:none;box-shadow:none}.toolbar{display:none}}</style>'
|
|
. '</head><body><div class="toolbar"><button onclick="window.print()">Imprimir / PDF</button></div><main class="sheet">'
|
|
. '<img class="sheet-img" src="' . $image . '" alt="Planilla" onerror="this.insertAdjacentHTML(\'afterend\', \'<div class="missing">No se pudo cargar la imagen de plantilla: ' . $image . '</div>\'); this.remove();">'
|
|
. implode('', $items)
|
|
. '</main></body></html>';
|
|
}
|
|
|
|
private function box(array $template, array $box, string $value): string
|
|
{
|
|
$align = $box['align'] ?? 'left';
|
|
$valign = $box['valign'] ?? 'top';
|
|
$translate = match ($valign) {
|
|
'middle' => 'translateY(-50%)',
|
|
'bottom' => 'translateY(-100%)',
|
|
default => 'none',
|
|
};
|
|
$style = sprintf(
|
|
'left:%s%%;top:%s%%;width:%s%%;font-size:%spx;text-align:%s;transform:%s',
|
|
($box['x'] / $template['width']) * 100,
|
|
($box['y'] / $template['height']) * 100,
|
|
($box['w'] / $template['width']) * 100,
|
|
$box['size'],
|
|
$align,
|
|
$translate
|
|
);
|
|
return '<span class="txt" style="' . $style . '">' . htmlspecialchars($value) . '</span>';
|
|
}
|
|
|
|
private function playerBoxes(array $template, array $config, array $players): array
|
|
{
|
|
foreach (['x', 'y', 'row_h', 'number_w', 'name_w', 'size'] as $required) {
|
|
if (!isset($config[$required])) {
|
|
return [];
|
|
}
|
|
}
|
|
$items = [];
|
|
foreach (array_slice($players, 0, 14) as $index => $player) {
|
|
$y = $config['y'] + ($index * $config['row_h']);
|
|
$items[] = $this->box($template, ['x' => $config['x'], 'y' => $y, 'w' => $config['number_w'], 'size' => $config['size'], 'align' => 'center'], (string) ($player['jersey_number'] ?? ''));
|
|
$items[] = $this->box($template, ['x' => $config['x'] + $config['number_w'], 'y' => $y, 'w' => $config['name_w'], 'size' => $config['size']], $player['first_name'] . ' ' . $player['last_name']);
|
|
}
|
|
return $items;
|
|
}
|
|
|
|
private function match(\PDO $db, int $matchId): array
|
|
{
|
|
$stmt = $db->prepare(
|
|
'SELECT m.*, tr.name tournament_name, ht.name home_team, at.name away_team, c.name court_name
|
|
FROM matches m
|
|
JOIN tournaments tr ON tr.id = m.tournament_id
|
|
JOIN teams ht ON ht.id = m.home_team_id
|
|
JOIN teams at ON at.id = m.away_team_id
|
|
LEFT JOIN courts c ON c.id = m.court_id
|
|
WHERE m.id = :id'
|
|
);
|
|
$stmt->execute(['id' => $matchId]);
|
|
return $stmt->fetch() ?: [];
|
|
}
|
|
|
|
private function players(\PDO $db, int $teamId): array
|
|
{
|
|
$stmt = $db->prepare('SELECT * FROM players WHERE team_id = :id ORDER BY jersey_number, last_name');
|
|
$stmt->execute(['id' => $teamId]);
|
|
return $stmt->fetchAll();
|
|
}
|
|
|
|
private function rows(\PDO $db, string $sql, int $matchId): array
|
|
{
|
|
$stmt = $db->prepare($sql);
|
|
$stmt->execute(['id' => $matchId]);
|
|
return $stmt->fetchAll();
|
|
}
|
|
}
|