WIP: add LOL schedule via Lol Esport Official API #1

Draft
Superkooka wants to merge 4 commits from feat/league-of-legends-schedule into main
15 changed files with 68763 additions and 17 deletions
Showing only changes of commit 79903465b2 - Show all commits

View File

@ -21,9 +21,10 @@ services:
$handlers: !tagged_iterator 'app.usecase' $handlers: !tagged_iterator 'app.usecase'
App\Application\UseCase\: App\Application\UseCase\:
resource: '../src/Application/UseCase/' resource: '../src/Application/UseCase/**'
tags: ['app.usecase'] tags: ['app.usecase']
exclude: exclude:
- '../src/Application/UseCase/*Request.php' - '../src/Application/UseCase/**/*Request.php'
App\Application\LolEsportOfficialAPI\LolEsportOfficialAPIEngine: '@App\Infrastructure\LolEsportOfficialAPI\HTTPLolEsportOfficialAPI'
App\Application\SportRadar\SportRadarEngine: '@App\Infrastructure\SportRadar\HTTPSportRadarEngine' App\Application\SportRadar\SportRadarEngine: '@App\Infrastructure\SportRadar\HTTPSportRadarEngine'

View File

@ -2,4 +2,5 @@ imports:
- { resource: services.yaml } - { resource: services.yaml }
services: services:
App\Application\LolEsportOfficialAPI\LolEsportOfficialAPIEngine: '@App\Infrastructure\LolEsportOfficialAPI\FakeLolEsportOfficialAPIEngine'
App\Application\SportRadar\SportRadarEngine: '@App\Infrastructure\SportRadar\FakeSportRadarEngine' App\Application\SportRadar\SportRadarEngine: '@App\Infrastructure\SportRadar\FakeSportRadarEngine'

View File

@ -0,0 +1,27 @@
<?php
declare(strict_types=1);
namespace App\Application\LolEsportOfficialAPI;
interface LolEsportOfficialAPIEngine
{
public const string PROVIDER_ID = 'c07b7834-de0f-11f0-bcf1-8727592b333f';
/**
* @return array<{
* id: string,
* slug: string,
* name: string,
* code: string,
* status: string
* }>
*/
public function getTeams();
public function getLeagues();
public function getSeasons(); // "Tournament"
public function getSchedules();
}

View File

@ -8,6 +8,8 @@ use App\Domain\Enum\ENHLSeasonType;
interface SportRadarEngine interface SportRadarEngine
{ {
public const string PROVIDER_ID = '885fe581-c4c3-45e7-a06c-29ece7d47fad';
/** /**
* @return array{ * @return array{
* league: array{ * league: array{

View File

@ -0,0 +1,74 @@
<?php
namespace App\Application\UseCase\LeagueOfLegends;
use App\Application\LolEsportOfficialAPI\LolEsportOfficialAPIEngine;
use App\Application\ReadModel\Provider as ProviderRM;
use App\Application\ReadModel\Team as TeamRM;
use App\Domain\Entity\Provider;
use App\Domain\Entity\Team;
use Doctrine\ORM\EntityManagerInterface;
class FetchLolEsportOfficialAPISchedule
{
public function __construct(
private readonly LolEsportOfficialAPIEngine $lolEsportOfficialAPIEngine,
private readonly EntityManagerInterface $entityManager,
) {
}
public function __invoke(FetchLolEsportOfficialAPIScheduleRequest $request)
{
// This UseCase can not DELETE, Only INSERT or UPDATE
$provider = $this->entityManager->getRepository(Provider::class)->find(LolEsportOfficialAPIEngine::PROVIDER_ID);
if (null === $provider) {
$provider = new Provider(LolEsportOfficialAPIEngine::PROVIDER_ID);
$provider->create('LolEsportOfficialAPI');
$this->entityManager->persist($provider);
$this->entityManager->flush();
}
$providerRM = $this->entityManager->getRepository(ProviderRM::class)->find(LolEsportOfficialAPIEngine::PROVIDER_ID);
// Fetch Teams, make diff from db, disable if only on db, add if new
// team from api have unique id and code as alias. Match use code to identify teams
$lolEsportOfficialAPITeams = $this->lolEsportOfficialAPIEngine->getTeams();
$teamsRM = $this->entityManager->getRepository(TeamRM::class)->findBy(['providerId' => $providerRM->id]);
$teamsRMWithId = [];
foreach ($teamsRM as $team) {
$teamsRMWithId[$team->providerTeamId] = $team;
}
foreach ($lolEsportOfficialAPITeams as $team) {
if (!isset($teamsRMWithId[$team['id']])) {
// Create Team
$teamEntity = new Team();
$teamEntity->create(
$provider,
$team['id'],
$team['name'],
$team['code'],
'active' === $team['status'],
);
$this->entityManager->persist($teamEntity);
continue;
}
// check for active/renaming?
}
// Fetch League
// Fetch Season (Tournament). Need to be maped to a league from name if fetch all, can be fetch by league
// add endDate
// Fetch Match Schedule
// paginated. can be by league or global
// team are identify by code, not id
$this->entityManager->flush();
}
}

View File

@ -0,0 +1,7 @@
<?php
namespace App\Application\UseCase\LeagueOfLegends;
readonly class FetchLolEsportOfficialAPIScheduleRequest
{
}

View File

@ -2,7 +2,7 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\Application\UseCase; namespace App\Application\UseCase\NHL;
use App\Application\SportRadar\SportRadarEngine; use App\Application\SportRadar\SportRadarEngine;
use App\Domain\Entity\Game; use App\Domain\Entity\Game;
@ -12,7 +12,7 @@ use App\Domain\Entity\Team;
use App\Domain\Enum\ENHLSeasonType; use App\Domain\Enum\ENHLSeasonType;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
class FetchNHLMatch class FetchNHLSportRadarMatch
{ {
public function __construct( public function __construct(
private readonly SportRadarEngine $sportRadarEngine, private readonly SportRadarEngine $sportRadarEngine,
@ -20,11 +20,16 @@ class FetchNHLMatch
) { ) {
} }
public function __invoke(FetchNHLMatchRequest $request): void public function __invoke(FetchNHLSportRadarMatchRequest $request): void
{ {
$provider = $provider = $this->entityManager->getRepository(Provider::class)->find(SportRadarEngine::PROVIDER_ID);
$this->entityManager->getRepository(Provider::class)->findOneBy(['id' => '885fe581-c4c3-45e7-a06c-29ece7d47fad']) // id should not be here if (null === $provider) {
?? throw new \Exception('Provider not found'); $provider = new Provider();
$provider->create('SportRadar');
$this->entityManager->persist($provider);
}
$matchs = $this->sportRadarEngine->getNHLSchedule($request->year, ENHLSeasonType::from($request->type)); $matchs = $this->sportRadarEngine->getNHLSchedule($request->year, ENHLSeasonType::from($request->type));
$season = $season =

View File

@ -2,9 +2,9 @@
declare(strict_types=1); declare(strict_types=1);
namespace App\Application\UseCase; namespace App\Application\UseCase\NHL;
readonly class FetchNHLMatchRequest readonly class FetchNHLSportRadarMatchRequest
{ {
public function __construct( public function __construct(
public int $year, public int $year,

View File

@ -8,9 +8,9 @@ abstract class AEntity
{ {
protected string $id; protected string $id;
public function __construct() public function __construct(?string $id = null)
{ {
$this->id = $this->generateUUIDv4(); $this->id = $id ?? $this->generateUUIDv4();
} }
/** /**

View File

@ -0,0 +1,24 @@
<?php
namespace App\Infrastructure\Console;
use App\Application\CommandBus\UseCaseCommandBus;
use App\Application\UseCase\LeagueOfLegends\FetchLolEsportOfficialAPIScheduleRequest;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
#[AsCommand(name: 'app:fetch-schedule:lol:lolesport-official-api')]
class FetchLolEsportOfficialAPIScheduleCommand
{
public function __construct(
private readonly UseCaseCommandBus $commandBus,
) {
}
public function __invoke(): int
{
$this->commandBus->ask(new FetchLolEsportOfficialAPIScheduleRequest());
return Command::SUCCESS;
}
}

View File

@ -3,12 +3,12 @@
namespace App\Infrastructure\Console; namespace App\Infrastructure\Console;
use App\Application\CommandBus\UseCaseCommandBus; use App\Application\CommandBus\UseCaseCommandBus;
use App\Application\UseCase\FetchNHLMatchRequest; use App\Application\UseCase\NHL\FetchNHLSportRadarMatchRequest;
use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Command\Command;
#[AsCommand(name: 'app:get-nhl-schedule')] #[AsCommand(name: 'app:fetch-schedule:nhl:sportradar')]
class GetNHLScheduleCommand class FetchNHLSportRadarCommand
{ {
public function __construct( public function __construct(
private readonly UseCaseCommandBus $commandBus, private readonly UseCaseCommandBus $commandBus,
@ -17,7 +17,7 @@ class GetNHLScheduleCommand
public function __invoke(): int public function __invoke(): int
{ {
$this->commandBus->ask(new FetchNHLMatchRequest(2025, 'REG')); $this->commandBus->ask(new FetchNHLSportRadarMatchRequest(2025, 'REG'));
return Command::SUCCESS; return Command::SUCCESS;
} }

View File

@ -0,0 +1,38 @@
<?php
declare(strict_types=1);
namespace App\Infrastructure\LolEsportOfficialAPI;
use App\Application\LolEsportOfficialAPI\LolEsportOfficialAPIEngine;
class FakeLolEsportOfficialAPIEngine implements LolEsportOfficialAPIEngine
{
public function getTeams(): array
{
$fake_lolesport_official_api_lol_teams = json_decode(file_get_contents(__DIR__ . '/Fixtures/lolesport_official_api_lol_teams_21_12_2025.json'), true);
return array_map(fn ($team) => [
"id" => $team["id"],
"slug" => $team["slug"],
"name" => $team["name"],
"code" => $team["code"],
"status" => $team["status"],
], $fake_lolesport_official_api_lol_teams["data"]["teams"]);
}
public function getLeagues()
{
// TODO: Implement getLeagues() method.
}
public function getSeasons()
{
// TODO: Implement getSeasons() method.
}
public function getSchedules()
{
// TODO: Implement getSchedules() method.
}
}

View File

@ -0,0 +1,28 @@
<?php
namespace App\Infrastructure\LolEsportOfficialAPI;
use App\Application\LolEsportOfficialAPI\LolEsportOfficialAPIEngine;
class HTTPLolEsportOfficialAPIEngine implements LolEsportOfficialAPIEngine
{
public function getTeams()
{
// TODO: Implement getTeams() method.
}
public function getLeagues()
{
// TODO: Implement getLeagues() method.
}
public function getSeasons()
{
// TODO: Implement getSeasons() method.
}
public function getSchedules()
{
// TODO: Implement getSchedules() method.
}
}

View File

@ -15,7 +15,7 @@ $builder
->build(); ->build();
$builder $builder
->createField('providerTeamId', 'uuid') ->createField('providerTeamId', 'string')
->columnName('provider_team_id') ->columnName('provider_team_id')
->nullable(false) ->nullable(false)
->build(); ->build();