From 89a7daf882e5a738f6610cd8014158f6277e3347 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Gangloff?= Date: Tue, 18 Feb 2025 01:29:29 +0100 Subject: [PATCH] feat: add id column on entity --- migrations/Version20250217234033.php | 145 +++++++++++++++++++++++++++ migrations/Version20250217235124.php | 33 ++++++ src/Entity/Domain.php | 2 +- src/Entity/DomainEntity.php | 2 +- src/Entity/Entity.php | 38 ++++++- src/Entity/EntityEvent.php | 4 +- src/Entity/NameserverEntity.php | 2 +- src/Entity/Tld.php | 37 +++++++ src/Service/RDAPService.php | 13 +-- 9 files changed, 264 insertions(+), 12 deletions(-) create mode 100644 migrations/Version20250217234033.php create mode 100644 migrations/Version20250217235124.php diff --git a/migrations/Version20250217234033.php b/migrations/Version20250217234033.php new file mode 100644 index 0000000..bef6aa1 --- /dev/null +++ b/migrations/Version20250217234033.php @@ -0,0 +1,145 @@ +addSql('CREATE SEQUENCE entity_id_seq INCREMENT BY 1 MINVALUE 1 START 1'); + $this->addSql('ALTER TABLE entity DROP CONSTRAINT entity_pkey CASCADE'); + $this->addSql('ALTER TABLE entity ADD id INT'); + $this->addSql('UPDATE entity SET id = nextval(\'entity_id_seq\') WHERE id IS NULL;'); + + $this->addSql('ALTER TABLE entity ADD tld_id VARCHAR(63) DEFAULT NULL'); + + $this->addSql('UPDATE entity e + SET tld_id = ( + CASE + WHEN e.handle ~ \'^[0-9]+$\' THEN NULL + ELSE ( + SELECT d.tld_id + FROM domain_entity de + JOIN domain d ON de.domain_id = d.ldh_name + WHERE de.entity_id = e.handle + LIMIT 1 + ) + END + ) + WHERE EXISTS ( + SELECT 1 + FROM domain_entity de + JOIN domain d ON de.domain_id = d.ldh_name + WHERE de.entity_id = e.handle + ) OR e.handle ~ \'^[0-9]+$\'; + '); + + $this->addSql('ALTER TABLE entity ADD CONSTRAINT FK_E28446850F7084E FOREIGN KEY (tld_id) REFERENCES tld (tld) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('CREATE INDEX IDX_E28446850F7084E ON entity (tld_id)'); + $this->addSql('ALTER TABLE entity ADD PRIMARY KEY (id)'); + + $this->addSql('DROP INDEX idx_614b48a181257d5d'); + $this->addSql('ALTER TABLE domain_entity DROP CONSTRAINT domain_entity_pkey'); + $this->addSql('ALTER TABLE domain_entity ADD entity_uid INT'); + + $this->addSql('UPDATE domain_entity de + SET entity_uid = ( + SELECT e.id + FROM entity e + WHERE e.handle = de.entity_id + ) + WHERE de.entity_uid IS NULL;'); + + $this->addSql('ALTER TABLE domain_entity DROP entity_id'); + $this->addSql('ALTER TABLE domain_entity ADD CONSTRAINT FK_614B48A12D1466A1 FOREIGN KEY (entity_uid) REFERENCES entity (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('CREATE INDEX IDX_614B48A12D1466A1 ON domain_entity (entity_uid)'); + $this->addSql('ALTER TABLE domain_entity ADD PRIMARY KEY (domain_id, entity_uid)'); + + $this->addSql('DROP INDEX uniq_975a3f5e47cc8c92aa9e377a81257d5d'); + $this->addSql('DROP INDEX idx_975a3f5e81257d5d'); + $this->addSql('ALTER TABLE entity_event ADD entity_uid INT'); + + $this->addSql('UPDATE entity_event ee + SET entity_uid = ( + SELECT e.id + FROM entity e + WHERE e.handle = ee.entity_id + ) + WHERE ee.entity_uid IS NULL;'); + + $this->addSql('ALTER TABLE entity_event DROP entity_id'); + $this->addSql('ALTER TABLE entity_event ADD CONSTRAINT FK_975A3F5E2D1466A1 FOREIGN KEY (entity_uid) REFERENCES entity (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('CREATE INDEX IDX_975A3F5E2D1466A1 ON entity_event (entity_uid)'); + $this->addSql('CREATE UNIQUE INDEX UNIQ_975A3F5E47CC8C92AA9E377A2D1466A1 ON entity_event (action, date, entity_uid)'); + + $this->addSql('DROP INDEX idx_a269afb481257d5d'); + $this->addSql('ALTER TABLE nameserver_entity DROP CONSTRAINT nameserver_entity_pkey'); + $this->addSql('ALTER TABLE nameserver_entity ADD entity_uid INT'); + + $this->addSql('UPDATE nameserver_entity ne + SET entity_uid = ( + SELECT e.id + FROM entity e + WHERE e.handle = ne.entity_id + ) + WHERE ne.entity_uid IS NULL;'); + + $this->addSql('ALTER TABLE nameserver_entity DROP entity_id'); + $this->addSql('ALTER TABLE nameserver_entity ADD CONSTRAINT FK_A269AFB42D1466A1 FOREIGN KEY (entity_uid) REFERENCES entity (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('CREATE INDEX IDX_A269AFB42D1466A1 ON nameserver_entity (entity_uid)'); + $this->addSql('ALTER TABLE nameserver_entity ADD PRIMARY KEY (nameserver_id, entity_uid)'); + } + + public function down(Schema $schema): void + { + $this->addSql('DROP SEQUENCE entity_id_seq CASCADE'); + + $this->addSql('ALTER TABLE entity DROP CONSTRAINT FK_E28446850F7084E'); + $this->addSql('DROP INDEX IDX_E28446850F7084E'); + + $this->addSql('ALTER TABLE entity DROP id'); + $this->addSql('ALTER TABLE entity DROP tld_id'); + $this->addSql('ALTER TABLE entity ADD PRIMARY KEY (handle)'); + + $this->addSql('ALTER TABLE nameserver_entity DROP CONSTRAINT FK_A269AFB42D1466A1'); + $this->addSql('DROP INDEX IDX_A269AFB42D1466A1'); + $this->addSql('DROP INDEX nameserver_entity_pkey'); + $this->addSql('ALTER TABLE nameserver_entity ADD entity_id VARCHAR(255) NOT NULL'); + $this->addSql('ALTER TABLE nameserver_entity DROP entity_uid'); + $this->addSql('ALTER TABLE nameserver_entity ADD CONSTRAINT fk_a269afb481257d5d FOREIGN KEY (entity_id) REFERENCES entity (handle) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('CREATE INDEX idx_a269afb481257d5d ON nameserver_entity (entity_id)'); + $this->addSql('ALTER TABLE nameserver_entity ADD PRIMARY KEY (nameserver_id, entity_id)'); + + $this->addSql('ALTER TABLE entity_event DROP CONSTRAINT FK_975A3F5E2D1466A1'); + $this->addSql('DROP INDEX IDX_975A3F5E2D1466A1'); + $this->addSql('DROP INDEX UNIQ_975A3F5E47CC8C92AA9E377A2D1466A1'); + $this->addSql('ALTER TABLE entity_event ADD entity_id VARCHAR(255) NOT NULL'); + $this->addSql('ALTER TABLE entity_event DROP entity_uid'); + $this->addSql('ALTER TABLE entity_event ADD CONSTRAINT fk_975a3f5e81257d5d FOREIGN KEY (entity_id) REFERENCES entity (handle) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('CREATE UNIQUE INDEX uniq_975a3f5e47cc8c92aa9e377a81257d5d ON entity_event (action, date, entity_id)'); + $this->addSql('CREATE INDEX idx_975a3f5e81257d5d ON entity_event (entity_id)'); + + $this->addSql('ALTER TABLE domain_entity DROP CONSTRAINT FK_614B48A12D1466A1'); + $this->addSql('DROP INDEX IDX_614B48A12D1466A1'); + $this->addSql('DROP INDEX domain_entity_pkey'); + $this->addSql('ALTER TABLE domain_entity ADD entity_id VARCHAR(255) NOT NULL'); + $this->addSql('ALTER TABLE domain_entity DROP entity_uid'); + $this->addSql('ALTER TABLE domain_entity ADD CONSTRAINT fk_614b48a181257d5d FOREIGN KEY (entity_id) REFERENCES entity (handle) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('CREATE INDEX idx_614b48a181257d5d ON domain_entity (entity_id)'); + $this->addSql('ALTER TABLE domain_entity ADD PRIMARY KEY (domain_id, entity_id)'); + } +} diff --git a/migrations/Version20250217235124.php b/migrations/Version20250217235124.php new file mode 100644 index 0000000..4d95d2d --- /dev/null +++ b/migrations/Version20250217235124.php @@ -0,0 +1,33 @@ +addSql('CREATE UNIQUE INDEX UNIQ_E28446850F7084E918020D9 ON entity (tld_id, handle)'); + $this->addSql('ALTER TABLE entity_event ALTER entity_uid SET NOT NULL'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('DROP INDEX UNIQ_E28446850F7084E918020D9'); + $this->addSql('ALTER TABLE entity_event ALTER entity_uid DROP NOT NULL'); + } +} diff --git a/src/Entity/Domain.php b/src/Entity/Domain.php index 23d29bc..ecd464d 100644 --- a/src/Entity/Domain.php +++ b/src/Entity/Domain.php @@ -117,7 +117,7 @@ class Domain #[SerializedName('oldStatus')] private Collection $domainStatuses; - #[ORM\Column(nullable: false)] + #[ORM\Column(nullable: false, options: ['default' => false])] #[Groups(['domain:item', 'domain:list'])] private ?bool $delegationSigned = null; diff --git a/src/Entity/DomainEntity.php b/src/Entity/DomainEntity.php index 7c2525c..39497ff 100644 --- a/src/Entity/DomainEntity.php +++ b/src/Entity/DomainEntity.php @@ -19,7 +19,7 @@ class DomainEntity #[ORM\Id] #[ORM\ManyToOne(targetEntity: Entity::class, cascade: ['persist'], inversedBy: 'domainEntities')] - #[ORM\JoinColumn(referencedColumnName: 'handle', nullable: false)] + #[ORM\JoinColumn(name: 'entity_uid', referencedColumnName: 'id', nullable: false)] #[Groups(['domain-entity:entity'])] private ?Entity $entity = null; diff --git a/src/Entity/Entity.php b/src/Entity/Entity.php index a819a24..97b60dc 100644 --- a/src/Entity/Entity.php +++ b/src/Entity/Entity.php @@ -12,6 +12,9 @@ use Symfony\Component\Serializer\Attribute\Groups; use Symfony\Component\Serializer\Attribute\SerializedName; #[ORM\Entity(repositoryClass: EntityRepository::class)] +#[ORM\UniqueConstraint( + columns: ['tld_id', 'handle'] +)] #[ApiResource( operations: [ /* @@ -21,7 +24,7 @@ use Symfony\Component\Serializer\Attribute\SerializedName; ), */ new Get( - uriTemplate: '/entities/{handle}', + uriTemplate: '/entities/{id}', normalizationContext: [ 'groups' => [ 'event:list', @@ -38,6 +41,15 @@ use Symfony\Component\Serializer\Attribute\SerializedName; class Entity { #[ORM\Id] + #[ORM\GeneratedValue] + #[ORM\Column] + private ?int $id = null; + + #[ORM\ManyToOne(targetEntity: Tld::class, inversedBy: 'entities')] + #[ORM\JoinColumn(referencedColumnName: 'tld', nullable: true)] + #[Groups(['entity:list', 'entity:item', 'domain:item'])] + private ?Tld $tld = null; + #[ORM\Column(length: 255)] #[Groups(['entity:list', 'entity:item', 'domain:item'])] private ?string $handle = null; @@ -205,4 +217,28 @@ class Entity return $this; } + + public function getId(): ?int + { + return $this->id; + } + + public function setId(int $id): static + { + $this->id = $id; + + return $this; + } + + public function getTld(): ?Tld + { + return $this->tld; + } + + public function setTld(?Tld $tld): static + { + $this->tld = $tld; + + return $this; + } } diff --git a/src/Entity/EntityEvent.php b/src/Entity/EntityEvent.php index b4e9ed2..d5d88f0 100644 --- a/src/Entity/EntityEvent.php +++ b/src/Entity/EntityEvent.php @@ -7,12 +7,12 @@ use Doctrine\ORM\Mapping as ORM; #[ORM\Entity(repositoryClass: EntityEventRepository::class)] #[ORM\UniqueConstraint( - columns: ['action', 'date', 'entity_id'] + columns: ['action', 'date', 'entity_uid'] )] class EntityEvent extends Event { #[ORM\ManyToOne(targetEntity: Entity::class, inversedBy: 'events')] - #[ORM\JoinColumn(referencedColumnName: 'handle', nullable: false)] + #[ORM\JoinColumn(name: 'entity_uid', referencedColumnName: 'id', nullable: false)] private ?Entity $entity = null; public function getEntity(): ?Entity diff --git a/src/Entity/NameserverEntity.php b/src/Entity/NameserverEntity.php index 7c205f8..3966fd0 100644 --- a/src/Entity/NameserverEntity.php +++ b/src/Entity/NameserverEntity.php @@ -19,7 +19,7 @@ class NameserverEntity #[ORM\Id] #[ORM\ManyToOne(targetEntity: Entity::class, cascade: ['persist'], inversedBy: 'nameserverEntities')] - #[ORM\JoinColumn(referencedColumnName: 'handle', nullable: false)] + #[ORM\JoinColumn(name: 'entity_uid', referencedColumnName: 'id', nullable: false)] #[Groups(['nameserver-entity:entity'])] private ?Entity $entity = null; diff --git a/src/Entity/Tld.php b/src/Entity/Tld.php index cdce3e0..bbc5fa2 100644 --- a/src/Entity/Tld.php +++ b/src/Entity/Tld.php @@ -70,9 +70,16 @@ class Tld #[Groups(['tld:item'])] private ?TldType $type = null; + /** + * @var Collection + */ + #[ORM\OneToMany(targetEntity: Entity::class, mappedBy: 'tld')] + private Collection $entities; + public function __construct() { $this->rdapServers = new ArrayCollection(); + $this->entities = new ArrayCollection(); } /** @@ -200,4 +207,34 @@ class Tld return $this; } + + /** + * @return Collection + */ + public function getEntities(): Collection + { + return $this->entities; + } + + public function addEntity(Entity $entity): static + { + if (!$this->entities->contains($entity)) { + $this->entities->add($entity); + $entity->setTld($this); + } + + return $this; + } + + public function removeEntity(Entity $entity): static + { + if ($this->entities->removeElement($entity)) { + // set the owning side to null (unless already changed) + if ($entity->getTld() === $this) { + $entity->setTld(null); + } + } + + return $this; + } } diff --git a/src/Service/RDAPService.php b/src/Service/RDAPService.php index 75e0388..1c50e81 100644 --- a/src/Service/RDAPService.php +++ b/src/Service/RDAPService.php @@ -357,7 +357,7 @@ readonly class RDAPService if (isset($rdapData['entities']) && is_array($rdapData['entities'])) { foreach ($rdapData['entities'] as $rdapEntity) { $roles = $this->extractEntityRoles($rdapData['entities'], $rdapEntity); - $entity = $this->registerEntity($rdapEntity, $roles, $domain->getLdhName()); + $entity = $this->registerEntity($rdapEntity, $roles, $domain->getLdhName(), $domain->getTld()); $domainEntity = $this->domainEntityRepository->findOneBy([ 'domain' => $domain, @@ -391,7 +391,7 @@ readonly class RDAPService foreach ($rdapData['nameservers'] as $rdapNameserver) { $nameserver = $this->fetchOrCreateNameserver($rdapNameserver, $domain); - $this->updateNameserverEntities($nameserver, $rdapNameserver); + $this->updateNameserverEntities($nameserver, $rdapNameserver, $domain->getTld()); if (!$domain->getNameservers()->contains($nameserver)) { $domain->addNameserver($nameserver); @@ -426,7 +426,7 @@ readonly class RDAPService /** * @throws \DateMalformedStringException */ - private function updateNameserverEntities(Nameserver $nameserver, array $rdapNameserver): void + private function updateNameserverEntities(Nameserver $nameserver, array $rdapNameserver, Tld $tld): void { if (!isset($rdapNameserver['entities']) || !is_array($rdapNameserver['entities'])) { return; @@ -434,7 +434,7 @@ readonly class RDAPService foreach ($rdapNameserver['entities'] as $rdapEntity) { $roles = $this->extractEntityRoles($rdapNameserver['entities'], $rdapEntity); - $entity = $this->registerEntity($rdapEntity, $roles, $nameserver->getLdhName()); + $entity = $this->registerEntity($rdapEntity, $roles, $nameserver->getLdhName(), $tld); $nameserverEntity = $this->nameserverEntityRepository->findOneBy([ 'nameserver' => $nameserver, @@ -483,7 +483,7 @@ readonly class RDAPService * @throws \DateMalformedStringException * @throws \Exception */ - private function registerEntity(array $rdapEntity, array $roles, string $domain): Entity + private function registerEntity(array $rdapEntity, array $roles, string $domain, Tld $tld): Entity { /* * If the RDAP server transmits the entity's IANA number, it is used as a priority to identify the entity @@ -513,6 +513,7 @@ readonly class RDAPService $entity = $this->entityRepository->findOneBy([ 'handle' => $rdapEntity['handle'], + 'tld' => is_numeric($rdapEntity['handle']) ? null : $tld, ]); if (null === $entity) { @@ -523,7 +524,7 @@ readonly class RDAPService ]); } - $entity->setHandle($rdapEntity['handle']); + $entity->setHandle($rdapEntity['handle'])->setTld(is_numeric($rdapEntity['handle']) ? null : $tld); if (isset($rdapEntity['remarks']) && is_array($rdapEntity['remarks']) && !is_numeric($rdapEntity['handle'])) { $entity->setRemarks($rdapEntity['remarks']);