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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

## 2.1.2 under development

- New #367: Add configurable transaction mode and `--transactional` / `--no-transactional` options for migration
generation (@samdark)
- New #363, #373: Add `migrate:mark` to move migration history to a version without executing migrations (@samdark,
@vjik)
- New #360, #366, #371: Add support for additional named databases with separate migration history and `--db`
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ migrate:up Applies new migrations.

The create command allows defining fields for the table being created.

Use `--transactional` or `--no-transactional` to choose the transaction mode when creating a migration.
See [Transactional migrations](docs/guide/en/transactional-migrations.md) to configure the default mode.

Use `--db=name` to select one of [multiple databases](docs/guide/en/multiple-databases.md).

## Documentation
Expand Down
3 changes: 2 additions & 1 deletion bin/yii-db-migration
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ if (!file_exists($configFile)) {
* maxSqlOutputLength: int|null,
* newMigrationNamespace: string,
* newMigrationPath: string,
* newMigrationTransactional?: bool|null,
* sourceNamespaces: list<string>,
* sourcePaths: list<string>,
* } $params
Expand All @@ -69,7 +70,7 @@ $migrator = new Migrator(
$params['migrationNameLimit'],
$params['maxSqlOutputLength']
);
$createService = new CreateService($db, $params['useTablePrefix']);
$createService = new CreateService($db, $params['useTablePrefix'], $params['newMigrationTransactional'] ?? null);
$downRunner = new DownRunner($migrator);
$updateRunner = new UpdateRunner($migrator);

Expand Down
5 changes: 5 additions & 0 deletions bin/yii-db-migration.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@
*/
'newMigrationPath' => '',

/**
* Whether generated migrations use transactions. Set to `null` to keep template defaults.
*/
'newMigrationTransactional' => null,

/**
* List of directories containing the migration classes.
* Migration classes located at these paths should be declared without a namespace.
Expand Down
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"yiisoft/injector": "^1.2"
},
"require-dev": {
"ext-tokenizer": "*",
"bamarni/composer-bin-plugin": "^1.9.1",
"friendsofphp/php-cs-fixer": "^3.95.1",
"phpunit/phpunit": "^10.5.63",
Expand Down
8 changes: 8 additions & 0 deletions config/di-console.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,21 @@
use Yiisoft\Db\Migration\DatabaseRegistry;
use Yiisoft\Db\Migration\Informer\ConsoleMigrationInformer;
use Yiisoft\Db\Migration\Informer\MigrationInformerInterface;
use Yiisoft\Db\Migration\Service\Generate\CreateService;
use Yiisoft\Db\Migration\Service\MigrationService;
use Yiisoft\Definitions\DynamicReference;
use Yiisoft\Definitions\Reference;

/** @var array $params */

return [
CreateService::class => [
'class' => CreateService::class,
'__construct()' => [
'transactional' => $params['yiisoft/db-migration']['newMigrationTransactional'] ?? null,
],
],

DatabaseRegistry::class => [
'__construct()' => [
'databases' => array_map(
Expand Down
1 change: 1 addition & 0 deletions config/params.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
'yiisoft/db-migration' => [
'newMigrationNamespace' => '',
'newMigrationPath' => '',
'newMigrationTransactional' => null,
'sourceNamespaces' => [],
'sourcePaths' => [],
'databases' => [],
Expand Down
1 change: 1 addition & 0 deletions docs/guide/en/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@
- [Symfony application](usage-with-symfony.md)
- [Standalone](usage-standalone.md)
- [Multiple databases](multiple-databases.md)
- [Transactional migrations](transactional-migrations.md)
- [Modifying migration history](migration-history.md)
103 changes: 103 additions & 0 deletions docs/guide/en/transactional-migrations.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# Transactional migrations

A migration that implements `Yiisoft\Db\Migration\TransactionalMigrationInterface` runs in a transaction.
The migrator uses a separate transaction for each migration's `up()` or `down()` method, including the history update.

Some database operations commit automatically or cannot run in a transaction.
The interface does not change these limits.

## Create a migration

To generate a transactional migration, use `--transactional`:

```shell
./yii migrate:create update_posts --transactional
```

To generate a migration without a transaction, use `--no-transactional`:

```shell
./yii migrate:create post --command=table --no-transactional
```

Both options work with all generator commands:
`create`, `table`, `dropTable`, `addColumn`, `dropColumn`, and `junction`.
For Symfony, replace `./yii` with `php bin/console`. For the standalone tool, use `./vendor/bin/yii-db-migration`.

## Default transaction mode

Set `newMigrationTransactional` to choose the default mode for new migrations:

| Value | Behavior |
| --- | --- |
| `true` | Generate transactional migrations. |
| `false` | Generate migrations without transactions. |
| `null` | Use the template's default. |

By default, the built-in `table` and `junction` templates generate transactional migrations.
The other built-in templates generate migrations without transactions.

CLI options override `newMigrationTransactional`.
If no option is set and the setting is `null`, the generator uses the template's default.

For Yii Console, set the mode for the default database in `config/console/params.php`:

```php
'yiisoft/db-migration' => [
// ...
'newMigrationTransactional' => true,
],
```

For the standalone tool, set `'newMigrationTransactional' => true` in the project's root `yii-db-migration.php` file.

For Symfony, configure the `CreateService` constructor argument in `config/services.yml`:

```yaml
services:
Yiisoft\Db\Migration\Service\Generate\CreateService:
arguments:
$transactional: true
```

For direct PHP use, pass `transactional: true` to the `CreateService` constructor.
Pass the `transactional` argument to `CreateService::run()` to override the mode for one call.

## Named databases

Each named database has its own `newMigrationTransactional` setting. It does not inherit the default database's setting.

For Yii Console, add the setting to the database's entry in `databases`.
For standalone or Symfony usage, pass it to the `DatabaseConfig` constructor:

```php
new DatabaseConfig(
$mapsConnection,
newMigrationPath: __DIR__ . '/migrations/maps',
newMigrationTransactional: true,
);
```

The CLI option overrides the setting for the selected database:

```shell
./yii migrate:create update_places --db=maps --no-transactional
```

See [Multiple databases](multiple-databases.md) to configure the connections.

## Change an existing migration

Generation settings do not change existing migrations.

To enable transactions, add `TransactionalMigrationInterface` to the migration's `implements` list.
To disable transactions, remove it. Keep `RevertibleMigrationInterface` if the migration supports `down()`.

## Custom templates

Templates set with `CreateService::setTemplate()` or `CreateService::setTemplates()` receive `$transactional`.
This variable contains the mode for the current call, or the configured mode if no override is set.
If the value is `null`, choose a template default, for example with `$transactional ??= false`.

Include the import and implementation of `TransactionalMigrationInterface` only when `$transactional` is `true`.
Templates that ignore this variable keep their existing behavior.
10 changes: 9 additions & 1 deletion resources/views/addColumnMigration.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,14 @@
* @var PhpRenderer $this
* @var string $className The new migration class name without namespace.
* @var string $namespace The new migration class namespace.
* @var bool|null $transactional Whether the migration uses transactions. `null` keeps the template default.
* @var string $table The table name.
* @var Column[] $columns Fields.
* @var ForeignKey[] $foreignKeys Foreign keys.
*/

$transactional ??= false;

echo "<?php\n";

echo "\ndeclare(strict_types=1);\n";
Expand All @@ -31,14 +34,19 @@

use Yiisoft\Db\Migration\MigrationBuilder;
use Yiisoft\Db\Migration\RevertibleMigrationInterface;
<?php if ($transactional): ?>
use Yiisoft\Db\Migration\TransactionalMigrationInterface;
<?php endif; ?>

/**
* Handles adding columns to table `<?= $table ?>`.
<?= $this->render(__DIR__ . '/_foreignTables.php', [
'foreignKeys' => $foreignKeys,
]) ?>
*/
final class <?= $className ?> implements RevertibleMigrationInterface
final class <?= $className ?> implements RevertibleMigrationInterface<?=
$transactional ? ", TransactionalMigrationInterface\n" : "\n"
?>
{
public function up(MigrationBuilder $b): void
{
Expand Down
9 changes: 8 additions & 1 deletion resources/views/createTableMigration.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,15 @@
* @var PhpRenderer $this
* @var string $className The new migration class name without namespace.
* @var string $namespace The new migration class namespace.
* @var bool|null $transactional Whether the migration uses transactions. `null` keeps the template default.
* @var string $table The table name.
* @var string $tableComment The table comment.
* @var Column[] $columns Fields.
* @var ForeignKey[] $foreignKeys Foreign keys.
*/

$transactional ??= true;

echo "<?php\n";

echo "\ndeclare(strict_types=1);\n";
Expand All @@ -32,15 +35,19 @@

use Yiisoft\Db\Migration\MigrationBuilder;
use Yiisoft\Db\Migration\RevertibleMigrationInterface;
<?php if ($transactional): ?>
use Yiisoft\Db\Migration\TransactionalMigrationInterface;
<?php endif; ?>

/**
* Handles the creation of table `<?= $table ?>`.
<?= $this->render(__DIR__ . '/_foreignTables.php', [
'foreignKeys' => $foreignKeys,
]) ?>
*/
final class <?= $className ?> implements RevertibleMigrationInterface, TransactionalMigrationInterface
final class <?= $className ?> implements RevertibleMigrationInterface<?=
$transactional ? ", TransactionalMigrationInterface\n" : "\n"
?>
{
public function up(MigrationBuilder $b): void
{
Expand Down
10 changes: 9 additions & 1 deletion resources/views/dropColumnMigration.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,14 @@
* @var PhpRenderer $this
* @var string $className The new migration class name without namespace.
* @var string $namespace The new migration class namespace.
* @var bool|null $transactional Whether the migration uses transactions. `null` keeps the template default.
* @var string $table The table name.
* @var Column[] $columns Fields.
* @var ForeignKey[] $foreignKeys Foreign keys.
*/

$transactional ??= false;
Comment thread
samdark marked this conversation as resolved.

echo "<?php\n";

echo "\ndeclare(strict_types=1);\n";
Expand All @@ -31,14 +34,19 @@

use Yiisoft\Db\Migration\MigrationBuilder;
use Yiisoft\Db\Migration\RevertibleMigrationInterface;
<?php if ($transactional): ?>
use Yiisoft\Db\Migration\TransactionalMigrationInterface;
<?php endif; ?>
Comment thread
samdark marked this conversation as resolved.

/**
* Handles dropping columns from table `<?= $table ?>`.
<?= $this->render(__DIR__ . '/_foreignTables.php', [
'foreignKeys' => $foreignKeys,
]) ?>
*/
final class <?= $className ?> implements RevertibleMigrationInterface
final class <?= $className ?> implements RevertibleMigrationInterface<?=
$transactional ? ", TransactionalMigrationInterface\n" : "\n"
?>
Comment thread
samdark marked this conversation as resolved.
{
public function up(MigrationBuilder $b): void
{
Expand Down
10 changes: 9 additions & 1 deletion resources/views/dropTableMigration.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,14 @@
* @var PhpRenderer $this
* @var string $className The new migration class name without namespace.
* @var string $namespace The new migration class namespace.
* @var bool|null $transactional Whether the migration uses transactions. `null` keeps the template default.
* @var string $table The table name.
* @var Column[] $columns Fields.
* @var ForeignKey[] $foreignKeys Foreign keys.
*/

$transactional ??= false;

echo "<?php\n";

echo "\ndeclare(strict_types=1);\n";
Expand All @@ -31,14 +34,19 @@

use Yiisoft\Db\Migration\MigrationBuilder;
use Yiisoft\Db\Migration\RevertibleMigrationInterface;
<?php if ($transactional): ?>
use Yiisoft\Db\Migration\TransactionalMigrationInterface;
<?php endif; ?>

/**
* Handles the dropping of table `<?= $table ?>`.
<?= $this->render(__DIR__ . '/_foreignTables.php', [
'foreignKeys' => $foreignKeys,
]) ?>
*/
final class <?= $className ?> implements RevertibleMigrationInterface
final class <?= $className ?> implements RevertibleMigrationInterface<?=
$transactional ? ", TransactionalMigrationInterface\n" : "\n"
?>
{
public function up(MigrationBuilder $b): void
{
Expand Down
10 changes: 9 additions & 1 deletion resources/views/migration.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,11 @@
* @var PhpRenderer $this
* @var string $className The new migration class name without namespace.
* @var string $namespace The new migration class namespace.
* @var bool|null $transactional Whether the migration uses transactions. `null` keeps the template default.
*/

$transactional ??= false;

echo "<?php\n";

echo "\ndeclare(strict_types=1);\n";
Expand All @@ -26,8 +29,13 @@

use Yiisoft\Db\Migration\MigrationBuilder;
use Yiisoft\Db\Migration\RevertibleMigrationInterface;
<?php if ($transactional): ?>
use Yiisoft\Db\Migration\TransactionalMigrationInterface;
<?php endif; ?>

final class <?= $className ?> implements RevertibleMigrationInterface
final class <?= $className ?> implements RevertibleMigrationInterface<?=
$transactional ? ", TransactionalMigrationInterface\n" : "\n"
?>
{
public function up(MigrationBuilder $b): void
{
Expand Down
Loading
Loading