Doctrine (and Migrations) DBAL
// Чтобы создать миграцию нужно выполнить в консоли
php migrations.phar migrations:generate
// Чтобы накатить все миграции
php migrations.phar migrations:migrate
// Выполнить конкретную миграцию
php migrations.phar migrations:execute 20200324143544 --up
php migrations.phar migrations:execute 20200324143544 --down
// Иногда нужно накатить миграцию, проверить, что-то поменять и снова накатить
// Можно сходить в БД и удалить из таблицы migration_versions нужную версию
// А можно в самой миграции описать удаление версии сраз
// БОЛЬШЕ НЕ РАБОТАЕТ - используем php migrations.phar migrations:prev
/*public function postUp(Schema $schema) {
$current_version = preg_replace("/[^0-9]/", '', get_class($this));
$qb = $this->connection->createQueryBuilder();
$qb
->delete('migration_versions')
->where('version = :version')
->setParameter(':version', $current_version);
if ($qb->execute()) $this->write("\r\nTHE MIGRATION SIGN HAS BEEN REMOVED");
}*/
// Вывести что-то в консоль можно так
public function up(Schema $schema) {
$this->write('JSON ENCODE IS FINISH!');
$this->write('UPDATE TABLE...');
}
// Стандартный пример миграции
// -> Пример со вставкой столбца следующим за service_comments
public function up(Schema $schema) {
$this->addSql("
SET NAMES 'utf8';
ALTER TABLE cars ADD COLUMN contractor_currencies_id TINYINT(4) UNSIGNED DEFAULT 1 COMMENT 'Валюта поставщика' AFTER service_comments;
");
}
public function down(Schema $schema) {
$this->addSql("
ALTER TABLE cars DROP contractor_currencies_id;
");
}
// -> Пример с созданием таблицы
public function up(Schema $schema) {
$this->addSql("
SET NAMES 'utf8';
CREATE TABLE approvals_transmitted (
id INT(11) NOT NULL AUTO_INCREMENT,
parent_approval_id INT(11) NOT NULL COMMENT 'Идентификатор родительской схемы утверждения, которая передает свои данные',
parent_company_id INT(11) UNSIGNED NOT NULL COMMENT 'Идентификатор родительской компании, которая передает схему утверждения',
child_approval_id INT(11) NOT NULL COMMENT 'Идентификатор дочерней схемы утверждения, которая принимает данные',
child_company_id INT(11) UNSIGNED NOT NULL COMMENT 'Идентификатор дочерней компании, которая принимает схему утверждения',
PRIMARY KEY (id),
INDEX FK_parent_approval_id (parent_approval_id),
INDEX FK_parent_company_id (parent_company_id),
INDEX FK_child_approval_id (child_approval_id),
INDEX FK_child_company_id (child_company_id),
CONSTRAINT FK_parent_approval_id FOREIGN KEY (parent_approval_id) REFERENCES approvals (id),
CONSTRAINT FK_parent_company_id FOREIGN KEY (parent_company_id) REFERENCES company (id),
CONSTRAINT FK_child_approval_id FOREIGN KEY (child_approval_id) REFERENCES approvals (id),
CONSTRAINT FK_child_company_id FOREIGN KEY (child_company_id) REFERENCES company (id)
)
COMMENT='Содержит связи между схемами утверждений, если они были транслированы'
COLLATE='utf8_unicode_ci'
ENGINE=InnoDB;
");
}
public function down(Schema $schema) {
$this->addSql("
SET NAMES 'utf8';
DROP TABLE approvals_transmitted;
");
}
// Если нужны множественные вставки или апдейты, то у меня получилось только через $this->addSql()
// Заодно описан метод preUp(), он выполняется до up()
// В этом методе используется QueryBuilder
public $toJsonResult = array(); // Выносим свойство в класс
public function preUp(Schema $schema): void {
$qb = $this->connection->createQueryBuilder();
$qb
->select('hnsd.id')
->addSelect('hnsd.synonyms')
->addSelect('hnsd.street_synonyms')
->from('hotel_names_synonyms_dict', 'hnsd');
$query = $qb->execute();
$result = $query->fetchAll();
for ($i = 0; $i < count($result); $i++) {
$synonyms = explode(';', $result[$i]['synonyms']);
$street_synonyms = explode(';', $result[$i]['street_synonyms']);
$id = $result[$i]['id'];
$this->toJsonResult[] = array(
'synonyms' => json_encode($synonyms, JSON_UNESCAPED_UNICODE),
'street_synonyms' => json_encode($street_synonyms, JSON_UNESCAPED_UNICODE),
'id' => $id,
);
}
}
public function up(Schema $schema) {
foreach ($this->toJsonResult as $res) {
$this->addSql('UPDATE hotel_names_synonyms_dict SET synonyms = :synonyms, street_synonyms = :street_synonyms WHERE id = :id', $res);
}
}
// Не проверял, но говорят вот так тоже можно
$qb = $this->connection
->createQueryBuilder(
"SELECT a FROM tbl a WHERE a.name = :name")
->setParameter('name',$name);
$qb->getQuery()->execute();
// Возможно пригодятся (не проверял)
// this up() migration is auto-generated, please modify it to your needs
$this->abortIf($this->connection->getDatabasePlatform()->getName() != 'mysql', 'Migration can only be executed safely on \'mysql\'.');
// А вообще вот тут описана работа с миграциями в симфонии https://www.sgalinski.de/typo3-agentur/technik/how-to-work-with-doctrine-migrations-in-symfony/
// Вот тут можно смотреть методы для QueryBuilder
https://www.doctrine-project.org/api/dbal/2.7/Doctrine/DBAL/Driver/ResultStatement.html
https://www.doctrine-project.org/projects/doctrine-migrations/en/latest/reference/migration-classes.html#methods-to-call
https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/reference/query-builder.html#working-with-querybuilder
https://www.doctrine-project.org/projects/doctrine-migrations/en/1.7/reference/migration_classes.html
// Можно щелкнуть в коде по методу QueryBuilder (например, delete) и перейти к реализации. Там в комментах есть пример ))
// Пример обновления с несколькими подготовленными выражениями
$qb = $this->connection->createQueryBuilder();
$qb
->update('hotel_names_synonyms_dict', 'hnsd')
->set('hnsd.synonyms', ':synonyms')
->set('hnsd.street_synonyms', ':street_synonyms')
->where('id', ':id')
->setParameter(':synonyms', $i)
->setParameter(':street_synonyms', $i)
->setParameter(':id', $arr[$i]['id']);
$qb->execute();
// Посмотрим статус
php migrations.phar migrations:status
// Откат миграций
// Идем в БД таблицу migration_versions
// Выбираем нужную версию (например предыдущую) и выполняем
php migrations.phar migrations:migrate 20181009130715
// Повторно накатить миграцию
// Идем в БД таблицу migration_versions
// Выбираем нужную версию и удаляем её из таблицы
// Вновь выполняем миграцию в терминале
$result = $query->fetchAll() // array(0 => array('column' => 'data', ...), 1 => array('column' => 'data2, ...), 2 => ...)
$result = $query->fetch(); // array('column' => 'data', ...)
$result = $query->fetchColumn(); // data
// Плейсхолдеры
->where('g.name = :name')
->setParameter('name', $name)
----
->where('u.id', '?1'),
->where('u.id', '?2'),
->setParameter(1, 123);
->setParameter(2, 321);
----
->setParameters(array('param1'=> $param1, 'param2' => $param2))
----
->where('at.id_service = :id_service AND at.ticketnum = :ticketnum')
->setParameter('id_service', '1038367')
->setParameter('ticketnum', '5552647029402');
// Пример группировки в запросе
'SELECT partial u.{id, username}, partial a.{id, name} FROM CmsUser u JOIN u.articles a'