Вопрос по php – Миграция Doctrine2 с использованием DBAL вместо $ this-> addSql

12

Итак, я выполнил несколько миграций Doctrine2 (https://github.com/doctrine/migrations), но у меня есть вопрос о новой миграции, которую я пытаюсь сделать.

Я немного покопался в библиотеке и вижу, что$this->addSql() используется для создания списка SQL для выполнения, а затем он выполняется позже.

Я хотел сделать что-то, где я выбираю некоторые данные, перебираю строки, вставляю новые данные на основе этого и затем удаляю выбранные данные. Это легко поддается библиотеке DBAL, но мне интересно, могу ли я использоватьprotected $connection в миграции безопасно? Или это плохо, потому что он будет выполнять операторы перед любым из моих$this->addSql() SQL выполняется? Также кажется, что это сломало быdry-run установка из того, что я видел в коде. Кто-нибудь имел опыт работы с этим типом миграции? Есть ли лучшие практики?

Далее я хочу выполнить миграцию, но я не уверен, что это поддерживается Doctrine Migrations:

<code>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");
}
</code>
Ты пробовал это? Выглядит хорошо для меня eddy147
Я решил сделать отдельные миграции до и после этого с необходимымиaddSql звонит, чтобы порядок был правильным. Matt
Я так думаю, но это было год назад. Я полагаю, что оригинальная проблема все еще остается. То есть используя->addSql() звонки, они будут выполнены последними. Иdry-run все равно будет выполнять ваши прямые манипуляции. Так что это все еще кажется хакерским (но я могу ошибаться, никогда не получал ответ, и я больше не помню об этом). Matt

Ваш Ответ

2   ответа
15

Вы можете использовать$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..

Вам следует только читать базу данных и не использовать соединение для обновления / удаления, чтобы оно не нарушало опцию пробного запуска.

В вашем примере вы должны выполнить две миграции. Первый будет делать два изменения таблицы. Второй будет выполнять процедуру «изображения с скребком и конвертировать скребок в корпус». При использовании множественной миграции их проще отменить, если что-то пойдет не так.

10

последние документы показывают этот пример, который еще лучше с методом "postUp"

http: //symfony.com/doc/current/bundles/DoctrineMigrationsBundle/index.htm

// ...
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
    }
}
Я хотел бы добавить, что вы должны быть осторожны при работе сEntityManager в среде Doctrine Migrations. EntityManager будет использовать текущие определения сущностей, которые могут отличаться от тех, которые использовались в исходной миграции. Я бы вообще не использовал EntityManager в миграциях. SteveB
@ AdrienG да, мое замечание больше касается вопроса использованияEntityManager как ярлык. Хотя это выглядит отлично, это не так. Это вызовет проблемы в будущем, когда кто-нибудь в конце концов обновит определение сущности. Использование чего-либо, не имеющего непосредственного отношения к текущему состоянию приложения, совершенно нормальн SteveB
@ SteveB может использоватьDBAL слой может быть решением. У нас есть доступ к собственностиconnection который является\Doctrine\DBAL\Connection Adrien G

Похожие вопросы