parent
d76534d6a3
commit
6ba77d3cec
@ -1,112 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace DoctrineMigrations;
|
|
||||||
|
|
||||||
use Doctrine\DBAL\Schema\Schema;
|
|
||||||
use Doctrine\Migrations\AbstractMigration;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Auto-generated Migration: Please modify to your needs!
|
|
||||||
*/
|
|
||||||
final class Version20240219220159 extends AbstractMigration
|
|
||||||
{
|
|
||||||
public function getDescription(): string
|
|
||||||
{
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function up(Schema $schema): void
|
|
||||||
{
|
|
||||||
// this up() migration is auto-generated, please modify it to your needs
|
|
||||||
$this->addSql('CREATE TABLE "character" (id UUID NOT NULL, dojo_id UUID DEFAULT NULL, name VARCHAR(255) NOT NULL, strength INT NOT NULL, constitution INT NOT NULL, agility INT NOT NULL, chi INT NOT NULL, PRIMARY KEY(id))');
|
|
||||||
$this->addSql('CREATE INDEX IDX_937AB03432F09E9C ON "character" (dojo_id)');
|
|
||||||
$this->addSql('COMMENT ON COLUMN "character".id IS \'(DC2Type:ulid)\'');
|
|
||||||
$this->addSql('COMMENT ON COLUMN "character".dojo_id IS \'(DC2Type:ulid)\'');
|
|
||||||
$this->addSql('CREATE TABLE character_technique (character_id UUID NOT NULL, technique_id UUID NOT NULL, PRIMARY KEY(character_id, technique_id))');
|
|
||||||
$this->addSql('CREATE INDEX IDX_506B3A7A1136BE75 ON character_technique (character_id)');
|
|
||||||
$this->addSql('CREATE INDEX IDX_506B3A7A1F8ACB26 ON character_technique (technique_id)');
|
|
||||||
$this->addSql('COMMENT ON COLUMN character_technique.character_id IS \'(DC2Type:ulid)\'');
|
|
||||||
$this->addSql('COMMENT ON COLUMN character_technique.technique_id IS \'(DC2Type:ulid)\'');
|
|
||||||
$this->addSql('CREATE TABLE city (id UUID NOT NULL, dungeon_id UUID NOT NULL, PRIMARY KEY(id))');
|
|
||||||
$this->addSql('CREATE UNIQUE INDEX UNIQ_2D5B0234B606863 ON city (dungeon_id)');
|
|
||||||
$this->addSql('COMMENT ON COLUMN city.id IS \'(DC2Type:ulid)\'');
|
|
||||||
$this->addSql('COMMENT ON COLUMN city.dungeon_id IS \'(DC2Type:ulid)\'');
|
|
||||||
$this->addSql('CREATE TABLE country (id UUID NOT NULL, capital_id UUID NOT NULL, PRIMARY KEY(id))');
|
|
||||||
$this->addSql('CREATE UNIQUE INDEX UNIQ_5373C966FC2D9FF7 ON country (capital_id)');
|
|
||||||
$this->addSql('COMMENT ON COLUMN country.id IS \'(DC2Type:ulid)\'');
|
|
||||||
$this->addSql('COMMENT ON COLUMN country.capital_id IS \'(DC2Type:ulid)\'');
|
|
||||||
$this->addSql('CREATE TABLE dojo (id UUID NOT NULL, village_id UUID DEFAULT NULL, owner_id UUID NOT NULL, name VARCHAR(255) NOT NULL, PRIMARY KEY(id))');
|
|
||||||
$this->addSql('CREATE UNIQUE INDEX UNIQ_9494CCB15E237E06 ON dojo (name)');
|
|
||||||
$this->addSql('CREATE INDEX IDX_9494CCB15E0D5582 ON dojo (village_id)');
|
|
||||||
$this->addSql('CREATE UNIQUE INDEX UNIQ_9494CCB17E3C61F9 ON dojo (owner_id)');
|
|
||||||
$this->addSql('COMMENT ON COLUMN dojo.id IS \'(DC2Type:ulid)\'');
|
|
||||||
$this->addSql('COMMENT ON COLUMN dojo.village_id IS \'(DC2Type:ulid)\'');
|
|
||||||
$this->addSql('COMMENT ON COLUMN dojo.owner_id IS \'(DC2Type:ulid)\'');
|
|
||||||
$this->addSql('CREATE TABLE dungeon (id UUID NOT NULL, city_id UUID NOT NULL, PRIMARY KEY(id))');
|
|
||||||
$this->addSql('CREATE UNIQUE INDEX UNIQ_3FFA1F908BAC62AF ON dungeon (city_id)');
|
|
||||||
$this->addSql('COMMENT ON COLUMN dungeon.id IS \'(DC2Type:ulid)\'');
|
|
||||||
$this->addSql('COMMENT ON COLUMN dungeon.city_id IS \'(DC2Type:ulid)\'');
|
|
||||||
$this->addSql('CREATE TABLE prefecture (id UUID NOT NULL, capital_id UUID NOT NULL, country_id UUID NOT NULL, PRIMARY KEY(id))');
|
|
||||||
$this->addSql('CREATE UNIQUE INDEX UNIQ_ABE6511AFC2D9FF7 ON prefecture (capital_id)');
|
|
||||||
$this->addSql('CREATE INDEX IDX_ABE6511AF92F3E70 ON prefecture (country_id)');
|
|
||||||
$this->addSql('COMMENT ON COLUMN prefecture.id IS \'(DC2Type:ulid)\'');
|
|
||||||
$this->addSql('COMMENT ON COLUMN prefecture.capital_id IS \'(DC2Type:ulid)\'');
|
|
||||||
$this->addSql('COMMENT ON COLUMN prefecture.country_id IS \'(DC2Type:ulid)\'');
|
|
||||||
$this->addSql('CREATE TABLE technique (id UUID NOT NULL, prerequisite_id UUID DEFAULT NULL, costs INT NOT NULL, damage VARCHAR(255) NOT NULL, energy VARCHAR(255) NOT NULL, accuracy VARCHAR(255) NOT NULL, PRIMARY KEY(id))');
|
|
||||||
$this->addSql('CREATE UNIQUE INDEX UNIQ_D73B9841276AF86B ON technique (prerequisite_id)');
|
|
||||||
$this->addSql('COMMENT ON COLUMN technique.id IS \'(DC2Type:ulid)\'');
|
|
||||||
$this->addSql('COMMENT ON COLUMN technique.prerequisite_id IS \'(DC2Type:ulid)\'');
|
|
||||||
$this->addSql('CREATE TABLE "user" (id UUID NOT NULL, dojo_id UUID DEFAULT NULL, auth_name VARCHAR(255) NOT NULL, properties JSON NOT NULL, PRIMARY KEY(id))');
|
|
||||||
$this->addSql('CREATE UNIQUE INDEX UNIQ_8D93D64932F09E9C ON "user" (dojo_id)');
|
|
||||||
$this->addSql('COMMENT ON COLUMN "user".id IS \'(DC2Type:ulid)\'');
|
|
||||||
$this->addSql('COMMENT ON COLUMN "user".dojo_id IS \'(DC2Type:ulid)\'');
|
|
||||||
$this->addSql('CREATE TABLE village (id UUID NOT NULL, prefecture_id UUID NOT NULL, PRIMARY KEY(id))');
|
|
||||||
$this->addSql('CREATE INDEX IDX_4E6C7FAA9D39C865 ON village (prefecture_id)');
|
|
||||||
$this->addSql('COMMENT ON COLUMN village.id IS \'(DC2Type:ulid)\'');
|
|
||||||
$this->addSql('COMMENT ON COLUMN village.prefecture_id IS \'(DC2Type:ulid)\'');
|
|
||||||
$this->addSql('ALTER TABLE "character" ADD CONSTRAINT FK_937AB03432F09E9C FOREIGN KEY (dojo_id) REFERENCES dojo (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
|
|
||||||
$this->addSql('ALTER TABLE character_technique ADD CONSTRAINT FK_506B3A7A1136BE75 FOREIGN KEY (character_id) REFERENCES "character" (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
|
||||||
$this->addSql('ALTER TABLE character_technique ADD CONSTRAINT FK_506B3A7A1F8ACB26 FOREIGN KEY (technique_id) REFERENCES technique (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
|
|
||||||
$this->addSql('ALTER TABLE city ADD CONSTRAINT FK_2D5B0234B606863 FOREIGN KEY (dungeon_id) REFERENCES dungeon (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
|
|
||||||
$this->addSql('ALTER TABLE country ADD CONSTRAINT FK_5373C966FC2D9FF7 FOREIGN KEY (capital_id) REFERENCES city (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
|
|
||||||
$this->addSql('ALTER TABLE dojo ADD CONSTRAINT FK_9494CCB15E0D5582 FOREIGN KEY (village_id) REFERENCES village (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
|
|
||||||
$this->addSql('ALTER TABLE dojo ADD CONSTRAINT FK_9494CCB17E3C61F9 FOREIGN KEY (owner_id) REFERENCES "user" (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
|
|
||||||
$this->addSql('ALTER TABLE dungeon ADD CONSTRAINT FK_3FFA1F908BAC62AF FOREIGN KEY (city_id) REFERENCES city (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
|
|
||||||
$this->addSql('ALTER TABLE prefecture ADD CONSTRAINT FK_ABE6511AFC2D9FF7 FOREIGN KEY (capital_id) REFERENCES city (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
|
|
||||||
$this->addSql('ALTER TABLE prefecture ADD CONSTRAINT FK_ABE6511AF92F3E70 FOREIGN KEY (country_id) REFERENCES country (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
|
|
||||||
$this->addSql('ALTER TABLE technique ADD CONSTRAINT FK_D73B9841276AF86B FOREIGN KEY (prerequisite_id) REFERENCES technique (id) ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE');
|
|
||||||
$this->addSql('ALTER TABLE "user" ADD CONSTRAINT FK_8D93D64932F09E9C FOREIGN KEY (dojo_id) REFERENCES dojo (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
|
|
||||||
$this->addSql('ALTER TABLE village ADD CONSTRAINT FK_4E6C7FAA9D39C865 FOREIGN KEY (prefecture_id) REFERENCES prefecture (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function down(Schema $schema): void
|
|
||||||
{
|
|
||||||
// this down() migration is auto-generated, please modify it to your needs
|
|
||||||
$this->addSql('CREATE SCHEMA public');
|
|
||||||
$this->addSql('ALTER TABLE "character" DROP CONSTRAINT FK_937AB03432F09E9C');
|
|
||||||
$this->addSql('ALTER TABLE character_technique DROP CONSTRAINT FK_506B3A7A1136BE75');
|
|
||||||
$this->addSql('ALTER TABLE character_technique DROP CONSTRAINT FK_506B3A7A1F8ACB26');
|
|
||||||
$this->addSql('ALTER TABLE city DROP CONSTRAINT FK_2D5B0234B606863');
|
|
||||||
$this->addSql('ALTER TABLE country DROP CONSTRAINT FK_5373C966FC2D9FF7');
|
|
||||||
$this->addSql('ALTER TABLE dojo DROP CONSTRAINT FK_9494CCB15E0D5582');
|
|
||||||
$this->addSql('ALTER TABLE dojo DROP CONSTRAINT FK_9494CCB17E3C61F9');
|
|
||||||
$this->addSql('ALTER TABLE dungeon DROP CONSTRAINT FK_3FFA1F908BAC62AF');
|
|
||||||
$this->addSql('ALTER TABLE prefecture DROP CONSTRAINT FK_ABE6511AFC2D9FF7');
|
|
||||||
$this->addSql('ALTER TABLE prefecture DROP CONSTRAINT FK_ABE6511AF92F3E70');
|
|
||||||
$this->addSql('ALTER TABLE technique DROP CONSTRAINT FK_D73B9841276AF86B');
|
|
||||||
$this->addSql('ALTER TABLE "user" DROP CONSTRAINT FK_8D93D64932F09E9C');
|
|
||||||
$this->addSql('ALTER TABLE village DROP CONSTRAINT FK_4E6C7FAA9D39C865');
|
|
||||||
$this->addSql('DROP TABLE "character"');
|
|
||||||
$this->addSql('DROP TABLE character_technique');
|
|
||||||
$this->addSql('DROP TABLE city');
|
|
||||||
$this->addSql('DROP TABLE country');
|
|
||||||
$this->addSql('DROP TABLE dojo');
|
|
||||||
$this->addSql('DROP TABLE dungeon');
|
|
||||||
$this->addSql('DROP TABLE prefecture');
|
|
||||||
$this->addSql('DROP TABLE technique');
|
|
||||||
$this->addSql('DROP TABLE "user"');
|
|
||||||
$this->addSql('DROP TABLE village');
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
namespace App\Controller;
|
||||||
|
|
||||||
|
use App\Entity\Fight;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Symfony\Component\HttpKernel\Attribute\AsController;
|
||||||
|
|
||||||
|
#[AsController]
|
||||||
|
class GetTournamentFights
|
||||||
|
{
|
||||||
|
|
||||||
|
public function __invoke($tournamentId, EntityManagerInterface $em): iterable
|
||||||
|
{
|
||||||
|
return $em->getRepository(Fight::class)->findBy([
|
||||||
|
'tournament' => $tournamentId
|
||||||
|
], [
|
||||||
|
'startDate' => 'ASC'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,108 @@
|
|||||||
|
<?php
|
||||||
|
namespace App\Entity;
|
||||||
|
|
||||||
|
use App\Repository\FightRepository;
|
||||||
|
use Doctrine\Common\Collections\ArrayCollection;
|
||||||
|
use Doctrine\Common\Collections\Collection;
|
||||||
|
use Doctrine\DBAL\Types\Types;
|
||||||
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
|
||||||
|
#[ORM\Entity(repositoryClass: FightRepository::class)]
|
||||||
|
class Fight extends Thing
|
||||||
|
{
|
||||||
|
|
||||||
|
#[ORM\ManyToMany(targetEntity: Character::class)]
|
||||||
|
private Collection $characters;
|
||||||
|
|
||||||
|
#[ORM\Column(type: Types::DATETIME_MUTABLE)]
|
||||||
|
private ?\DateTimeInterface $startDate = null;
|
||||||
|
|
||||||
|
#[ORM\Column()]
|
||||||
|
private array $events = [];
|
||||||
|
|
||||||
|
#[ORM\ManyToOne]
|
||||||
|
#[ORM\JoinColumn(nullable: false)]
|
||||||
|
private ?Character $winner = null;
|
||||||
|
|
||||||
|
#[ORM\ManyToOne(inversedBy: 'fights')]
|
||||||
|
#[ORM\JoinColumn(nullable: false, onDelete: 'cascade')]
|
||||||
|
private ?Tournament $tournament = null;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->characters = new ArrayCollection();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return Collection<int, Character>
|
||||||
|
*/
|
||||||
|
public function getCharacters(): Collection
|
||||||
|
{
|
||||||
|
return $this->characters;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addCharacter(Character $character): static
|
||||||
|
{
|
||||||
|
if (! $this->characters->contains($character)) {
|
||||||
|
$this->characters->add($character);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function removeCharacter(Character $character): static
|
||||||
|
{
|
||||||
|
$this->characters->removeElement($character);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getStartDate(): ?\DateTimeInterface
|
||||||
|
{
|
||||||
|
return $this->startDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setStartDate(\DateTimeInterface $startDate): static
|
||||||
|
{
|
||||||
|
$this->startDate = $startDate;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getEvents(): array
|
||||||
|
{
|
||||||
|
return $this->events;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setEvents(array $events): static
|
||||||
|
{
|
||||||
|
$this->events = $events;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getWinner(): ?Character
|
||||||
|
{
|
||||||
|
return $this->winner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setWinner(?Character $winner): static
|
||||||
|
{
|
||||||
|
$this->winner = $winner;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTournament(): ?Tournament
|
||||||
|
{
|
||||||
|
return $this->tournament;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setTournament(?Tournament $tournament): static
|
||||||
|
{
|
||||||
|
$this->tournament = $tournament;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,111 @@
|
|||||||
|
<?php
|
||||||
|
namespace App\Entity;
|
||||||
|
|
||||||
|
use App\Repository\TournamentRepository;
|
||||||
|
use Doctrine\Common\Collections\ArrayCollection;
|
||||||
|
use Doctrine\Common\Collections\Collection;
|
||||||
|
use Doctrine\DBAL\Types\Types;
|
||||||
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
|
||||||
|
#[ORM\Entity(repositoryClass: TournamentRepository::class)]
|
||||||
|
class Tournament extends Thing
|
||||||
|
{
|
||||||
|
|
||||||
|
#[ORM\Column(length: 255)]
|
||||||
|
public string $name;
|
||||||
|
|
||||||
|
#[ORM\ManyToMany(targetEntity: Character::class)]
|
||||||
|
public Collection $characters;
|
||||||
|
|
||||||
|
#[ORM\Column(type: Types::DATETIME_MUTABLE)]
|
||||||
|
private ?\DateTimeInterface $startDate = null;
|
||||||
|
|
||||||
|
#[ORM\OneToMany(mappedBy: 'tournament', targetEntity: Fight::class)]
|
||||||
|
private Collection $fights;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->characters = new ArrayCollection();
|
||||||
|
$this->fights = new ArrayCollection();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getName(): ?string
|
||||||
|
{
|
||||||
|
return $this->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setName(string $name): static
|
||||||
|
{
|
||||||
|
$this->name = $name;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return Collection<int, Character>
|
||||||
|
*/
|
||||||
|
public function getCharacters(): Collection
|
||||||
|
{
|
||||||
|
return $this->characters;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addCharacter(Character $character): static
|
||||||
|
{
|
||||||
|
if (! $this->characters->contains($character)) {
|
||||||
|
$this->characters->add($character);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function removeCharacter(Character $character): static
|
||||||
|
{
|
||||||
|
$this->characters->removeElement($character);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getStartDate(): ?\DateTimeInterface
|
||||||
|
{
|
||||||
|
return $this->startDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setStartDate(\DateTimeInterface $startDate): static
|
||||||
|
{
|
||||||
|
$this->startDate = $startDate;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return Collection<int, Fight>
|
||||||
|
*/
|
||||||
|
public function getFights(): Collection
|
||||||
|
{
|
||||||
|
return $this->fights;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addFight(Fight $fight): static
|
||||||
|
{
|
||||||
|
if (! $this->fights->contains($fight)) {
|
||||||
|
$this->fights->add($fight);
|
||||||
|
$fight->setTournament($this);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function removeFight(Fight $fight): static
|
||||||
|
{
|
||||||
|
if ($this->fights->removeElement($fight)) {
|
||||||
|
// set the owning side to null (unless already changed)
|
||||||
|
if ($fight->getTournament() === $this) {
|
||||||
|
$fight->setTournament(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
namespace App\Entity;
|
||||||
|
|
||||||
|
class TournamentRegistration
|
||||||
|
{
|
||||||
|
|
||||||
|
public Tournament $tournament;
|
||||||
|
|
||||||
|
public Character $character;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,71 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Factory;
|
||||||
|
|
||||||
|
use App\Entity\Fight;
|
||||||
|
use App\Repository\FightRepository;
|
||||||
|
use Zenstruck\Foundry\ModelFactory;
|
||||||
|
use Zenstruck\Foundry\Proxy;
|
||||||
|
use Zenstruck\Foundry\RepositoryProxy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @extends ModelFactory<Fight>
|
||||||
|
*
|
||||||
|
* @method Fight|Proxy create(array|callable $attributes = [])
|
||||||
|
* @method static Fight|Proxy createOne(array $attributes = [])
|
||||||
|
* @method static Fight|Proxy find(object|array|mixed $criteria)
|
||||||
|
* @method static Fight|Proxy findOrCreate(array $attributes)
|
||||||
|
* @method static Fight|Proxy first(string $sortedField = 'id')
|
||||||
|
* @method static Fight|Proxy last(string $sortedField = 'id')
|
||||||
|
* @method static Fight|Proxy random(array $attributes = [])
|
||||||
|
* @method static Fight|Proxy randomOrCreate(array $attributes = [])
|
||||||
|
* @method static FightRepository|RepositoryProxy repository()
|
||||||
|
* @method static Fight[]|Proxy[] all()
|
||||||
|
* @method static Fight[]|Proxy[] createMany(int $number, array|callable $attributes = [])
|
||||||
|
* @method static Fight[]|Proxy[] createSequence(iterable|callable $sequence)
|
||||||
|
* @method static Fight[]|Proxy[] findBy(array $attributes)
|
||||||
|
* @method static Fight[]|Proxy[] randomRange(int $min, int $max, array $attributes = [])
|
||||||
|
* @method static Fight[]|Proxy[] randomSet(int $number, array $attributes = [])
|
||||||
|
*/
|
||||||
|
final class FightFactory extends ModelFactory
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#factories-as-services
|
||||||
|
*
|
||||||
|
* @todo inject services if required
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#model-factories
|
||||||
|
*
|
||||||
|
* @todo add your default values here
|
||||||
|
*/
|
||||||
|
protected function getDefaults(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'events' => [],
|
||||||
|
'startDate' => self::faker()->dateTime(),
|
||||||
|
'tournament' => TournamentFactory::new(),
|
||||||
|
'winner' => CharacterFactory::new(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#initialization
|
||||||
|
*/
|
||||||
|
protected function initialize(): self
|
||||||
|
{
|
||||||
|
return $this
|
||||||
|
// ->afterInstantiate(function(Fight $fight): void {})
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static function getClass(): string
|
||||||
|
{
|
||||||
|
return Fight::class;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,69 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Factory;
|
||||||
|
|
||||||
|
use App\Entity\Tournament;
|
||||||
|
use App\Repository\TournamentRepository;
|
||||||
|
use Zenstruck\Foundry\ModelFactory;
|
||||||
|
use Zenstruck\Foundry\Proxy;
|
||||||
|
use Zenstruck\Foundry\RepositoryProxy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @extends ModelFactory<Tournament>
|
||||||
|
*
|
||||||
|
* @method Tournament|Proxy create(array|callable $attributes = [])
|
||||||
|
* @method static Tournament|Proxy createOne(array $attributes = [])
|
||||||
|
* @method static Tournament|Proxy find(object|array|mixed $criteria)
|
||||||
|
* @method static Tournament|Proxy findOrCreate(array $attributes)
|
||||||
|
* @method static Tournament|Proxy first(string $sortedField = 'id')
|
||||||
|
* @method static Tournament|Proxy last(string $sortedField = 'id')
|
||||||
|
* @method static Tournament|Proxy random(array $attributes = [])
|
||||||
|
* @method static Tournament|Proxy randomOrCreate(array $attributes = [])
|
||||||
|
* @method static TournamentRepository|RepositoryProxy repository()
|
||||||
|
* @method static Tournament[]|Proxy[] all()
|
||||||
|
* @method static Tournament[]|Proxy[] createMany(int $number, array|callable $attributes = [])
|
||||||
|
* @method static Tournament[]|Proxy[] createSequence(iterable|callable $sequence)
|
||||||
|
* @method static Tournament[]|Proxy[] findBy(array $attributes)
|
||||||
|
* @method static Tournament[]|Proxy[] randomRange(int $min, int $max, array $attributes = [])
|
||||||
|
* @method static Tournament[]|Proxy[] randomSet(int $number, array $attributes = [])
|
||||||
|
*/
|
||||||
|
final class TournamentFactory extends ModelFactory
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#factories-as-services
|
||||||
|
*
|
||||||
|
* @todo inject services if required
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#model-factories
|
||||||
|
*
|
||||||
|
* @todo add your default values here
|
||||||
|
*/
|
||||||
|
protected function getDefaults(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'name' => self::faker()->text(255),
|
||||||
|
'startDate' => self::faker()->dateTime(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#initialization
|
||||||
|
*/
|
||||||
|
protected function initialize(): self
|
||||||
|
{
|
||||||
|
return $this
|
||||||
|
// ->afterInstantiate(function(Tournament $tournament): void {})
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static function getClass(): string
|
||||||
|
{
|
||||||
|
return Tournament::class;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Repository;
|
||||||
|
|
||||||
|
use App\Entity\Fight;
|
||||||
|
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||||
|
use Doctrine\Persistence\ManagerRegistry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @extends ServiceEntityRepository<Fight>
|
||||||
|
*
|
||||||
|
* @method Fight|null find($id, $lockMode = null, $lockVersion = null)
|
||||||
|
* @method Fight|null findOneBy(array $criteria, array $orderBy = null)
|
||||||
|
* @method Fight[] findAll()
|
||||||
|
* @method Fight[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
||||||
|
*/
|
||||||
|
class FightRepository extends ServiceEntityRepository
|
||||||
|
{
|
||||||
|
public function __construct(ManagerRegistry $registry)
|
||||||
|
{
|
||||||
|
parent::__construct($registry, Fight::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
// /**
|
||||||
|
// * @return Fight[] Returns an array of Fight objects
|
||||||
|
// */
|
||||||
|
// public function findByExampleField($value): array
|
||||||
|
// {
|
||||||
|
// return $this->createQueryBuilder('f')
|
||||||
|
// ->andWhere('f.exampleField = :val')
|
||||||
|
// ->setParameter('val', $value)
|
||||||
|
// ->orderBy('f.id', 'ASC')
|
||||||
|
// ->setMaxResults(10)
|
||||||
|
// ->getQuery()
|
||||||
|
// ->getResult()
|
||||||
|
// ;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public function findOneBySomeField($value): ?Fight
|
||||||
|
// {
|
||||||
|
// return $this->createQueryBuilder('f')
|
||||||
|
// ->andWhere('f.exampleField = :val')
|
||||||
|
// ->setParameter('val', $value)
|
||||||
|
// ->getQuery()
|
||||||
|
// ->getOneOrNullResult()
|
||||||
|
// ;
|
||||||
|
// }
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Repository;
|
||||||
|
|
||||||
|
use App\Entity\Tournament;
|
||||||
|
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||||
|
use Doctrine\Persistence\ManagerRegistry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @extends ServiceEntityRepository<Tournament>
|
||||||
|
*
|
||||||
|
* @method Tournament|null find($id, $lockMode = null, $lockVersion = null)
|
||||||
|
* @method Tournament|null findOneBy(array $criteria, array $orderBy = null)
|
||||||
|
* @method Tournament[] findAll()
|
||||||
|
* @method Tournament[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
||||||
|
*/
|
||||||
|
class TournamentRepository extends ServiceEntityRepository
|
||||||
|
{
|
||||||
|
public function __construct(ManagerRegistry $registry)
|
||||||
|
{
|
||||||
|
parent::__construct($registry, Tournament::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
// /**
|
||||||
|
// * @return Tournament[] Returns an array of Tournament objects
|
||||||
|
// */
|
||||||
|
// public function findByExampleField($value): array
|
||||||
|
// {
|
||||||
|
// return $this->createQueryBuilder('t')
|
||||||
|
// ->andWhere('t.exampleField = :val')
|
||||||
|
// ->setParameter('val', $value)
|
||||||
|
// ->orderBy('t.id', 'ASC')
|
||||||
|
// ->setMaxResults(10)
|
||||||
|
// ->getQuery()
|
||||||
|
// ->getResult()
|
||||||
|
// ;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public function findOneBySomeField($value): ?Tournament
|
||||||
|
// {
|
||||||
|
// return $this->createQueryBuilder('t')
|
||||||
|
// ->andWhere('t.exampleField = :val')
|
||||||
|
// ->setParameter('val', $value)
|
||||||
|
// ->getQuery()
|
||||||
|
// ->getOneOrNullResult()
|
||||||
|
// ;
|
||||||
|
// }
|
||||||
|
}
|
@ -1,68 +0,0 @@
|
|||||||
<?php
|
|
||||||
namespace App\Security;
|
|
||||||
|
|
||||||
use App\Repository\UserRepository;
|
|
||||||
use Psr\Log\LoggerInterface;
|
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
|
||||||
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
|
|
||||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
|
||||||
use Symfony\Component\Security\Core\Exception\AuthenticationException;
|
|
||||||
use Symfony\Component\Security\Core\User\UserInterface;
|
|
||||||
use Symfony\Component\Security\Http\Authenticator\AbstractAuthenticator;
|
|
||||||
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
|
|
||||||
use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;
|
|
||||||
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
|
|
||||||
|
|
||||||
class ApiKeyAuthenticator extends AbstractAuthenticator
|
|
||||||
{
|
|
||||||
|
|
||||||
public function __construct(private UserRepository $userRepository, private LoggerInterface $logger)
|
|
||||||
{}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called on every request to decide if this authenticator should be
|
|
||||||
* used for the request.
|
|
||||||
* Returning false will cause this authenticator
|
|
||||||
* to be skipped.
|
|
||||||
*/
|
|
||||||
public function supports(Request $request): ?bool
|
|
||||||
{
|
|
||||||
return $request->headers->has('X-AUTH-TOKEN');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function authenticate(Request $request): Passport
|
|
||||||
{
|
|
||||||
$apiToken = $request->headers->get('X-AUTH-TOKEN');
|
|
||||||
if (null === $apiToken) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$userIdentifier = $apiToken;
|
|
||||||
|
|
||||||
return new SelfValidatingPassport(
|
|
||||||
new UserBadge($userIdentifier,
|
|
||||||
function (string $userIdentifier): ?UserInterface {
|
|
||||||
return $this->userRepository->findOneBy([
|
|
||||||
'authName' => $userIdentifier
|
|
||||||
]);
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
|
|
||||||
{
|
|
||||||
// on success, let the request continue
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response
|
|
||||||
{
|
|
||||||
$this->logger->critical("YYY");
|
|
||||||
$message = strtr($exception->getMessageKey(), $exception->getMessageData());
|
|
||||||
// or to translate this message
|
|
||||||
// $this->translator->trans($exception->getMessageKey(), $exception->getMessageData())
|
|
||||||
|
|
||||||
// This should translated by FOSRestBundle!
|
|
||||||
throw new AccessDeniedHttpException($message);
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,134 @@
|
|||||||
|
<?php
|
||||||
|
namespace App\Tests;
|
||||||
|
|
||||||
|
use App\Factory\TechniqueFactory;
|
||||||
|
|
||||||
|
class TechniqueTest extends AbstractTest
|
||||||
|
{
|
||||||
|
|
||||||
|
public function testListTechniques(): void
|
||||||
|
{
|
||||||
|
TechniqueFactory::createMany(10, [
|
||||||
|
'prerequisite' => NULL
|
||||||
|
]);
|
||||||
|
|
||||||
|
$response = static::createClientWithToken()->request('GET', '/api/techniques');
|
||||||
|
$this->assertEquals(10, count($response->toArray()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testListTechniquesWithPrerequisite(): void
|
||||||
|
{
|
||||||
|
$prerequisite = TechniqueFactory::createOne([
|
||||||
|
'prerequisite' => NULL
|
||||||
|
]);
|
||||||
|
|
||||||
|
TechniqueFactory::createMany(2, [
|
||||||
|
'prerequisite' => $prerequisite
|
||||||
|
]);
|
||||||
|
|
||||||
|
$response = static::createClientWithToken()->request('GET', '/api/techniques');
|
||||||
|
$this->assertEquals(3, count($response->toArray()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testShowTechnique(): void
|
||||||
|
{
|
||||||
|
$technique = TechniqueFactory::createOne([
|
||||||
|
'prerequisite' => NULL
|
||||||
|
]);
|
||||||
|
|
||||||
|
$response = static::createClientWithToken()->request('GET',
|
||||||
|
'/api/techniques/' . $technique->getId()
|
||||||
|
->toBase32());
|
||||||
|
|
||||||
|
$this->assertJsonEquals(
|
||||||
|
[
|
||||||
|
'id' => $technique->getId()
|
||||||
|
->toBase32(),
|
||||||
|
'name' => $technique->getName(),
|
||||||
|
'costs' => $technique->getCosts(),
|
||||||
|
'damage' => $technique->getDamage(),
|
||||||
|
'energy' => $technique->getEnergy(),
|
||||||
|
'accuracy' => $technique->getAccuracy()
|
||||||
|
], $response->getContent());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testShowTechniqueWithPrerequisite(): void
|
||||||
|
{
|
||||||
|
$prerequisite = TechniqueFactory::createOne([
|
||||||
|
'prerequisite' => NULL
|
||||||
|
]);
|
||||||
|
|
||||||
|
$technique = TechniqueFactory::createOne([
|
||||||
|
'prerequisite' => $prerequisite
|
||||||
|
]);
|
||||||
|
|
||||||
|
$response = static::createClientWithToken()->request('GET',
|
||||||
|
'/api/techniques/' . $technique->getId()
|
||||||
|
->toBase32());
|
||||||
|
|
||||||
|
$this->assertJsonEquals(
|
||||||
|
[
|
||||||
|
'id' => $technique->getId()
|
||||||
|
->toBase32(),
|
||||||
|
'name' => $technique->getName(),
|
||||||
|
'costs' => $technique->getCosts(),
|
||||||
|
'damage' => $technique->getDamage(),
|
||||||
|
'energy' => $technique->getEnergy(),
|
||||||
|
'accuracy' => $technique->getAccuracy(),
|
||||||
|
'prerequisite' => '/api/techniques/' . $prerequisite->getId()
|
||||||
|
->toBase32()
|
||||||
|
], $response->getContent());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCreateTechniqueAsAdmin(): void
|
||||||
|
{
|
||||||
|
$response = static::createClientWithToken("dehecht")->request('POST', '/api/techniques',
|
||||||
|
[
|
||||||
|
'json' => [
|
||||||
|
'name' => 'Drei-Schwert-Style',
|
||||||
|
'costs' => 2,
|
||||||
|
'damage' => '3 * strength',
|
||||||
|
'energy' => '1.5 * constitution + 2 * strength',
|
||||||
|
'accuracy' => '2 * agility'
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertResponseStatusCodeSame(201);
|
||||||
|
|
||||||
|
$this->assertArrayHasKey('id', $response->toArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCreateTechniqueFailsAsUser(): void
|
||||||
|
{
|
||||||
|
static::createClientWithToken()->request('POST', '/api/techniques',
|
||||||
|
[
|
||||||
|
'json' => [
|
||||||
|
'name' => 'Drei-Schwert-Style',
|
||||||
|
'costs' => 2,
|
||||||
|
'damage' => '3 * strength',
|
||||||
|
'energy' => '1.5 * constitution + 2 * strength',
|
||||||
|
'accuracy' => '2 * agility'
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertResponseStatusCodeSame(403);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testFailToCreateTechniqueWithNonExistentPrerequisite(): void
|
||||||
|
{
|
||||||
|
$response = static::createClientWithToken("dehecht")->request('POST', '/api/techniques',
|
||||||
|
[
|
||||||
|
'json' => [
|
||||||
|
'name' => 'Drei-Schwert-Style',
|
||||||
|
'costs' => 2,
|
||||||
|
'damage' => '3 * strength',
|
||||||
|
'energy' => '1.5 * constitution + 2 * strength',
|
||||||
|
'accuracy' => '2 * agility',
|
||||||
|
'prerequisite' => '/api/techniques/01ARZ3NDEKTSV4RRFFQ69G5FAV'
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertTrue($response->getStatusCode() / 100 != 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,71 @@
|
|||||||
|
<?php
|
||||||
|
namespace App\Tests;
|
||||||
|
|
||||||
|
use App\Factory\CharacterFactory;
|
||||||
|
use App\Factory\DojoFactory;
|
||||||
|
use App\Factory\TournamentFactory;
|
||||||
|
use App\Factory\UserFactory;
|
||||||
|
|
||||||
|
class TournamentTest extends AbstractTest
|
||||||
|
{
|
||||||
|
|
||||||
|
// No need to create tournaments via API Endpoint ... will be done in cronjob
|
||||||
|
public function testRegisterCharacter(): void
|
||||||
|
{
|
||||||
|
$tournament = TournamentFactory::createOne();
|
||||||
|
|
||||||
|
$dojo = DojoFactory::createOne([
|
||||||
|
'owner' => UserFactory::createOne()
|
||||||
|
]);
|
||||||
|
|
||||||
|
$character = CharacterFactory::createOne([
|
||||||
|
'dojo' => $dojo
|
||||||
|
]);
|
||||||
|
|
||||||
|
$response = static::createClientWithToken($dojo->getOwner()->authName)->request('POST',
|
||||||
|
'/api/tournament_registrations',
|
||||||
|
[
|
||||||
|
'json' => [
|
||||||
|
'tournament' => $this->getIri($tournament),
|
||||||
|
'character' => $this->getIri($character)
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertResponseStatusCodeSame(201);
|
||||||
|
|
||||||
|
$this->assertArrayHasKey('id', $response->toArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testRegisterCharacterNotPossibleTwice(): void
|
||||||
|
{}
|
||||||
|
|
||||||
|
public function testRegisterCharacterOnPastTournament(): void
|
||||||
|
{}
|
||||||
|
|
||||||
|
public function testShowRegisteredCharacters(): void
|
||||||
|
{}
|
||||||
|
|
||||||
|
public function testListTournaments(): void
|
||||||
|
{}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Status is ...
|
||||||
|
* meta data like when it is starting, name, "location", Winner (nullable), etc.
|
||||||
|
*/
|
||||||
|
public function testTournamentStatus(): void
|
||||||
|
{}
|
||||||
|
|
||||||
|
// /api/tournament/{id}/fights
|
||||||
|
// readableLink: true -> participant ids and winner
|
||||||
|
public function testTournamentFights(): void
|
||||||
|
{}
|
||||||
|
|
||||||
|
// /api/tournament/{id}/character/{id}/fights
|
||||||
|
public function testTournamentFightsForCharacter(): void
|
||||||
|
{}
|
||||||
|
|
||||||
|
// /api/tournament/{id}/ranking
|
||||||
|
public function testTournamentRanking(): void
|
||||||
|
{}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in new issue