getTable('short_urls'); $this->skipIf($shortUrls->hasColumn(self::API_KEY_COLUMN)); $shortUrls->addColumn(self::API_KEY_COLUMN, Types::BIGINT, [ 'unsigned' => true, 'notnull' => false, ]); $shortUrls->addForeignKeyConstraint('api_keys', [self::API_KEY_COLUMN], ['id'], [ 'onDelete' => 'SET NULL', 'onUpdate' => 'RESTRICT', ], 'FK_' . self::API_KEY_COLUMN); } public function postUp(Schema $schema): void { // If there's only one API key and it's active, link all existing URLs with it $qb = $this->connection->createQueryBuilder(); $qb->select('id') ->from('api_keys') ->where($qb->expr()->eq('enabled', ':enabled')) ->andWhere($qb->expr()->or( $qb->expr()->isNull('expiration_date'), $qb->expr()->gt('expiration_date', ':expiration'), )) ->setParameters([ 'enabled' => true, 'expiration' => Chronos::now()->toDateTimeString(), ]); /** @var Result $result */ $result = $qb->execute(); $id = $this->resolveOneApiKeyId($result); if ($id === null) { return; } $qb = $this->connection->createQueryBuilder(); $qb->update('short_urls') ->set(self::API_KEY_COLUMN, ':apiKeyId') ->setParameter('apiKeyId', $id) ->execute(); } private function resolveOneApiKeyId(Result $result): string|int|null { $results = []; while ($row = $result->fetchAssociative()) { // As soon as we have to iterate more than once, then we cannot resolve a single API key if (! empty($results)) { return null; } $results[] = $row['id'] ?? null; } return $results[0] ?? null; } public function down(Schema $schema): void { $shortUrls = $schema->getTable('short_urls'); $this->skipIf(! $shortUrls->hasColumn(self::API_KEY_COLUMN)); $shortUrls->removeForeignKey('FK_' . self::API_KEY_COLUMN); $shortUrls->dropColumn(self::API_KEY_COLUMN); } public function isTransactional(): bool { return $this->connection->getDatabasePlatform()->getName() !== 'mysql'; } }