Миграция Doctrine2 с использованием DBAL вместо $this->addSql
Итак, я сделал несколько миграций Doctrine2 (https://github.com/doctrine/migrations), но у меня есть вопрос о новой миграции, которую я пытаюсь сделать.
Я немного покопался в библиотеке и вижу, что $this->addSql()
используется для построения списка SQL для выполнения, а затем выполняется позже.
Я хотел сделать что-то, где я выбираю некоторые данные, перебираю строки, вставляю новые данные на их основе, а затем удаляю выбранные данные. Это легко поддается библиотеке DBAL, но мне интересно, могу ли я использовать protected $connection
в миграции безопасно? Или это плохо, потому что он будет выполнять операторы перед любым из моих $this->addSql()
SQL выполняется? Также кажется, что это сломало бы dry-run
установка из того, что я видел в коде. Кто-нибудь имел опыт работы с этим типом миграции? Есть ли лучшие практики?
Ниже приведена миграция, которую я хочу выполнить, но я не уверен, что это поддерживается Doctrine Migrations:
public function up(Schema $schema)
{
// this up() migration is autogenerated, please modify it to your needs
$this->abortIf($this->connection->getDatabasePlatform()->getName() != "mysql");
$this->addSql("ALTER TABLE article_enclosures ADD is_scrape TINYINT(1) NOT NULL");
$this->addSql("ALTER TABLE images DROP FOREIGN KEY FK_E01FBE6AA536AAC7");
// now lets take all images with a scrape and convert the scrape to an enclosure
//
// Select all images where not scrape_id is null (join on article_image_scrape)
// for each image:
// insert into article_enclosures
// update image set enclosure_id = new ID
// delete from article_image_scrape where id...
//
// insert into article_enclosures select article_image_scrapes...
$sql = "SELECT i.id img_id, e.* FROM images i JOIN article_image_scrapes e ON i.scrape_id = e.id";
$stmt = $this->connection->prepare($sql);
$stmt->execute();
$scrapesToDelete = array();
while ($row = $stmt->fetch()) {
$scrapeArticle = $row['article_id'];
$scrapeOldId = $row['id'];
$scrapeUrl = $row['url'];
$scrapeExtension = $row['extension'];
$scrapeUrlHash = $row['url_hash'];
$imageId = $row['image_id'];
$this->connection->insert('article_enclosures', array(
'url' => $scrapeUrl,
'extension' => $scrapeExtension,
'url_hash' => $scrapeUrlHash
));
$scrapeNewId = $this->connection->lastInsertId();
$this->connection->update('images', array(
'enclosure_id' => $scrapeNewId,
'scrape_id' => null
), array(
'id' => $imageId
));
$scrapesToDelete[] = $scrapeOldId;
}
foreach ($scrapesToDelete as $id) {
$this->connection->delete('article_image_scrapes', array('id' => $id));
}
$this->addSql("INSERT INTO article_scrapes (article_id, url, extension, url_hash) "
."SELECT s.id, s.url, s.extension, s.url_hash"
."FROM article_image_scrapes s");
$this->addSql("DROP INDEX IDX_E01FBE6AA536AAC7 ON images");
$this->addSql("ALTER TABLE images DROP scrape_id, CHANGE enclosure_id enclosure_id INT NOT NULL");
}
2 ответа
Вы можете использовать $connection
как это
$result = $this->connection->fetchAssoc('SELECT id, name FROM table1 WHERE id = 1');
$this->abortIf(!$result, 'row with id not found');
$this->abortIf($result['name'] != 'jo', 'id 1 is not jo');
// etc..
Вы должны только читать базу данных и не использовать соединение для обновления / удаления, чтобы не нарушить опцию пробного запуска.
В вашем примере вы должны выполнить две миграции. Первый будет делать два изменения таблицы. Второй будет выполнять процедуру "изображения с скребком и конвертировать скребок в оболочку". При использовании множественной миграции их проще отменить, если что-то пойдет не так.
К вашему сведению, последние документы показывают этот пример, который еще лучше с методом "postUp"
http://symfony.com/doc/current/bundles/DoctrineMigrationsBundle/index.html
// ...
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
class Version20130326212938 extends AbstractMigration implements ContainerAwareInterface
{
private $container;
public function setContainer(ContainerInterface $container = null)
{
$this->container = $container;
}
public function up(Schema $schema)
{
// ... migration content
}
public function postUp(Schema $schema)
{
$em = $this->container->get('doctrine.orm.entity_manager');
// ... update the entities
}
}