diff --git a/grumphp.yml b/grumphp.yml index 13c9ae95..674d3a44 100644 --- a/grumphp.yml +++ b/grumphp.yml @@ -13,7 +13,7 @@ grumphp: phpstan: autoload_file: phpstan.neon configuration: ~ - memory_limit: "512M" + memory_limit: "256M" phpunit: ~ phpversion: project: '8.4' diff --git a/src/Application/Command/Keyforge/Deck/GenerateAlliances/GenerateDeckAlliancesCommand.php b/src/Application/Command/Keyforge/Deck/GenerateAlliances/GenerateDeckAlliancesCommand.php index 3a0d0d49..495d0f95 100644 --- a/src/Application/Command/Keyforge/Deck/GenerateAlliances/GenerateDeckAlliancesCommand.php +++ b/src/Application/Command/Keyforge/Deck/GenerateAlliances/GenerateDeckAlliancesCommand.php @@ -7,24 +7,47 @@ final readonly class GenerateDeckAlliancesCommand { - private(set) array $deckIds; - private(set) array $deckHouses; + private(set) array $decks; + private(set) ?string $extraCardType; + private(set) ?string $extraCards; + private(set) bool $addToMyDecks; + private(set) bool $addToOwnedDok; - public function __construct($deckIds, $deckHouses) + public function __construct($decks, $extraCardType, $extraCards, $addToMyDecks, $addToOwnedDok) { Assert::lazy() - ->that($deckIds, 'deckIds')->all()->uuid() - ->that($deckHouses, 'deckHouses')->isArray() + ->that($decks, 'decks')->all()->isArray() + ->that($extraCardType, 'extraCardType')->nullOr()->inArray(['Token', 'Prophecies']) + ->that($extraCards, 'extraCards')->nullOr()->string()->notBlank() + ->that($addToMyDecks, 'addToMyDecks')->boolean() + ->that($addToOwnedDok, 'addToOwnedDok')->boolean() ->verifyNow(); - foreach ($deckHouses as $index => $item) { + foreach ($decks as $id => $houses) { Assert::lazy() - ->that($index)->uuid() - ->that($item)->all()->inArray(KeyforgeHouse::values()) + ->that($id)->uuid() + ->that($houses)->all()->inArray(KeyforgeHouse::values()) ->verifyNow(); + + if (0 === count($houses)) { + unset($decks[$id]); + } } - $this->deckIds = $deckIds; - $this->deckHouses = $deckHouses; + $this->decks = $decks; + $this->extraCardType = $extraCardType; + $this->extraCards = $extraCards; + $this->addToMyDecks = $addToMyDecks; + $this->addToOwnedDok = $addToOwnedDok; + } + + public function deckIds(): array + { + return array_keys($this->decks); + } + + public function housesOf(string $deckId): array + { + return $this->decks[$deckId] ?? []; } } diff --git a/src/Application/Command/Keyforge/Deck/GenerateAlliances/GenerateDeckAlliancesCommandHandler.php b/src/Application/Command/Keyforge/Deck/GenerateAlliances/GenerateDeckAlliancesCommandHandler.php index 679e18b7..74323062 100644 --- a/src/Application/Command/Keyforge/Deck/GenerateAlliances/GenerateDeckAlliancesCommandHandler.php +++ b/src/Application/Command/Keyforge/Deck/GenerateAlliances/GenerateDeckAlliancesCommandHandler.php @@ -5,7 +5,9 @@ use AdnanMula\Cards\Domain\Model\Keyforge\Deck\KeyforgeDeck; use AdnanMula\Cards\Domain\Model\Keyforge\Deck\KeyforgeDeckAllianceRepository; use AdnanMula\Cards\Domain\Model\Keyforge\Deck\KeyforgeDeckRepository; +use AdnanMula\Cards\Domain\Model\Keyforge\Deck\ValueObject\KeyforgeDeckType; use AdnanMula\Cards\Domain\Model\Shared\User; +use AdnanMula\Cards\Domain\Model\Shared\ValueObject\Link; use AdnanMula\Cards\Domain\Model\Shared\ValueObject\UserRole; use AdnanMula\Cards\Domain\Model\Shared\ValueObject\Uuid; use AdnanMula\Cards\Domain\Service\Keyforge\ImportDeckAllianceService; @@ -16,6 +18,7 @@ use AdnanMula\Criteria\Filter\FilterType; use AdnanMula\Criteria\FilterField\FilterField; use AdnanMula\Criteria\FilterValue\StringArrayFilterValue; +use AdnanMula\Criteria\FilterValue\StringFilterValue; use Symfony\Bundle\SecurityBundle\Security; use Symfony\Component\HttpFoundation\Request; use Symfony\Contracts\HttpClient\HttpClientInterface; @@ -42,18 +45,16 @@ public function __invoke(GenerateDeckAlliancesCommand $command): array $decks = $this->deckRepository->search(new Criteria( new Filters( FilterType::AND, - new Filter(new FilterField('id'), new StringArrayFilterValue(...$command->deckIds), FilterOperator::IN), + new Filter(new FilterField('id'), new StringArrayFilterValue(...$command->deckIds()), FilterOperator::IN), ), )); - if (\count($decks) !== \count(array_unique($command->deckIds))) { - throw new \Exception('Missing deck'); - } + $this->validations($command, ...$decks); - $this->validations(...$decks); + $pods = $this->pods($command, ...$decks); + $combinations = $this->combinations($command, $pods, $command->addToOwnedDok); - $pods = $this->pods($command->deckHouses, ...$decks); - $combinations = $this->combinations($pods); + $importedDecks = []; $authToken = $this->login(); @@ -65,9 +66,24 @@ public function __invoke(GenerateDeckAlliancesCommand $command): array $combination['houseTwo'], $combination['houseThreeDeckId'], $combination['houseThree'], + $command->extraCardType, + $command->extraCards, ); - if ($isAlreadyImported) { + if (null !== $isAlreadyImported) { + $deck = $this->deckRepository->searchOne(new Criteria( + new Filters( + FilterType::AND, + new Filter(new FilterField('id'), new StringFilterValue($isAlreadyImported), FilterOperator::EQUAL), + ), + )); + + $importedDecks[] = [ + 'id' => $isAlreadyImported, + 'url' => Link::dokDeckFromId(KeyforgeDeckType::ALLIANCE, Uuid::from($isAlreadyImported)), + 'deck' => $deck, + ]; + continue; } @@ -79,9 +95,16 @@ public function __invoke(GenerateDeckAlliancesCommand $command): array 'json' => $combination, ]); - $this->importDeckAllianceService->execute(Uuid::from(\str_replace('"', '', $response->getContent())), $user->id()); + $importedDeckId = Uuid::from(\str_replace('"', '', $response->getContent())); + $importedDeck = $this->importDeckAllianceService->execute($importedDeckId, $command->addToMyDecks ? $user->id() : null); $this->deckRepository->commit(); $this->deckRepository->beginTransaction(); + + $importedDecks[] = [ + 'id' => $importedDeckId->value(), + 'url' => Link::dokDeckFromId(KeyforgeDeckType::ALLIANCE, $importedDeckId), + 'deck' => $importedDeck, + ]; } catch (\Throwable) { throw new \Exception('Error desconocido'); } @@ -89,33 +112,34 @@ public function __invoke(GenerateDeckAlliancesCommand $command): array return [ 'combinations' => \count($combinations), + 'decks' => $importedDecks, ]; } - private function validations(?KeyforgeDeck ...$decks): void + private function validations(GenerateDeckAlliancesCommand $command, ?KeyforgeDeck ...$decks): void { + if (\count($decks) !== \count($command->deckIds())) { + throw new \Exception('Missing deck'); + } + if (0 === \count($decks)) { throw new \Exception('Deck error'); } foreach ($decks as $deck) { - if (null === $deck) { - throw new \Exception('Deck error'); - } - if ($deck->set() !== $decks[0]->set()) { throw new \Exception('Set error'); } } } - private function pods(array $houses, KeyforgeDeck ...$decks): array + private function pods(GenerateDeckAlliancesCommand $command, KeyforgeDeck ...$decks): array { $pods = []; foreach ($decks as $deck) { foreach ($deck->houses()->value() as $house) { - if (false === \in_array($house->value, $houses[$deck->id()->value()] ?? [], true)) { + if (false === \in_array($house->value, $command->housesOf($deck->id()->value()), true)) { continue; } @@ -129,7 +153,7 @@ private function pods(array $houses, KeyforgeDeck ...$decks): array return $pods; } - private function combinations(array $data): array + private function combinations(GenerateDeckAlliancesCommand $command, array $data, bool $addToOwned): array { $count = \count($data); @@ -153,15 +177,25 @@ private function combinations(array $data): array $isNotSameDeck = $id1 !== $id2 || $id1 !== $id3 || $id2 !== $id3; if ($isNotDuplicate && $isNotSameDeck) { - $combinations[] = [ + $combination = [ 'houseOne' => $data[$i]['house'], 'houseOneDeckId' => $data[$i]['id'], 'houseTwo' => $data[$j]['house'], 'houseTwoDeckId' => $data[$j]['id'], 'houseThree' => $data[$k]['house'], 'houseThreeDeckId' => $data[$k]['id'], - 'owned' => true, + 'owned' => $addToOwned, ]; + + if ('Token' === $command->extraCardType) { + $combination['tokenName'] = $command->extraCards; + } + + if ('Prophecies' === $command->extraCardType) { + $combination['propheciesDeckId'] = $command->extraCards; + } + + $combinations[] = $combination; } } } diff --git a/src/Domain/Model/Keyforge/Deck/KeyforgeDeckAllianceRepository.php b/src/Domain/Model/Keyforge/Deck/KeyforgeDeckAllianceRepository.php index cb022d42..22ad83df 100644 --- a/src/Domain/Model/Keyforge/Deck/KeyforgeDeckAllianceRepository.php +++ b/src/Domain/Model/Keyforge/Deck/KeyforgeDeckAllianceRepository.php @@ -7,5 +7,5 @@ interface KeyforgeDeckAllianceRepository { public function saveComposition(Uuid $id, array $composition): void; - public function isAlreadyImported(string $id1, string $house1, string $id2, string $house2, string $id3, string $house3): bool; + public function isAlreadyImported(string $id1, string $house1, string $id2, string $house2, string $id3, string $house3, string $extraCardType, string $extraCard): ?string; } diff --git a/src/Domain/Model/Shared/ValueObject/Link.php b/src/Domain/Model/Shared/ValueObject/Link.php new file mode 100644 index 00000000..c357a95a --- /dev/null +++ b/src/Domain/Model/Shared/ValueObject/Link.php @@ -0,0 +1,32 @@ +url(); + + return new static($value); + } + + public static function dokDeckFromId(KeyforgeDeckType $type, Uuid $uuid): static + { + $domain = match ($type) { + KeyforgeDeckType::STANDARD => self::DECK_REGULAR, + KeyforgeDeckType::ALLIANCE => self::DECK_ALLIANCE, + KeyforgeDeckType::THEORETICAL => self::DECK_THEORETICAL, + }; + + return self::from(self::HTTPS . $domain . $uuid->value()); + } +} diff --git a/src/Entrypoint/Controller/Keyforge/Deck/Alliance/GenerateAlliancesController.php b/src/Entrypoint/Controller/Keyforge/Deck/Alliance/GenerateAlliancesController.php index 5c459880..45f6cd89 100644 --- a/src/Entrypoint/Controller/Keyforge/Deck/Alliance/GenerateAlliancesController.php +++ b/src/Entrypoint/Controller/Keyforge/Deck/Alliance/GenerateAlliancesController.php @@ -24,9 +24,20 @@ public function __invoke(Request $request): Response try { $payload = Json::decode($request->getContent()); - $this->bus->dispatch(new GenerateDeckAlliancesCommand($payload['decks'], $payload['houses'])); - - return new JsonResponse(['success' => true]); + $result = $this->extractResult( + $this->bus->dispatch(new GenerateDeckAlliancesCommand( + $payload['decks'], + $payload['extraCardType'], + $payload['extraCard'], + $payload['addToMyDecks'], + $payload['addToOwnedDok'], + )), + ); + + return new JsonResponse([ + 'success' => true, + 'result' => $result, + ]); } catch (InvalidUuidStringException) { return new JsonResponse(['error' => 'Invalid uuid']); } catch (\Throwable $e) { diff --git a/src/Entrypoint/Controller/Keyforge/Deck/Alliance/generate_alliances.html.twig b/src/Entrypoint/Controller/Keyforge/Deck/Alliance/generate_alliances.html.twig index 8b9148e9..892519f7 100644 --- a/src/Entrypoint/Controller/Keyforge/Deck/Alliance/generate_alliances.html.twig +++ b/src/Entrypoint/Controller/Keyforge/Deck/Alliance/generate_alliances.html.twig @@ -18,151 +18,326 @@
-
-
-
-
-
- -
- - - - - - -
- -
- - -
- - - - - - -
- -
- - -
- - - - - - -
- -
- - +
+ +
+ + +
+
+ + +
+ +
+ + +
+
+
+ + +
+ +
+ +
-
- + + +
{% endblock %} diff --git a/src/Entrypoint/Controller/Keyforge/Deck/Detail/deck.html.twig b/src/Entrypoint/Controller/Keyforge/Deck/Detail/deck.html.twig index a5b88ce8..c5daf443 100644 --- a/src/Entrypoint/Controller/Keyforge/Deck/Detail/deck.html.twig +++ b/src/Entrypoint/Controller/Keyforge/Deck/Detail/deck.html.twig @@ -76,7 +76,7 @@
{% if deck.type == 'ALLIANCE' %} {% endif %} diff --git a/src/Entrypoint/Controller/Shared/Admin/admin.html.twig b/src/Entrypoint/Controller/Shared/Admin/admin.html.twig index df0fc283..791fc21a 100644 --- a/src/Entrypoint/Controller/Shared/Admin/admin.html.twig +++ b/src/Entrypoint/Controller/Shared/Admin/admin.html.twig @@ -35,10 +35,7 @@
-

Alliance Gen

-
-
diff --git a/src/Infrastructure/Persistence/Repository/Keyforge/Deck/KeyforgeDeckAllianceDbalRepository.php b/src/Infrastructure/Persistence/Repository/Keyforge/Deck/KeyforgeDeckAllianceDbalRepository.php index 1fe3a3a7..e89f4a60 100644 --- a/src/Infrastructure/Persistence/Repository/Keyforge/Deck/KeyforgeDeckAllianceDbalRepository.php +++ b/src/Infrastructure/Persistence/Repository/Keyforge/Deck/KeyforgeDeckAllianceDbalRepository.php @@ -26,33 +26,61 @@ public function saveComposition(Uuid $id, array $composition): void $stmt->executeStatement(); } - public function isAlreadyImported(string $id1, string $house1, string $id2, string $house2, string $id3, string $house3): bool + public function isAlreadyImported(string $id1, string $house1, string $id2, string $house2, string $id3, string $house3, ?string $extraCardType, ?string $extraCard): ?string { - $stmt = $this->connection->prepare( - \sprintf( - "SELECT id FROM %s + $query = \sprintf( + "SELECT id FROM %s WHERE EXISTS ( SELECT 1 - FROM jsonb_array_elements(alliance_composition) AS elem + FROM jsonb_array_elements(alliance_composition->'pods') AS elem WHERE elem->>'keyforgeId' = :id1 AND elem->>'house' = :house1 ) AND EXISTS ( SELECT 1 - FROM jsonb_array_elements(alliance_composition) AS elem + FROM jsonb_array_elements(alliance_composition->'pods') AS elem WHERE elem->>'keyforgeId' = :id2 AND elem->>'house' = :house2 ) AND EXISTS ( SELECT 1 - FROM jsonb_array_elements(alliance_composition) AS elem + FROM jsonb_array_elements(alliance_composition->'pods') AS elem WHERE elem->>'keyforgeId' = :id3 AND elem->>'house' = :house3 - );", - self::TABLE, - ), + )", + self::TABLE, ); + if ($extraCardType === 'Token' && $extraCard !== null) { + $query .= " AND EXISTS ( + SELECT 1 + FROM jsonb_array_elements(alliance_composition->'extraCards') AS elem + WHERE elem->>'name' = :extraCard + )"; + } + + if ($extraCardType === 'Prophecies' && $extraCard !== null) { + $query .= " AND EXISTS ( + SELECT 1 + FROM jsonb_array_elements(alliance_composition->'extraCards') AS elem + WHERE elem->>'name' = :prophecy1 + ) AND EXISTS ( + SELECT 1 + FROM jsonb_array_elements(alliance_composition->'extraCards') AS elem + WHERE elem->>'name' = :prophecy2 + ) AND EXISTS ( + SELECT 1 + FROM jsonb_array_elements(alliance_composition->'extraCards') AS elem + WHERE elem->>'name' = :prophecy3 + ) AND EXISTS ( + SELECT 1 + FROM jsonb_array_elements(alliance_composition->'extraCards') AS elem + WHERE elem->>'name' = :prophecy4 + )"; + } + + $stmt = $this->connection->prepare($query); + $stmt->bindValue('id1', $id1); $stmt->bindValue('house1', $house1); $stmt->bindValue('id2', $id2); @@ -60,6 +88,25 @@ public function isAlreadyImported(string $id1, string $house1, string $id2, stri $stmt->bindValue('id3', $id3); $stmt->bindValue('house3', $house3); - return false !== $stmt->executeQuery()->fetchOne(); + if ($extraCardType === 'Token' && $extraCard !== null) { + $stmt->bindValue('extraCard', $extraCard); + } + + if ($extraCardType === 'Prophecies' && $extraCard !== null) { + $propheciesStmt = $this->connection->prepare("SELECT cards FROM keyforge_decks WHERE id = :id"); + $propheciesStmt->bindValue('id', $extraCard); + $prophecies = json_decode($propheciesStmt->executeQuery()->fetchOne(), true)['extraCards']; + + $stmt->bindValue('prophecy1', $prophecies[0]['name']);; + $stmt->bindValue('prophecy2', $prophecies[0]['name']);; + $stmt->bindValue('prophecy3', $prophecies[0]['name']);; + $stmt->bindValue('prophecy4', $prophecies[0]['name']);; + } + + $result = $stmt->executeQuery()->fetchOne(); + + return false === $result + ? null + : $result; } } diff --git a/src/Infrastructure/Service/Keyforge/DoK/ImportDeckAllianceFromDokService.php b/src/Infrastructure/Service/Keyforge/DoK/ImportDeckAllianceFromDokService.php index 6df4ee7b..b5611fcd 100644 --- a/src/Infrastructure/Service/Keyforge/DoK/ImportDeckAllianceFromDokService.php +++ b/src/Infrastructure/Service/Keyforge/DoK/ImportDeckAllianceFromDokService.php @@ -78,7 +78,10 @@ public function execute(Uuid $uuid, ?Uuid $owner = null, bool $forceUpdate = fal $this->repository->save($newDeck); - $this->allianceRepository->saveComposition($newDeck->id(), $deckResponse['deck']['allianceHouses']); + $this->allianceRepository->saveComposition($newDeck->id(), [ + 'pods' => $deckResponse['deck']['allianceHouses'], + 'extraCards' => $newDeck->cards()->extraCards, + ]); if (null !== $owner) { $this->repository->addOwner($newDeck->id(), $owner); diff --git a/translations/messages.en_GB.yaml b/translations/messages.en_GB.yaml index 2328077d..68a05e36 100644 --- a/translations/messages.en_GB.yaml +++ b/translations/messages.en_GB.yaml @@ -52,6 +52,7 @@ data.winrate: 'Win rate' data.wins: Wins deck.actions: Actions deck.add_to_my_decks: 'Add to my decks' +deck.add_to_owned_dok: 'Add to owned on DoK' deck.aerc: Aerc deck.amber_control: Amber control deck.antisynergy: Antisinergy @@ -209,9 +210,6 @@ menu.add_friends: 'Add friends' menu.add_my_deck: 'Add to my decks' menu.addgame: 'Register game' menu.admin: Admin -menu.admin_action_generate_home_projection: Regenerate home projection -menu.admin_action_generate_user_projection: Regenerate user projection -menu.admin_actions: Admin actions menu.admin_no_new_accounts: No pending accounts menu.all: All menu.any: Any @@ -446,6 +444,9 @@ menu.filters: Filters menu.predefined: Predefined menu.show: Show menu.other_filters: Other filters +menu.generate_alliances: Generate alliances +menu.view_deck: View deck +menu.dok: DoK wiki.tag_criteria.has_scaling_amber: Has cards that deny more Amber the more Amber the opponent has. wiki.tag_criteria.has_board_wipes: Has cards capable of clearing the board of creatures to varying degrees. wiki.tag_criteria.synergistic: An estimation of a deck’s overall quality; can help detect synergies and anti-synergies. @@ -478,6 +479,8 @@ menu.prophecies_activated: Prophecies activated menu.prophecies_fulfilled: Prophecies fulfilled menu.chains_obtained: Chains obtained menu.fates_resolved: Fates resolved +menu.select_token: Select a token +menu.select_prophecies: Select prophecies game.timeline.extra_turn: To take an extra turn after this one deck.archon-power: Archon Power deck.prophecy: Prophecy diff --git a/translations/messages.es_ES.yaml b/translations/messages.es_ES.yaml index d28be90c..a1e0affc 100644 --- a/translations/messages.es_ES.yaml +++ b/translations/messages.es_ES.yaml @@ -52,6 +52,7 @@ data.winrate: 'Win rate' data.wins: Victorias deck.actions: Acciones deck.add_to_my_decks: 'Añadir a mis barajas' +deck.add_to_owned_dok: 'Añadir a owned en DoK' deck.aerc: Aerc deck.amber_control: Control de ámbar deck.antisynergy: Antisinergia @@ -209,9 +210,6 @@ menu.add_friends: 'Añadir amigos' menu.add_my_deck: 'Añadir a mis barajas' menu.addgame: 'Registrar partida' menu.admin: Admin -menu.admin_action_generate_home_projection: Regenerar proyección de página principal -menu.admin_action_generate_user_projection: Regenerar proyección de usuario -menu.admin_actions: Acciones de admin menu.admin_no_new_accounts: Ninguna cuenta pendiente menu.all: Todas menu.any: Cualquiera @@ -446,6 +444,9 @@ menu.filters: Filtros menu.predefined: Predefinidas menu.show: Mostrar menu.other_filters: Otros filtros +menu.generate_alliances: Generar alianzas +menu.view_deck: Ver baraja +menu.dok: DoK wiki.tag_criteria.has_scaling_amber: Tiene cartas permiten denegar más ámbar cuanto más tiene el rival wiki.tag_criteria.has_board_wipes: Tiene cartas capacez de limpiar el tablero de criaturas en mayor o menor medida wiki.tag_criteria.synergistic: Aproximación de la calidad de una baraja, puede ayudar a detectar sinérgias y antisinérgias. @@ -474,10 +475,12 @@ menu.leave: Salir menu.extra_turns: Turnos extra menu.tokens_created: Tokens creados menu.tides_raised: Mareas subidas -menu.prophecies_activated: Profecias activadas -menu.prophecies_fulfilled: Profecias cumplidas +menu.prophecies_activated: Profecías activadas +menu.prophecies_fulfilled: Profecías cumplidas menu.chains_obtained: Cadenas obtenidas menu.fates_resolved: Destinos resueltos +menu.select_token: Selecciona un token +menu.select_prophecies: Selecciona profecías game.timeline.extra_turn: Para tomar un turno adicional después de este deck.archon-power: Archon Power deck.prophecy: Profecía