Version20201102113208.php 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. <?php
  2. declare(strict_types=1);
  3. namespace ShlinkMigrations;
  4. use Cake\Chronos\Chronos;
  5. use Doctrine\DBAL\Driver\Result;
  6. use Doctrine\DBAL\Schema\Schema;
  7. use Doctrine\DBAL\Types\Types;
  8. use Doctrine\Migrations\AbstractMigration;
  9. final class Version20201102113208 extends AbstractMigration
  10. {
  11. private const API_KEY_COLUMN = 'author_api_key_id';
  12. public function up(Schema $schema): void
  13. {
  14. $shortUrls = $schema->getTable('short_urls');
  15. $this->skipIf($shortUrls->hasColumn(self::API_KEY_COLUMN));
  16. $shortUrls->addColumn(self::API_KEY_COLUMN, Types::BIGINT, [
  17. 'unsigned' => true,
  18. 'notnull' => false,
  19. ]);
  20. $shortUrls->addForeignKeyConstraint('api_keys', [self::API_KEY_COLUMN], ['id'], [
  21. 'onDelete' => 'SET NULL',
  22. 'onUpdate' => 'RESTRICT',
  23. ], 'FK_' . self::API_KEY_COLUMN);
  24. }
  25. public function postUp(Schema $schema): void
  26. {
  27. // If there's only one API key and it's active, link all existing URLs with it
  28. $qb = $this->connection->createQueryBuilder();
  29. $qb->select('id')
  30. ->from('api_keys')
  31. ->where($qb->expr()->eq('enabled', ':enabled'))
  32. ->andWhere($qb->expr()->or(
  33. $qb->expr()->isNull('expiration_date'),
  34. $qb->expr()->gt('expiration_date', ':expiration'),
  35. ))
  36. ->setParameters([
  37. 'enabled' => true,
  38. 'expiration' => Chronos::now()->toDateTimeString(),
  39. ]);
  40. /** @var Result $result */
  41. $result = $qb->execute();
  42. $id = $this->resolveOneApiKeyId($result);
  43. if ($id === null) {
  44. return;
  45. }
  46. $qb = $this->connection->createQueryBuilder();
  47. $qb->update('short_urls')
  48. ->set(self::API_KEY_COLUMN, ':apiKeyId')
  49. ->setParameter('apiKeyId', $id)
  50. ->execute();
  51. }
  52. /**
  53. * @return string|int|null
  54. */
  55. private function resolveOneApiKeyId(Result $result)
  56. {
  57. $results = [];
  58. while ($row = $result->fetchAssociative()) {
  59. // As soon as we have to iterate more than once, then we cannot resolve a single API key
  60. if (! empty($results)) {
  61. return null;
  62. }
  63. $results[] = $row['id'] ?? null;
  64. }
  65. return $results[0] ?? null;
  66. }
  67. public function down(Schema $schema): void
  68. {
  69. $shortUrls = $schema->getTable('short_urls');
  70. $this->skipIf(! $shortUrls->hasColumn(self::API_KEY_COLUMN));
  71. $shortUrls->removeForeignKey('FK_' . self::API_KEY_COLUMN);
  72. $shortUrls->dropColumn(self::API_KEY_COLUMN);
  73. }
  74. /**
  75. * @fixme Workaround for https://github.com/doctrine/migrations/issues/1104
  76. */
  77. public function isTransactional(): bool
  78. {
  79. return false;
  80. }
  81. }