Skip to content

Commit

Permalink
Merge pull request #178 from bizley/4.4.0
Browse files Browse the repository at this point in the history
4.4.0
  • Loading branch information
Bizley authored Oct 10, 2022
2 parents 4f55bc9 + 153052a commit dcb956f
Show file tree
Hide file tree
Showing 36 changed files with 1,092 additions and 243 deletions.
83 changes: 49 additions & 34 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,45 +105,57 @@ The following console command are available (assuming you named the controller `
php yii migration/update "table_name"
```

To generate migrations for all the tables in the database at once (except the excluded ones) use asterisk (*):
To generate migrations for all the tables in the database at once (except the excluded ones) use asterisk (*):

```
php yii migration/create "*"
php yii migration/update "*"
```
```
php yii migration/create "*"
php yii migration/update "*"
```

You can generate multiple migrations for many tables at once by separating the names with comma:
You can generate multiple migrations for many tables at once by separating the names with comma:

```
php yii migration/create "table_name1,table_name2,table_name3"
```
```
php yii migration/create "table_name1,table_name2,table_name3"
```

You can provide an asterisk as a part of table name to use all tables matching the pattern:
You can provide an asterisk as a part of table name to use all tables matching the pattern:

```
php yii migration/update "prefix_*"
```
```
php yii migration/update "prefix_*"
```

Creating multiple table migrations at once forces the proper migration order based on the presence of the foreign keys.
When tables are cross-referenced the additional foreign keys migration is generated at the end of default generation.

- Extract SQL statements of migration `migration_name` (UP) **New in 4.4.0**:

```
php yii migration/sql "migration_name"
```

Creating multiple table migrations at once forces the proper migration order based on the presence of the foreign keys.
When tables are cross-referenced the additional foreign keys migration is generated at the end of default generation.
- Extract SQL statements of migration `migration_name` (DOWN) **New in 4.4.0**:

```
php yii migration/sql "migration_name" "down"
```

## Command line parameters

| command | alias | description
|----------------------|:-----:|------------------------------------------------------------------------------------
| `migrationPath` | `mp` | Directory (one or more) storing the migration classes.
| `migrationNamespace` | `mn` | Namespace (one or more) in case of generating a namespaced migration.
| `useTablePrefix` | `tp` | Whether the generated table names should consider the `tablePrefix` setting of the DB connection.
| `migrationTable` | `mt` | Name of the table for keeping the applied migration information.
| `onlyShow` | `os` | Whether to only display changes instead of generating an update migration.
| `generalSchema` | `gs` | Whether to use the general column schema instead of the database specific one (see [1] below).
| `fixHistory` | `fh` | Whether to add a migration history entry when the migration is generated.
| `skipMigrations` | | List of migrations from the history table that should be skipped during the update process (see [2] below).
| `excludeTables` | | List of tables that should be skipped.
| `experimental` | `ex` | Whether to run in the experimental mode (see [3] below).
| `fileMode` | `fm` | Generated file mode to be changed using `chmod`.
| `fileOwnership` | `fo` | Generated file ownership to be changed using `chown`/`chgrp`.
| `leeway` | `lw` | **New in 4.3.0** - The leeway in seconds to apply to a starting timestamp when generating migration, so it can be saved with a later date
| command | alias | description |
|----------------------|:-----:|------------------------------------------------------------------------------------------------------------------------|
| `migrationPath` | `mp` | Directory (one or more) storing the migration classes. |
| `migrationNamespace` | `mn` | Namespace (one or more) in case of generating a namespaced migration. |
| `useTablePrefix` | `tp` | Whether the generated table names should consider the `tablePrefix` setting of the DB connection. |
| `migrationTable` | `mt` | Name of the table for keeping the applied migration information. |
| `onlyShow` | `os` | Whether to only display changes instead of generating an update migration. |
| `generalSchema` | `gs` | Whether to use the general column schema instead of the database specific one (see [1] below). |
| `fixHistory` | `fh` | Whether to add a migration history entry when the migration is generated. |
| `skipMigrations` | | List of migrations from the history table that should be skipped during the update process (see [2] below). |
| `excludeTables` | | List of tables that should be skipped. |
| `experimental` | `ex` | Whether to run in the experimental mode (see [3] below). |
| `fileMode` | `fm` | Generated file mode to be changed using `chmod`. |
| `fileOwnership` | `fo` | Generated file ownership to be changed using `chown`/`chgrp`. |
| `leeway` | `lw` | The leeway in seconds to apply to a starting timestamp when generating migration, so it can be saved with a later date |

[1] Remember that with different database types, general column schemas may be generated with different length.

Expand Down Expand Up @@ -202,6 +214,9 @@ etc.) are not tracked.
Updating migrations process requires for the methods `createTable()`, `addColumn()`, and `alterColumn()` to provide changes
in columns definition in the form of an instance of `yii\db\ColumnSchemaBuilder` (like `$this->string()` instead of `'varchar(255)'`).

The new 4.4.0 feature with extracting SQL statements from the existing migration supports all methods available in
`yii\db\Migration`.

## Tests

Tests for MySQL, PostgreSQL, and SQLite are provided. Database configuration is stored in `tests/config.php` (you can
Expand All @@ -213,7 +228,7 @@ Docker Compose file for setting up the databases is stored in `tests/docker`.
These versions are not developed anymore but still available for all poor souls that are stuck with EOL PHP.
Some of the newest features may not be available there.

| version constraint | PHP requirements | Yii requirements
|:------------------:|:----------------:|:----------------:
| ^3.6 | >= 7.1 | >= 2.0.15.1
| ^2.9 | < 7.1 | 2.0.13 to track non-unique indexes, 2.0.14 to handle `TINYINT` and `JSON` type columns.
| version constraint | PHP requirements | Yii requirements |
|:------------------:|:----------------:|:---------------------------------------------------------------------------------------:|
| ^3.6 | >= 7.1 | >= 2.0.15.1 |
| ^2.9 | < 7.1 | 2.0.13 to track non-unique indexes, 2.0.14 to handle `TINYINT` and `JSON` type columns. |
3 changes: 2 additions & 1 deletion infection.json.dist
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
"src"
],
"excludes": [
"dummy/Migration.php",
"dummy/MigrationChanges.php",
"dummy/MigrationSql.php",
"controllers/FallbackFileHelper.php"
]
},
Expand Down
3 changes: 2 additions & 1 deletion phpunit-no-yii-autoload.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
stopOnFailure="false">
stopOnFailure="false"
processIsolation="true">
<testsuites>
<testsuite name="Yii 2 Migration Test Suite (No Yii Autoloader)">
<directory>./tests</directory>
Expand Down
3 changes: 2 additions & 1 deletion phpunit.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
stopOnFailure="false">
stopOnFailure="false"
processIsolation="true">
<testsuites>
<testsuite name="Yii 2 Migration Test Suite">
<directory>./tests</directory>
Expand Down
9 changes: 2 additions & 7 deletions src/Arranger.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,12 @@

namespace bizley\migration;

use bizley\migration\table\ForeignKeyInterface;
use yii\base\NotSupportedException;

use function array_diff;
use function array_key_exists;
use function array_merge_recursive;
use function array_unique;
use function array_values;
use function count;

final class Arranger implements ArrangerInterface
Expand Down Expand Up @@ -40,9 +38,8 @@ public function arrangeTables(array $inputTables): void

foreach ($inputTables as $inputTable) {
$this->addDependency($inputTable);
$foreignKeys = $this->mapper->getStructureOf($inputTable)->getForeignKeys();

foreach ($foreignKeys as $foreignKey) {
foreach ($this->mapper->getStructureOf($inputTable)->getForeignKeys() as $foreignKey) {
$this->addDependency($inputTable, $foreignKey->getReferredTable());
}
}
Expand Down Expand Up @@ -89,9 +86,7 @@ public function getTablesInOrder(): array
public function getReferencesToPostpone(): array
{
$flattenedReferencesToPostpone = [];
$referencesToPostponeValues = array_values($this->referencesToPostpone);
/** @var array<string> $referencesToPostponeValue */
foreach ($referencesToPostponeValues as $referencesToPostponeValue) {
foreach ($this->referencesToPostpone as $referencesToPostponeValue) {
foreach ($referencesToPostponeValue as $reference) {
$flattenedReferencesToPostpone[] = $reference;
}
Expand Down
36 changes: 15 additions & 21 deletions src/Comparator.php
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ private function compareColumns(
/** @var ColumnInterface $column */
/** @var string $name */
foreach ($newColumns as $name => $column) {
if (array_key_exists($name, $oldColumns) === false) {
if (!array_key_exists($name, $oldColumns)) {
$blueprint->addDescription("missing column '$name'");
if ($previousColumn) {
$column->setAfter($previousColumn);
Expand All @@ -103,7 +103,7 @@ private function compareColumns(
$this->generalSchema === false
&& $newPrimaryKey
&& $column->getAppend() === null
&& $newPrimaryKey->isComposite() === false
&& !$newPrimaryKey->isComposite()
&& $column->isColumnInPrimaryKey($newPrimaryKey)
) {
$column->setAppend($column->prepareSchemaAppend(true, $column->isAutoIncrement(), $schema));
Expand Down Expand Up @@ -131,10 +131,10 @@ private function compareColumns(
$oldProperty = $oldColumn->$propertyFetch();
$newProperty = $column->$propertyFetch();
}
if (is_bool($oldProperty) === false && $oldProperty !== null && is_array($oldProperty) === false) {
if (!is_bool($oldProperty) && $oldProperty !== null && !is_array($oldProperty)) {
$oldProperty = (string)$oldProperty;
}
if (is_bool($newProperty) === false && $newProperty !== null && is_array($newProperty) === false) {
if (!is_bool($newProperty) && $newProperty !== null && !is_array($newProperty)) {
$newProperty = (string)$newProperty;
}
if ($oldProperty !== $newProperty) {
Expand Down Expand Up @@ -184,7 +184,7 @@ private function compareColumns(
}

foreach ($oldColumns as $name => $column) {
if (array_key_exists($name, $newColumns) === false) {
if (!array_key_exists($name, $newColumns)) {
$blueprint->addDescription("excessive column '$name'");
if ($schema === Schema::SQLITE) {
$blueprint->addDescription(
Expand Down Expand Up @@ -219,7 +219,7 @@ private function compareForeignKeys(
$newForeignKeys = $newStructure->getForeignKeys();
$oldForeignKeys = $oldStructure->getForeignKeys();
foreach ($newForeignKeys as $name => $foreignKey) {
if (array_key_exists($name, $oldForeignKeys) === false) {
if (!array_key_exists($name, $oldForeignKeys)) {
$blueprint->addDescription("missing foreign key '$name'");

if ($schema === Schema::SQLITE) {
Expand Down Expand Up @@ -360,7 +360,7 @@ private function compareForeignKeys(
}

foreach ($oldForeignKeys as $name => $foreignKey) {
if (array_key_exists($name, $newForeignKeys) === false) {
if (!array_key_exists($name, $newForeignKeys)) {
$blueprint->addDescription("excessive foreign key '$name'");

if ($schema === Schema::SQLITE) {
Expand Down Expand Up @@ -447,13 +447,11 @@ private function comparePrimaryKeys(
*/
private function removeExcessivePrimaryKeyStatements(BlueprintInterface $blueprint, ?string $schema): void
{
$addedColumns = $blueprint->getAddedColumns();
foreach ($addedColumns as $column) {
foreach ($blueprint->getAddedColumns() as $column) {
$column->setAppend($column->removeAppendedPrimaryKeyInfo($schema));
}

$alteredColumns = $blueprint->getAlteredColumns();
foreach ($alteredColumns as $column) {
foreach ($blueprint->getAlteredColumns() as $column) {
$column->setAppend($column->removeAppendedPrimaryKeyInfo($schema));
}
}
Expand All @@ -476,15 +474,13 @@ private function shouldPrimaryKeyBeAdded(
return false;
}
if ($newColumnsCount === 1 && count($differentColumns) === 1) {
$addedColumns = $blueprint->getAddedColumns();
foreach ($addedColumns as $name => $column) {
foreach ($blueprint->getAddedColumns() as $name => $column) {
if ($name === $differentColumns[0] && $column->isPrimaryKeyInfoAppended($schema)) {
return false;
}
}

$alteredColumns = $blueprint->getAlteredColumns();
foreach ($alteredColumns as $name => $column) {
foreach ($blueprint->getAlteredColumns() as $name => $column) {
if ($name === $differentColumns[0] && $column->isPrimaryKeyInfoAppended($schema)) {
return false;
}
Expand All @@ -511,7 +507,7 @@ private function compareIndexes(
$oldIndexes = $oldStructure->getIndexes();

foreach ($newIndexes as $name => $index) {
if (array_key_exists($name, $oldIndexes) === false) {
if (!array_key_exists($name, $oldIndexes)) {
$indexColumns = $index->getColumns();
if (
$index->isUnique()
Expand All @@ -525,8 +521,7 @@ private function compareIndexes(
continue;
}

$foreignKeys = $newStructure->getForeignKeys();
foreach ($foreignKeys as $foreignKey) {
foreach ($newStructure->getForeignKeys() as $foreignKey) {
if ($foreignKey->getColumns() === $indexColumns) {
// index is created for foreign key with the same columns
continue 2;
Expand Down Expand Up @@ -568,7 +563,7 @@ private function compareIndexes(
}

foreach ($oldIndexes as $name => $index) {
if (array_key_exists($name, $newIndexes) === false) {
if (!array_key_exists($name, $newIndexes)) {
$blueprint->addDescription("excessive index '$name'");
$blueprint->dropIndex($index);
}
Expand Down Expand Up @@ -655,8 +650,7 @@ private function stripAppend(?string $append): array
private function getRealUniqueness(StructureInterface $structure, string $columnName, bool $unique): bool
{
if ($unique) {
$indexes = $structure->getIndexes();
foreach ($indexes as $index) {
foreach ($structure->getIndexes() as $index) {
$indexColumns = $index->getColumns();
if ($index->isUnique() && count($indexColumns) === 1 && in_array($columnName, $indexColumns, true)) {
return false;
Expand Down
Loading

0 comments on commit dcb956f

Please sign in to comment.