chg: dev: create the UserStats entity what is a Materialized View to store Profile stats for every user - & massive ProfileController refactor #8

This commit is contained in:
2026-04-20 20:44:33 +02:00
parent 6be0d52fb7
commit 6a5ba84b5e
13 changed files with 827 additions and 502 deletions
+105
View File
@@ -0,0 +1,105 @@
<?php declare(strict_types=1);
/**
* This file is part of the SplendidBear Websites' projects.
*
* Copyright (c) 2026 @ www.splendidbear.org
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace App\Dto;
use App\Entity\PlayedGame;
/**
* Class BattleShareDto
*
* @package App\Dto
* @author Lang <https://www.splendidbear.org>
* @category Class
* @license https://www.gnu.org/licenses/lgpl-3.0.en.html GNU Lesser General Public License
* @link www.splendidbear.org
* @since 2026. 04. 20.
*/
final readonly class BattleShareDto
{
public function __construct(
public PlayedGame $game,
public string $redName,
public string $blueName,
public ?int $redPts,
public ?int $bluePts,
public ?string $resign,
public ?string $redAvatar,
public ?string $blueAvatar,
public float $redBonusPoints,
public float $blueBonusPoints,
public array $redBonusStats,
public array $blueBonusStats,
public string $ogTitle,
public string $ogDesc,
) {
}
public static function fromPlayedGame(PlayedGame $game): self
{
$redName = $game->red?->getUsername() ?? ($game->redAnon !== null ? 'Anonymous' : 'Guest');
$blueName = $game->blue?->getUsername() ?? ($game->blueAnon !== null ? 'Anonymous' : 'Guest');
$redPts = $game->redPoints;
$bluePts = $game->bluePoints;
$resign = $game->resign;
$summary = self::buildSummary($redName, $blueName, $redPts, $bluePts, $resign);
return new self(
game: $game,
redName: $redName,
blueName: $blueName,
redPts: $redPts,
bluePts: $bluePts,
resign: $resign,
redAvatar: $game->red?->avatarPath,
blueAvatar: $game->blue?->avatarPath,
redBonusPoints: (float)($game->redBonusPoints ?? 0),
blueBonusPoints: (float)($game->blueBonusPoints ?? 0),
redBonusStats: $game->redBonusStats ?? [],
blueBonusStats: $game->blueBonusStats ?? [],
ogTitle: "MineSeeker · $summary",
ogDesc: "Watch the battle replay: $summary — played on MineSeeker, the multiplayer minesweeper.",
);
}
private static function buildSummary(
string $redName,
string $blueName,
?int $redPts,
?int $bluePts,
?string $resign,
): string {
if ($resign === 'red') {
return "$redName resigned — $blueName wins";
}
if ($resign === 'blue') {
return "$blueName resigned — $redName wins";
}
if ($redPts !== null && $bluePts !== null) {
if ($redPts > $bluePts) {
return "$redName defeated $blueName ($redPts $bluePts)";
}
if ($bluePts > $redPts) {
return "$blueName defeated $redName ($bluePts $redPts)";
}
return "$redName and $blueName drew ($redPts $bluePts)";
}
return "$redName vs $blueName";
}
public function toTemplateContext(): array
{
return get_object_vars($this);
}
}