Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement all or nothing transaction strategy for migrations. #683

Merged
merged 1 commit into from
May 17, 2018
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
1 change: 1 addition & 0 deletions docs/en/reference/custom_configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ code that would looks like the following:
$configuration->setMigrationsDirectory('/path/to/project/src/App/Migrations');
$configuration->setMigrationsNamespace('App/Migrations');
$configuration->registerMigrationsFromDirectory('/path/to/project/src/App/Migrations');
$configuration->setAllOrNothing(true);

// My command that extends Doctrine\DBAL\Migrations\Tools\Console\Command\AbstractCommand
$command->setMigrationConfiguration($configuration);
3 changes: 3 additions & 0 deletions docs/en/reference/installation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ file like the following:

<migrations-directory>/path/to/migrations/classes/DoctrineMigrations</migrations-directory>

<all-or-nothing>1</all-or-nothing>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here it is 1...


</doctrine-migrations>

Of course you could do the same thing with a *configuration.yml* file:
Expand All @@ -82,6 +84,7 @@ Of course you could do the same thing with a *configuration.yml* file:
column_name: version
executed_at_column_name: executed_at
migrations_directory: /path/to/migrations/classes/DoctrineMigrations
all_or_nothing: true

With the above example, the migrations tool will search the ``migrations_directory``
recursively for files that begin with ``Version`` followed one to 255 characters
Expand Down
79 changes: 74 additions & 5 deletions docs/en/reference/introduction.rst
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ commands to our `Doctrine Command Line Interface <http://doctrine-orm.readthedoc
new \Doctrine\DBAL\Migrations\Tools\Console\Command\VersionCommand()
));

Additionally you have to make sure the 'db' and 'dialog' Helpers are added to your Symfony
Additionally you have to make sure the ``db`` and ``dialog`` Helpers are added to your Symfony
Console HelperSet.

.. code-block:: php
Expand Down Expand Up @@ -185,18 +185,87 @@ the migrations are executed in the correct order.
While you *can* use custom filenames, it's probably a good idea to let Doctrine
:doc:`generate migration files </reference/generating_migrations>` for you.


And if you want to specify each migration manually in YAML you can:

.. code-block:: yaml

table_name: doctrine_migration_versions
migrations_directory: /path/to/migrations/classes/DoctrineMigrations
migrations:
migration1:
version: 20100704000000
class: DoctrineMigrations\NewMigration
migration1:
version: 20100704000000
class: DoctrineMigrations\NewMigration

If you specify your own migration classes (like `DoctrineMigrations\NewMigration` in the previous
example) you will need an autoloader unless all those classes begin with the prefix Version*,
for example path/to/migrations/classes/VersionNewMigration.php.

All or Nothing Migrations
~~~~~~~~~~~~~~~~~~~~~~~~~

If you want your migrations to be all or nothing then you can configure your migrations behave that way.
This means when you executed multiple migrations in a row, the whole migration will be wrapped
in a single migration and if one of the migrations fails, the transaction will be rolled back.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wrapped in a single transaction

looks like a typo?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like it. Can you check if it still exists in master and record an issue to fix it if so?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jwage oh, didn't realize that the PR is so old 😅

The whole paragraph is gone in 2.0 and I couldn't find it in 1.8 either (that's where this PR landed).

So probably already fixed then. 👍
Sorry for the noise.


.. note::

This only works if the database connection you are using supports transactional DDL statements.

.. configuration-block::

.. code-block:: php

$configuration = new Configuration($connection);
$configuration->setAllOrNothing(true);

.. code-block:: xml

<?xml version="1.0" encoding="UTF-8"?>
<doctrine-migrations xmlns="http://doctrine-project.org/schemas/migrations/configuration"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://doctrine-project.org/schemas/migrations/configuration
http://doctrine-project.org/schemas/migrations/configuration.xsd">

<name>Doctrine Sandbox Migrations</name>

<migrations-namespace>DoctrineMigrations</migrations-namespace>

<table name="doctrine_migration_versions" />

<migrations-directory>/path/to/migrations/classes/DoctrineMigrations</migrations-directory>

<all-or-nothing>true</all-or-nothing>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... here it is true.

Should be consistent

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the feedback

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the feedback


</doctrine-migrations>

.. code-block:: yaml

name: Doctrine Sandbox Migrations
migrations_namespace: DoctrineMigrations
table_name: doctrine_migration_versions
migrations_directory: /path/to/migrations/classes/DoctrineMigrations
all_or_nothing: true


.. code-block:: json

{
"name" : "Doctrine Sandbox Migrations",
"migrations_namespace" : "DoctrineMigrations",
"table_name" : "doctrine_migration_versions",
"migrations_directory" : "/path/to/migrations/classes/DoctrineMigrations",
"all_or_nothing" : true
}

You can also optionally use the ``--all-or-nothing`` option from the command line to enable or disable
the feature for a specific migration run:

.. code-block:: bash

$ ./doctrine migrations:migrate --all-or-nothing

Or if you have it enabled in your configuration setup and you want to disable it for a migration:

.. code-block:: bash

$ ./doctrine migrations:migrate --all-or-nothing=0
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ abstract class AbstractFileConfiguration extends Configuration
'migrations_directory',
'migrations',
'custom_template',
'all_or_nothing',
];

/** @var string */
Expand Down Expand Up @@ -113,11 +114,15 @@ protected function setConfiguration(array $config) : void
$this->loadMigrations($config['migrations']);
}

if (! isset($config['custom_template'])) {
if (isset($config['custom_template'])) {
$this->setCustomTemplate($config['custom_template']);
}

if (! isset($config['all_or_nothing'])) {
return;
}

$this->setCustomTemplate($config['custom_template']);
$this->setAllOrNothing($config['all_or_nothing']);
}

protected function getDirectoryRelativeToFile(string $file, string $input) : string
Expand Down
13 changes: 13 additions & 0 deletions lib/Doctrine/Migrations/Configuration/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ class Configuration
/** @var bool */
private $isDryRun = false;

/** @var bool */
private $allOrNothing = false;

/** @var Connection */
private $connection;

Expand Down Expand Up @@ -289,6 +292,16 @@ public function isDryRun() : bool
return $this->isDryRun;
}

public function setAllOrNothing(bool $allOrNothing) : void
{
$this->allOrNothing = $allOrNothing;
}

public function isAllOrNothing() : bool
{
return $this->allOrNothing;
}

public function isMigrationTableCreated() : bool
{
return $this->getDependencyFactory()->getMigrationTableStatus()->isCreated();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
</xs:simpleType>
</xs:element>
<xs:element type="xs:string" name="migrations-directory" minOccurs="0" maxOccurs="1"/>
<xs:element type="xs:boolean" name="all-or-nothing" minOccurs="0" maxOccurs="1"/>
<xs:element name="migrations" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:sequence minOccurs="0" maxOccurs="unbounded">
Expand Down
13 changes: 12 additions & 1 deletion lib/Doctrine/Migrations/Configuration/XmlConfiguration.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Doctrine\Migrations\Configuration;

use Doctrine\Migrations\Configuration\Exception\XmlNotValid;
use Doctrine\Migrations\Tools\BooleanStringFormatter;
use DOMDocument;
use const DIRECTORY_SEPARATOR;
use const LIBXML_NOCDATA;
Expand Down Expand Up @@ -62,7 +63,17 @@ protected function doLoad(string $file) : void
}

if (isset($xml->{'migrations-directory'})) {
$config['migrations_directory'] = $this->getDirectoryRelativeToFile($file, (string) $xml->{'migrations-directory'});
$config['migrations_directory'] = $this->getDirectoryRelativeToFile(
$file,
(string) $xml->{'migrations-directory'}
);
}

if (isset($xml->{'all-or-nothing'})) {
$config['all_or_nothing'] = BooleanStringFormatter::toBoolean(
(string) $xml->{'all-or-nothing'},
false
);
}

if (isset($xml->migrations->migration)) {
Expand Down
Loading