Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
"symfony/serializer": "*",
"symfony/translation": "*",
"symfony/twig-bundle": "*",
"symfony/uid": "7.3.*",
"symfony/validator": "*",
"symfony/web-link": "*",
"symfony/yaml": "*",
Expand Down
163 changes: 162 additions & 1 deletion composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

82 changes: 82 additions & 0 deletions migrations/2026/03/Version20260302120000.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<?php
declare(strict_types=1);

/**
* This file is part of the Poppy Seed Pets API.
*
* The Poppy Seed Pets API is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* The Poppy Seed Pets API is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with The Poppy Seed Pets API. If not, see <https://www.gnu.org/licenses/>.
*/

namespace DoctrineMigrations;

use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
use Symfony\Component\Uid\Ulid;

final class Version20260302120000 extends AbstractMigration
{
public function getDescription(): string
{
return 'Convert item_treasure.id from auto-increment INT to ULID BINARY(16), and update item.treasure_id FK accordingly.';
}

public function up(Schema $schema): void
{
// 1. Drop FK constraint and unique index on item.treasure_id
$this->addSql('ALTER TABLE item DROP FOREIGN KEY FK_1F1B251E4DF05F8E');
$this->addSql('DROP INDEX UNIQ_1F1B251E4DF05F8E ON item');

// 2. Add new BINARY(16) columns
$this->addSql('ALTER TABLE item_treasure ADD new_id BINARY(16) NULL AFTER id');
$this->addSql('ALTER TABLE item ADD new_treasure_id BINARY(16) NULL AFTER treasure_id');
}

public function postUp(Schema $schema): void
{
// 3. Generate ULIDs for each existing item_treasure row
$rows = $this->connection->fetchAllAssociative('SELECT id FROM item_treasure');
$idMap = [];

foreach ($rows as $row) {
$oldId = $row['id'];
$ulid = new Ulid();
$binary = $ulid->toBinary();
$idMap[$oldId] = $binary;

$this->connection->executeStatement(
'UPDATE item_treasure SET new_id = :newId WHERE id = :oldId',
['newId' => $binary, 'oldId' => $oldId]
);
}

// 4. Copy FK mappings: set item.new_treasure_id from the ULID map
foreach ($idMap as $oldId => $binary) {
$this->connection->executeStatement(
'UPDATE item SET new_treasure_id = :newTreasureId WHERE treasure_id = :oldTreasureId',
['newTreasureId' => $binary, 'oldTreasureId' => $oldId]
);
}

// 5. Drop old columns
$this->connection->executeStatement('ALTER TABLE item DROP COLUMN treasure_id');
$this->connection->executeStatement('ALTER TABLE item_treasure DROP PRIMARY KEY, DROP COLUMN id');

// 6. Rename new columns
$this->connection->executeStatement('ALTER TABLE item_treasure CHANGE new_id id BINARY(16) NOT NULL');
$this->connection->executeStatement('ALTER TABLE item CHANGE new_treasure_id treasure_id BINARY(16) DEFAULT NULL');

// 7. Re-add PK, unique index, and FK constraint
$this->connection->executeStatement('ALTER TABLE item_treasure ADD PRIMARY KEY (id)');
$this->connection->executeStatement('CREATE UNIQUE INDEX UNIQ_1F1B251E4DF05F8E ON item (treasure_id)');
$this->connection->executeStatement('ALTER TABLE item ADD CONSTRAINT FK_1F1B251E4DF05F8E FOREIGN KEY (treasure_id) REFERENCES item_treasure (id)');
}

public function down(Schema $schema): void
{
throw new \RuntimeException('Cannot reverse ULID migration — original auto-increment IDs are lost.');
}
}
4 changes: 4 additions & 0 deletions src/Command/ExportItemCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
use App\Functions\ItemRepository;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Uid\AbstractUid;

class ExportItemCommand extends PoppySeedPetsCommand
{
Expand Down Expand Up @@ -185,6 +186,9 @@ private static function encodeValueToSql(mixed $value): mixed
if(is_array($value))
return '"' . addslashes(json_encode($value)) . '"';

if($value instanceof AbstractUid)
return '0x' . bin2hex($value->toBinary());

if(is_object($value))
return $value->getId();

Expand Down
15 changes: 10 additions & 5 deletions src/Entity/ItemTreasure.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,16 @@
namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Types\UlidType;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Uid\Ulid;

#[ORM\Entity]
class ItemTreasure
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column(type: 'integer')]
/** @phpstan-ignore property.unusedType */
private ?int $id = null;
#[ORM\Column(type: UlidType::NAME)]
private Ulid $id;

#[Groups(["dragonTreasure"])]
#[ORM\Column(type: 'integer')]
Expand All @@ -37,7 +37,12 @@ class ItemTreasure
#[ORM\Column(type: 'integer')]
private int $gems = 0;

public function getId(): ?int
public function __construct()
{
$this->id = new Ulid();
}

public function getId(): Ulid
{
return $this->id;
}
Expand Down
9 changes: 9 additions & 0 deletions symfony.lock
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,15 @@
"./templates/base.html.twig"
]
},
"symfony/uid": {
"version": "7.3",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "7.0",
"ref": "0df5844274d871b37fc3816c57a768ffc60a43a5"
}
},
"symfony/validator": {
"version": "6.4",
"recipe": {
Expand Down
Loading