...
This commit is contained in:
parent
366935846c
commit
4bf3bbb978
8 changed files with 348 additions and 2 deletions
10
composer.json
Normal file
10
composer.json
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"name": "torsten/tippspiel2027",
|
||||
"description": "Nachfolgeprojekt von tippspiel in Pure PHP",
|
||||
"type": "project",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"App\\": "src/"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +1,56 @@
|
|||
<?php
|
||||
|
||||
// Einfaches Routing (Microframework / Pure PHP) für tippspiel2027
|
||||
// Dies stellt sicher, dass der Code maximal lesbar und zukunftssicher bleibt.
|
||||
// Lade den minimalistischen Autoloader
|
||||
require_once __DIR__ . '/../src/autoload.php';
|
||||
|
||||
use App\Core\Database;
|
||||
use App\Models\Game;
|
||||
use App\Models\Tipp;
|
||||
|
||||
$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
|
||||
|
||||
if ($uri === '/' || $uri === '/index.php') {
|
||||
echo "<h1>Willkommen bei Tippspiel 2027</h1>";
|
||||
echo "<p>Dies ist die Nachfolgeversion des alten Tippspiels (Pure PHP Variante).</p>";
|
||||
|
||||
try {
|
||||
$db = Database::getConnection();
|
||||
$userCount = $db->query("SELECT COUNT(*) FROM users")->fetchColumn();
|
||||
echo "<p>Datenbank verbunden! Aktuell <strong>$userCount</strong> User im System.</p>";
|
||||
|
||||
echo "<h2>Portierte Backend-Logik (Test)</h2>";
|
||||
|
||||
// 1. Test der Score-Berechnung (getScoreLocal Logik aus Tipp.php)
|
||||
echo "<h3>Punkteberechnung</h3>";
|
||||
$scoreTest = Tipp::getScoreLocal(2, 1, 2, 1, true); // Ergebnis: 2:1, Tipp: 2:1 (mit Joker)
|
||||
echo "<p>Test: Spiel endet 2:1, getippt wurde 2:1 mit Joker. Erwartet: 4 Punkte. <strong>Berechnet: $scoreTest Punkte</strong>.</p>";
|
||||
|
||||
// 2. Test der Spiel-Logiken
|
||||
echo "<h3>Spiele der letzten gespielten Runde</h3>";
|
||||
|
||||
// Finde zunächst die ID der letzten gespielten Runde (wo es Ergebnisse gibt)
|
||||
$lastRoundId = $db->query("SELECT round_id FROM games WHERE score1 > -1 ORDER BY id DESC LIMIT 1")->fetchColumn();
|
||||
|
||||
if ($lastRoundId) {
|
||||
// Hole alle Spiele exakt dieser Runde
|
||||
$games = Game::getGamesByRound($lastRoundId);
|
||||
|
||||
if ($games) {
|
||||
echo "<ul>";
|
||||
foreach ($games as $g) {
|
||||
$status = Game::getResultString($g['score1'], $g['score2'], $g['kickoff']);
|
||||
$locked = Game::isLocked($g['kickoff']) ? "Gesperrt" : "Offen";
|
||||
echo "<li>" . htmlspecialchars($g['team1'] . " vs " . $g['team2']) . " | Status: $status | $locked</li>";
|
||||
}
|
||||
echo "</ul>";
|
||||
}
|
||||
} else {
|
||||
echo "<p>Keine gespielten Spiele gefunden.</p>";
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
echo "<p style='color:red;'>Datenbankfehler: " . $e->getMessage() . "</p>";
|
||||
}
|
||||
} elseif ($uri === '/api/status') {
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode(['status' => 'ok', 'version' => '2027.1']);
|
||||
|
|
|
|||
60
schema.sql
60
schema.sql
|
|
@ -1,3 +1,4 @@
|
|||
DROP TABLE IF EXISTS `users`;
|
||||
CREATE TABLE `users` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(201) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
|
|
@ -19,6 +20,7 @@ CREATE TABLE `users` (
|
|||
UNIQUE KEY `users_email_unique` (`email`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
DROP TABLE IF EXISTS `tipps`;
|
||||
CREATE TABLE `tipps` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`user_id` int(11) NOT NULL,
|
||||
|
|
@ -31,6 +33,7 @@ CREATE TABLE `tipps` (
|
|||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
DROP TABLE IF EXISTS `games`;
|
||||
CREATE TABLE `games` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`round_id` int(11) NOT NULL,
|
||||
|
|
@ -44,6 +47,7 @@ CREATE TABLE `games` (
|
|||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
DROP TABLE IF EXISTS `rounds`;
|
||||
CREATE TABLE `rounds` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
|
|
@ -54,6 +58,7 @@ CREATE TABLE `rounds` (
|
|||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
DROP TABLE IF EXISTS `seasons`;
|
||||
CREATE TABLE `seasons` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
|
|
@ -63,3 +68,58 @@ CREATE TABLE `seasons` (
|
|||
`updated_at` timestamp NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
DROP TABLE IF EXISTS `settings`;
|
||||
CREATE TABLE `settings` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`current_season_id` int(11) NOT NULL,
|
||||
`created_at` timestamp NULL DEFAULT NULL,
|
||||
`updated_at` timestamp NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
DROP TABLE IF EXISTS `payments`;
|
||||
CREATE TABLE `payments` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`season_id` int(11) NOT NULL,
|
||||
`user_id` int(11) NOT NULL,
|
||||
`paid_date` datetime DEFAULT NULL,
|
||||
`created_at` timestamp NULL DEFAULT NULL,
|
||||
`updated_at` timestamp NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
DROP TABLE IF EXISTS `quotas`;
|
||||
CREATE TABLE `quotas` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`season_id` int(11) NOT NULL DEFAULT '0',
|
||||
`name` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`order` int(11) NOT NULL DEFAULT '0',
|
||||
`prc` double NOT NULL DEFAULT '0',
|
||||
`created_at` timestamp NULL DEFAULT NULL,
|
||||
`updated_at` timestamp NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
DROP TABLE IF EXISTS `roundmails`;
|
||||
CREATE TABLE `roundmails` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`user_id` int(11) NOT NULL,
|
||||
`send_date` date NOT NULL,
|
||||
`recipients` text COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`topic` varchar(200) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`message` text COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`created_at` timestamp NULL DEFAULT NULL,
|
||||
`updated_at` timestamp NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
DROP TABLE IF EXISTS `manual_payouts`;
|
||||
CREATE TABLE `manual_payouts` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`season_id` int(11) NOT NULL,
|
||||
`user_id` int(11) NOT NULL,
|
||||
`quota_name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
|
|
|
|||
39
src/Core/Database.php
Normal file
39
src/Core/Database.php
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
namespace App\Core;
|
||||
|
||||
use PDO;
|
||||
use PDOException;
|
||||
|
||||
class Database {
|
||||
private static $instance = null;
|
||||
private $pdo;
|
||||
|
||||
private function __construct() {
|
||||
$host = getenv('DB_HOST') ?: '127.0.0.1';
|
||||
$user = getenv('DB_USER') ?: 'root';
|
||||
$pass = getenv('DB_PASS') ?: '';
|
||||
$dbName = getenv('DB_NEW_NAME') ?: 'tippspiel2027';
|
||||
|
||||
$dsn = "mysql:host=$host;dbname=$dbName;charset=utf8mb4";
|
||||
|
||||
try {
|
||||
$this->pdo = new PDO($dsn, $user, $pass);
|
||||
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
$this->pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
|
||||
} catch (PDOException $e) {
|
||||
die("Datenbankverbindung fehlgeschlagen: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public static function getInstance() {
|
||||
if (self::$instance === null) {
|
||||
self::$instance = new self();
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
public static function getConnection() {
|
||||
return self::getInstance()->pdo;
|
||||
}
|
||||
}
|
||||
57
src/Models/Game.php
Normal file
57
src/Models/Game.php
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Core\Database;
|
||||
use DateTime;
|
||||
use DateInterval;
|
||||
|
||||
class Game {
|
||||
|
||||
/**
|
||||
* Prüft ob ein Spiel bereits gelockt (Anpfiff steht kurz bevor) ist.
|
||||
* Portiert aus dem Laravel Game Modell: Lock war 1 Minute vor Anpfiff.
|
||||
*/
|
||||
public static function isLocked($kickoffTime) {
|
||||
$now = new DateTime();
|
||||
$kickoff = new DateTime($kickoffTime);
|
||||
|
||||
// 1 Minute vor Anpfiff wird gelockt
|
||||
$kickoff->sub(new DateInterval('PT1M'));
|
||||
|
||||
return $now >= $kickoff;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt einen formatierten String für das Ergebnis eines Spiels zurück
|
||||
*/
|
||||
public static function getResultString($score1, $score2, $kickoffTime) {
|
||||
if ($score1 > -1 && $score2 > -1) {
|
||||
return "$score1 : $score2";
|
||||
}
|
||||
|
||||
$now = new DateTime();
|
||||
$start = new DateTime($kickoffTime);
|
||||
$end = (clone $start)->add(new DateInterval('PT2H')); // ca. 2 Stunden nach Anpfiff
|
||||
|
||||
if ($start > $now) {
|
||||
return "-";
|
||||
}
|
||||
|
||||
if ($now > $start && $now < $end) {
|
||||
return "Läuft";
|
||||
}
|
||||
|
||||
return "(Eingeben)";
|
||||
}
|
||||
|
||||
/**
|
||||
* Holt alle Spiele einer Runde aus der Datenbank
|
||||
*/
|
||||
public static function getGamesByRound($roundId) {
|
||||
$db = Database::getConnection();
|
||||
$stmt = $db->prepare("SELECT * FROM games WHERE round_id = ? ORDER BY kickoff ASC");
|
||||
$stmt->execute([$roundId]);
|
||||
return $stmt->fetchAll();
|
||||
}
|
||||
}
|
||||
28
src/Models/Round.php
Normal file
28
src/Models/Round.php
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Core\Database;
|
||||
|
||||
class Round {
|
||||
|
||||
/**
|
||||
* Holt eine Runde anhand der ID
|
||||
*/
|
||||
public static function getById($id) {
|
||||
$db = Database::getConnection();
|
||||
$stmt = $db->prepare("SELECT * FROM rounds WHERE id = ?");
|
||||
$stmt->execute([$id]);
|
||||
return $stmt->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* Holt alle Runden einer Season
|
||||
*/
|
||||
public static function getBySeason($seasonId) {
|
||||
$db = Database::getConnection();
|
||||
$stmt = $db->prepare("SELECT * FROM rounds WHERE season_id = ? ORDER BY id ASC");
|
||||
$stmt->execute([$seasonId]);
|
||||
return $stmt->fetchAll();
|
||||
}
|
||||
}
|
||||
83
src/Models/Tipp.php
Normal file
83
src/Models/Tipp.php
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
class Tipp {
|
||||
|
||||
/**
|
||||
* Berechnet die Punkte für einen Tipp im Vergleich zum echten Ergebnis.
|
||||
* Portiert aus der alten Laravel-Anwendung.
|
||||
*
|
||||
* @param int $goals1 Tore Team 1
|
||||
* @param int $goals2 Tore Team 2
|
||||
* @param int $tipp1 Getippte Tore Team 1
|
||||
* @param int $tipp2 Getippte Tore Team 2
|
||||
* @param bool $joker Ob der Joker für diesen Tipp gesetzt wurde
|
||||
* @return int Die erreichten Punkte
|
||||
*/
|
||||
public static function getScoreLocal($goals1, $goals2, $tipp1, $tipp2, $joker) {
|
||||
$score = 0;
|
||||
|
||||
// Wenn noch kein Ergebnis vorliegt (-1 bedeutet in der DB meistens noch nicht gespielt)
|
||||
if ($tipp1 == -1 || $tipp2 == -1 || $goals1 == -1 || $goals2 == -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$tippTendenz = $tipp1 - $tipp2;
|
||||
if ($tippTendenz > 0) { $tippTendenz = 1; }
|
||||
if ($tippTendenz < 0) { $tippTendenz = -1; }
|
||||
|
||||
$gameTendenz = $goals1 - $goals2;
|
||||
if ($gameTendenz < 0) { $gameTendenz = -1; }
|
||||
if ($gameTendenz > 0) { $gameTendenz = 1; }
|
||||
|
||||
// Tendenz richtig
|
||||
if ($tippTendenz == $gameTendenz) {
|
||||
$score = 1;
|
||||
}
|
||||
|
||||
// Genaues Ergebnis richtig (gibt 2 Grundpunkte + Bonus)
|
||||
if (($tipp1 == $goals1) && ($tipp2 == $goals2)) {
|
||||
$bonus = max(0, $goals1 + $goals2 - 3);
|
||||
$score = 2 + $bonus;
|
||||
}
|
||||
|
||||
// Joker verdoppelt die Punktzahl
|
||||
if ($joker == true) {
|
||||
$score = $score * 2;
|
||||
}
|
||||
|
||||
return $score;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt das Styling/die Farbe für die Tendenz zurück (fürs Frontend)
|
||||
*/
|
||||
public static function getCol($goals1, $goals2, $tipp1, $tipp2, $joker) {
|
||||
if ($tipp1 == -1 || $tipp2 == -1 || $goals1 == -1 || $goals2 == -1) {
|
||||
return "";
|
||||
}
|
||||
|
||||
$tippTendenz = $tipp1 - $tipp2;
|
||||
if ($tippTendenz > 0) { $tippTendenz = 1; }
|
||||
if ($tippTendenz < 0) { $tippTendenz = -1; }
|
||||
|
||||
$gameTendenz = $goals1 - $goals2;
|
||||
if ($gameTendenz < 0) { $gameTendenz = -1; }
|
||||
if ($gameTendenz > 0) { $gameTendenz = 1; }
|
||||
|
||||
if ($tippTendenz != $gameTendenz) {
|
||||
return "";
|
||||
}
|
||||
|
||||
$styling = 'background-color:grey;';
|
||||
|
||||
if (($tipp1 == $goals1) && ($tipp2 == $goals2)) {
|
||||
$styling = 'background-color:orange;';
|
||||
if ($joker) {
|
||||
$styling = 'background-color:red';
|
||||
}
|
||||
}
|
||||
return $styling;
|
||||
}
|
||||
}
|
||||
26
src/autoload.php
Normal file
26
src/autoload.php
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
spl_autoload_register(function ($class) {
|
||||
// Projekt-Namespace Prefix
|
||||
$prefix = 'App\\';
|
||||
|
||||
// Basisverzeichnis für den Namespace Prefix
|
||||
$base_dir = __DIR__ . '/';
|
||||
|
||||
// Prüfen ob die Klasse das Prefix verwendet
|
||||
$len = strlen($prefix);
|
||||
if (strncmp($prefix, $class, $len) !== 0) {
|
||||
return; // Gehört nicht zu diesem Autoloader
|
||||
}
|
||||
|
||||
// Den relativen Klassennamen extrahieren
|
||||
$relative_class = substr($class, $len);
|
||||
|
||||
// Namespace-Trenner (\) durch Verzeichnis-Trenner (/) ersetzen und .php anhängen
|
||||
$file = $base_dir . str_replace('\\', '/', $relative_class) . '.php';
|
||||
|
||||
// Wenn die Datei existiert, einbinden
|
||||
if (file_exists($file)) {
|
||||
require $file;
|
||||
}
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue