How do I write a Doctrine migration which can redistribute data into new tables
OK, I seem to have found it, from a number of sources (including this) and trial and error.
Cerad's comments were a little help, but mainly I'm doing it by using the DBAL layer to read in the data (which I can get at by $this->connection
), and the ORM to save the new data (which requires the EntityManager, so I did have to use the trick with the container).
I put all the code in postUp()
, including the generated code to drop columns from tables.
Sample bits of my code:
use Symfony\Component\DependencyInjection\ContainerAwareInterface;use Symfony\Component\DependencyInjection\ContainerInterface;use PG\InventoryBundle\Entity\Item;use PG\InventoryBundle\Entity\Address; . . ./** * Auto-generated Migration: Please modify to your needs! */class Version20140519211228 extends AbstractMigration implements ContainerAwareInterface{ private $container; public function setContainer(ContainerInterface $container = null) { $this->container = $container; } public function up(Schema $schema) { . . . }}public function postUp(Schema $schema){ $em = $this->container->get('doctrine.orm.entity_manager'); // ... update the entities $query = "SELECT * FROM item"; $stmt = $this->connection->prepare($query); $stmt->execute(); // We can't use Doctrine's ORM to fetch the item, because it has a load of extra fields // that aren't in the entity definition. while ($row = $stmt->fetch()) { // But we will also get the entity, so that we can put addresses in it. $id = $row['id']; // And create new objects $stock = new Stock(); . . . $stock->setAssetNo($row['asset_no']); $stock->setItemId($row['id']); $em->persist($stock); $em->flush(); } // Now we can drop fields we don't need. $this->connection->executeQuery("ALTER TABLE item DROP container_id"); $this->connection->executeQuery("ALTER TABLE item DROP location_id"); . . . }