diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 91c54862..fac01bed 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -125,7 +125,7 @@ jobs:
- name: Code Coverage Report
if: success() && matrix.php-version == '8.1' && matrix.db-type == 'mysql'
- uses: codecov/codecov-action@v4
+ uses: codecov/codecov-action@v5
testsuite-windows:
runs-on: windows-2022
@@ -195,7 +195,7 @@ jobs:
vendor/bin/phpunit --coverage-clover=coverage.xml
- name: Submit code coverage
- uses: codecov/codecov-action@v4
+ uses: codecov/codecov-action@v5
cs-stan:
uses: cakephp/.github/.github/workflows/cs-stan.yml@5.x
diff --git a/.phive/phars.xml b/.phive/phars.xml
index 726b7777..d311bfa5 100644
--- a/.phive/phars.xml
+++ b/.phive/phars.xml
@@ -1,5 +1,5 @@
-
-
+
+
diff --git a/.stickler.yml b/.stickler.yml
deleted file mode 100644
index 0ec83f6f..00000000
--- a/.stickler.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-linters:
- phpcs:
- standard: CakePHP
-files:
- ignore: ['tests/bootstrap.php', 'tests/comparisons/*']
diff --git a/README.md b/README.md
index 0aecc0f0..0b396e83 100644
--- a/README.md
+++ b/README.md
@@ -29,6 +29,7 @@ bin/cake plugin load Migrations
```
Or you can manually add the loading statement in the **src/Application.php** file of your application:
+
```php
public function bootstrap(): void
{
@@ -37,7 +38,20 @@ public function bootstrap(): void
}
```
-Additionally, you will need to configure the ``default`` database configuration in your **config/app.php** file.
+### Enabling the builtin backend
+
+In a future release, migrations will be switching to a new backend based on the CakePHP ORM. We're aiming
+to be compatible with as many existing migrations as possible, and could use your feedback. Enable the
+new backend with:
+
+```php
+// in app/config/app_local.php
+$config = [
+ // Other configuration
+ 'Migrations' => ['backend' => 'builtin'],
+];
+
+```
## Documentation
diff --git a/docs/en/upgrading-to-builtin-backend.rst b/docs/en/upgrading-to-builtin-backend.rst
index 4731cc22..b1837263 100644
--- a/docs/en/upgrading-to-builtin-backend.rst
+++ b/docs/en/upgrading-to-builtin-backend.rst
@@ -2,7 +2,8 @@ Upgrading to the builtin backend
################################
As of migrations 4.3 there is a new migrations backend that uses CakePHP's
-database abstractions and ORM. Longer term this will allow for phinx to be
+database abstractions and ORM. In 4.4, the ``builtin`` backend became the
+default backend. Longer term this will allow for phinx to be
removed as a dependency. This greatly reduces the dependency footprint of
migrations.
@@ -42,16 +43,16 @@ Similar changes are for fetching a single row::
$stmt = $this->getAdapter()->query('SELECT * FROM articles');
$rows = $stmt->fetch('assoc');
-Enabling the new backend
-========================
+Problems with the new backend?
+==============================
-The new backend can be enabled through application configuration. Add the
+The new backend is enabled by default. If your migrations contain errors when
+run with the builtin backend, please open `an issue
+`_. You can also switch back
+to the ``phinx`` backend through application configuration. Add the
following to your ``config/app.php``::
return [
// Other configuration.
- 'Migrations' => ['backend' => 'builtin'],
+ 'Migrations' => ['backend' => 'phinx'],
];
-
-If your migrations have problems running with the builtin backend, removing this
-configuration option will revert to using phinx.
diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon
index 49a54904..f5dae26c 100644
--- a/phpstan-baseline.neon
+++ b/phpstan-baseline.neon
@@ -1,71 +1,169 @@
parameters:
ignoreErrors:
-
- message: "#^Call to an undefined method object\\:\\:loadHelper\\(\\)\\.$#"
+ message: '#^Call to an undefined method object\:\:loadHelper\(\)\.$#'
+ identifier: method.notFound
count: 1
path: src/Command/BakeMigrationCommand.php
-
- message: "#^Call to an undefined method object\\:\\:loadHelper\\(\\)\\.$#"
+ message: '#^Parameter \#1 \$arguments of method Migrations\\Util\\ColumnParser\:\:parseFields\(\) expects array\, array\\|int\<1, max\>, list\\|string\> given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Command/BakeMigrationCommand.php
+
+ -
+ message: '#^Parameter \#1 \$arguments of method Migrations\\Util\\ColumnParser\:\:parseIndexes\(\) expects array\, array\\|int\<1, max\>, list\\|string\> given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Command/BakeMigrationCommand.php
+
+ -
+ message: '#^Parameter \#1 \$arguments of method Migrations\\Util\\ColumnParser\:\:parsePrimaryKey\(\) expects array\, array\\|int\<1, max\>, list\\|string\> given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Command/BakeMigrationCommand.php
+
+ -
+ message: '#^Call to an undefined method object\:\:loadHelper\(\)\.$#'
+ identifier: method.notFound
count: 1
path: src/Command/BakeMigrationDiffCommand.php
-
- message: "#^Call to an undefined method object\\:\\:loadHelper\\(\\)\\.$#"
+ message: '#^Call to an undefined method object\:\:loadHelper\(\)\.$#'
+ identifier: method.notFound
count: 1
path: src/Command/BakeMigrationSnapshotCommand.php
-
- message: "#^Unsafe usage of new static\\(\\)\\.$#"
+ message: '#^PHPDoc tag @var with type string is not subtype of native type non\-falsy\-string\|true\.$#'
+ identifier: varTag.nativeType
+ count: 1
+ path: src/Command/BakeSeedCommand.php
+
+ -
+ message: '#^Strict comparison using \!\=\= between string and false will always evaluate to true\.$#'
+ identifier: notIdentical.alwaysTrue
+ count: 1
+ path: src/Command/BakeSeedCommand.php
+
+ -
+ message: '#^Call to an undefined method Cake\\Datasource\\ConnectionInterface\:\:cacheMetadata\(\)\.$#'
+ identifier: method.notFound
+ count: 1
+ path: src/Command/Phinx/CacheBuild.php
+
+ -
+ message: '#^Call to an undefined method Cake\\Datasource\\ConnectionInterface\:\:cacheMetadata\(\)\.$#'
+ identifier: method.notFound
+ count: 1
+ path: src/Command/Phinx/CacheClear.php
+
+ -
+ message: '#^Unsafe usage of new static\(\)\.$#'
+ identifier: new.static
count: 1
path: src/Db/Adapter/AdapterFactory.php
-
- message: "#^Offset 'id' on non\\-empty\\-array\\ in isset\\(\\) always exists and is not nullable\\.$#"
+ message: '#^Offset ''id'' on non\-empty\-array\ in isset\(\) always exists and is not nullable\.$#'
+ identifier: isset.offset
count: 2
path: src/Db/Adapter/MysqlAdapter.php
-
- message: "#^Right side of && is always true\\.$#"
+ message: '#^Offset 3 might not exist on array\{0\: string, 1\: non\-empty\-string, 2\?\: string, 3\?\: ''''\|numeric\-string, 4\?\: string, 5\?\: ''''\|numeric\-string, 6\?\: non\-empty\-string\}\.$#'
+ identifier: offsetAccess.notFound
count: 1
path: src/Db/Adapter/MysqlAdapter.php
-
- message: "#^Access to an undefined property Cake\\\\Database\\\\Connection\\:\\:\\$connection\\.$#"
+ message: '#^Offset 5 might not exist on array\{0\: string, 1\: non\-empty\-string, 2\?\: string, 3\?\: ''''\|numeric\-string, 4\?\: string, 5\?\: ''''\|numeric\-string, 6\?\: non\-empty\-string\}\.$#'
+ identifier: offsetAccess.notFound
count: 1
- path: src/Db/Adapter/PdoAdapter.php
+ path: src/Db/Adapter/MysqlAdapter.php
-
- message: "#^Offset 'id' on array\\ in isset\\(\\) always exists and is not nullable\\.$#"
- count: 2
- path: src/Db/Adapter/PostgresAdapter.php
+ message: '#^Offset 6 might not exist on array\{0\: string, 1\: non\-empty\-string, 2\?\: string, 3\?\: ''''\|numeric\-string, 4\?\: string, 5\?\: ''''\|numeric\-string, 6\?\: non\-empty\-string\}\.$#'
+ identifier: offsetAccess.notFound
+ count: 1
+ path: src/Db/Adapter/MysqlAdapter.php
-
- message: "#^Offset 'id' on array\\ in isset\\(\\) always exists and is not nullable\\.$#"
- count: 2
- path: src/Db/Adapter/SqliteAdapter.php
+ message: '#^Right side of && is always true\.$#'
+ identifier: booleanAnd.rightAlwaysTrue
+ count: 1
+ path: src/Db/Adapter/MysqlAdapter.php
-
- message: "#^Offset 'id' on array\\ in isset\\(\\) always exists and is not nullable\\.$#"
- count: 2
- path: src/Db/Adapter/SqlserverAdapter.php
+ message: '#^Right side of && is always true\.$#'
+ identifier: booleanAnd.rightAlwaysTrue
+ count: 1
+ path: src/Db/Adapter/SqliteAdapter.php
-
- message: "#^PHPDoc tag @return with type Phinx\\\\Db\\\\Adapter\\\\AdapterInterface is not subtype of native type Migrations\\\\Db\\\\Adapter\\\\AdapterInterface\\.$#"
+ message: '#^PHPDoc tag @return with type Phinx\\Db\\Adapter\\AdapterInterface is not subtype of native type Migrations\\Db\\Adapter\\AdapterInterface\.$#'
+ identifier: return.phpDocType
count: 1
path: src/Db/Adapter/SqlserverAdapter.php
-
- message: "#^Ternary operator condition is always true\\.$#"
+ message: '#^Ternary operator condition is always true\.$#'
+ identifier: ternary.alwaysTrue
count: 2
path: src/Db/Adapter/SqlserverAdapter.php
-
- message: "#^Method Migrations\\\\Shim\\\\OutputAdapter\\:\\:getVerbosity\\(\\) should return 16\\|32\\|64\\|128\\|256 but returns int\\.$#"
+ message: '#^Parameter \#1 \$message of method Cake\\Console\\ConsoleIo\:\:verbose\(\) expects list\\|string, array\ given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Migration/Manager.php
+
+ -
+ message: '#^Parameter \#1 \.\.\.\$arg1 of function max expects non\-empty\-array, array given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/Migration/Manager.php
+
+ -
+ message: '#^PHPDoc tag @var with type array\ is not subtype of native type mixed\.$#'
+ identifier: varTag.nativeType
+ count: 1
+ path: src/Migration/ManagerFactory.php
+
+ -
+ message: '#^Method Migrations\\Shim\\OutputAdapter\:\:getVerbosity\(\) should return 16\|32\|64\|128\|256 but returns int\.$#'
+ identifier: return.type
count: 1
path: src/Shim/OutputAdapter.php
-
- message: "#^Possibly invalid array key type Cake\\\\Database\\\\Schema\\\\TableSchemaInterface\\|string\\.$#"
+ message: '#^Parameter \#1 \$message of method Cake\\Console\\ConsoleIo\:\:out\(\) expects list\\|string, array\|string given\.$#'
+ identifier: argument.type
+ count: 2
+ path: src/Shim/OutputAdapter.php
+
+ -
+ message: '#^Parameter \#2 \$tables of method Cake\\TestSuite\\ConnectionHelper\:\:dropTables\(\) expects list\\|null, non\-empty\-array\ given\.$#'
+ identifier: argument.type
+ count: 1
+ path: src/TestSuite/Migrator.php
+
+ -
+ message: '#^Parameter \#2 \$tables of method Cake\\TestSuite\\ConnectionHelper\:\:truncateTables\(\) expects list\\|null, non\-empty\-array\ given\.$#'
+ identifier: argument.type
+ count: 2
+ path: src/TestSuite/Migrator.php
+
+ -
+ message: '#^Offset 0 on non\-empty\-list\ in isset\(\) always exists and is not nullable\.$#'
+ identifier: isset.offset
+ count: 2
+ path: src/Util/TableFinder.php
+
+ -
+ message: '#^Possibly invalid array key type Cake\\Database\\Schema\\TableSchemaInterface\|string\.$#'
+ identifier: offsetAccess.invalidOffset
count: 2
path: src/View/Helper/MigrationHelper.php
diff --git a/psalm-baseline.xml b/psalm-baseline.xml
index 58309755..5b7121ab 100644
--- a/psalm-baseline.xml
+++ b/psalm-baseline.xml
@@ -59,6 +59,10 @@
+
+
+
+
@@ -82,6 +86,23 @@
+
+
+
+
+ getManager()->maxNameLength]]>
+
+
+
+
+
+
+
+
+
+
+
+
@@ -224,4 +245,9 @@
regexpParseField]]>
+
+
+
+
+
diff --git a/psalm.xml b/psalm.xml
index 738d8fcd..54311675 100644
--- a/psalm.xml
+++ b/psalm.xml
@@ -5,7 +5,7 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://getpsalm.org/schema/config"
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
- errorBaseline="./psalm-baseline.xml"
+ errorBaseline="psalm-baseline.xml"
autoloader="tests/bootstrap.php"
findUnusedPsalmSuppress="true"
findUnusedBaselineEntry="true"
diff --git a/src/Command/BakeMigrationDiffCommand.php b/src/Command/BakeMigrationDiffCommand.php
index 1f076f0b..3cef914a 100644
--- a/src/Command/BakeMigrationDiffCommand.php
+++ b/src/Command/BakeMigrationDiffCommand.php
@@ -31,8 +31,6 @@
/**
* Task class for generating migration diff files.
- *
- * @property \Bake\Shell\Task\TestTask $Test
*/
class BakeMigrationDiffCommand extends BakeSimpleMigrationCommand
{
diff --git a/src/Command/Phinx/Dump.php b/src/Command/Phinx/Dump.php
index b4eca9f3..42336b24 100644
--- a/src/Command/Phinx/Dump.php
+++ b/src/Command/Phinx/Dump.php
@@ -87,8 +87,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$this->output($output);
$path = $this->getOperationsPath($input);
- /** @var string $connectionName */
$connectionName = $input->getOption('connection') ?: 'default';
+ assert(is_string($connectionName), 'Connection name must be a string');
$connection = ConnectionManager::get($connectionName);
assert($connection instanceof Connection);
$collection = $connection->getSchemaCollection();
diff --git a/src/Db/Adapter/PdoAdapter.php b/src/Db/Adapter/PdoAdapter.php
index 33a29482..b1d4452d 100644
--- a/src/Db/Adapter/PdoAdapter.php
+++ b/src/Db/Adapter/PdoAdapter.php
@@ -173,7 +173,6 @@ public function getConnection(): Connection
$this->connect();
}
- /** @var \Cake\Database\Connection $this->connection */
return $this->connection;
}
diff --git a/src/Db/Adapter/PostgresAdapter.php b/src/Db/Adapter/PostgresAdapter.php
index eb2bd4c4..a525c219 100644
--- a/src/Db/Adapter/PostgresAdapter.php
+++ b/src/Db/Adapter/PostgresAdapter.php
@@ -186,11 +186,11 @@ public function createTable(Table $table, array $columns = [], array $indexes =
$parts = $this->getSchemaName($table->getName());
// Add the default primary key
- if (!isset($options['id']) || (isset($options['id']) && $options['id'] === true)) {
+ if (!isset($options['id']) || $options['id'] === true) {
$options['id'] = 'id';
}
- if (isset($options['id']) && is_string($options['id'])) {
+ if (is_string($options['id'])) {
// Handle id => "field_name" to support AUTO_INCREMENT
$column = new Column();
$column->setName($options['id'])
diff --git a/src/Db/Adapter/SqliteAdapter.php b/src/Db/Adapter/SqliteAdapter.php
index 7a9df3e7..540b675f 100644
--- a/src/Db/Adapter/SqliteAdapter.php
+++ b/src/Db/Adapter/SqliteAdapter.php
@@ -360,11 +360,11 @@ public function createTable(Table $table, array $columns = [], array $indexes =
{
// Add the default primary key
$options = $table->getOptions();
- if (!isset($options['id']) || (isset($options['id']) && $options['id'] === true)) {
+ if (!isset($options['id']) || ($options['id'] === true)) {
$options['id'] = 'id';
}
- if (isset($options['id']) && is_string($options['id'])) {
+ if (is_string($options['id'])) {
// Handle id => "field_name" to support AUTO_INCREMENT
$column = new Column();
$column->setName($options['id'])
diff --git a/src/Db/Adapter/SqlserverAdapter.php b/src/Db/Adapter/SqlserverAdapter.php
index 99f0ec4f..0e3b43c0 100644
--- a/src/Db/Adapter/SqlserverAdapter.php
+++ b/src/Db/Adapter/SqlserverAdapter.php
@@ -137,11 +137,11 @@ public function createTable(Table $table, array $columns = [], array $indexes =
$options = $table->getOptions();
// Add the default primary key
- if (!isset($options['id']) || (isset($options['id']) && $options['id'] === true)) {
+ if (!isset($options['id']) || $options['id'] === true) {
$options['id'] = 'id';
}
- if (isset($options['id']) && is_string($options['id'])) {
+ if (is_string($options['id'])) {
// Handle id => "field_name" to support AUTO_INCREMENT
$column = new Column();
$column->setName($options['id'])
diff --git a/src/Migration/Environment.php b/src/Migration/Environment.php
index 47ea5ee1..cd11a46e 100644
--- a/src/Migration/Environment.php
+++ b/src/Migration/Environment.php
@@ -155,9 +155,7 @@ public function executeSeed(SeedInterface $seed): void
}
// Run the seeder
- if (method_exists($seed, SeedInterface::RUN)) {
- $seed->{SeedInterface::RUN}();
- }
+ $seed->{SeedInterface::RUN}();
// commit the transaction if the adapter supports it
if ($atomic) {
diff --git a/src/Migration/PhinxBackend.php b/src/Migration/PhinxBackend.php
index 14ad28a7..68474a8b 100644
--- a/src/Migration/PhinxBackend.php
+++ b/src/Migration/PhinxBackend.php
@@ -13,6 +13,7 @@
*/
namespace Migrations\Migration;
+use Cake\Database\Connection;
use Cake\Datasource\ConnectionManager;
use DateTime;
use InvalidArgumentException;
@@ -339,10 +340,10 @@ public function setAdapter(): void
return;
}
- /** @var string $connectionName */
$connectionName = $this->input()->getOption('connection') ?: 'default';
- /** @var \Cake\Database\Connection $connection */
+ assert(is_string($connectionName), 'Connection name should be a string');
$connection = ConnectionManager::get($connectionName);
+ assert($connection instanceof Connection, 'Connection should be an instance of Cake\Database\Connection');
/** @psalm-suppress PossiblyNullReference */
$env = $this->manager->getEnvironment('default');
diff --git a/src/Migrations.php b/src/Migrations.php
index 71859f89..d089f618 100644
--- a/src/Migrations.php
+++ b/src/Migrations.php
@@ -14,6 +14,7 @@
namespace Migrations;
use Cake\Core\Configure;
+use Cake\Database\Connection;
use Cake\Datasource\ConnectionManager;
use InvalidArgumentException;
use Migrations\Migration\BackendInterface;
@@ -296,10 +297,10 @@ public function setAdapter(): void
return;
}
- /** @var string $connectionName */
$connectionName = $this->input()->getOption('connection') ?: 'default';
- /** @var \Cake\Database\Connection $connection */
+ assert(is_string($connectionName), 'Connection name must be a string');
$connection = ConnectionManager::get($connectionName);
+ assert($connection instanceof Connection, 'Connection must be an instance of \Cake\Database\Connection');
/** @psalm-suppress PossiblyNullReference */
$env = $this->manager->getEnvironment('default');
diff --git a/src/Util/SchemaTrait.php b/src/Util/SchemaTrait.php
index f68a84cb..9891af7a 100644
--- a/src/Util/SchemaTrait.php
+++ b/src/Util/SchemaTrait.php
@@ -34,7 +34,7 @@ protected function _getSchema(InputInterface $input, OutputInterface $output): ?
{
/** @var string $connectionName */
$connectionName = $input->getOption('connection');
- /** @var \Cake\Database\Connection $connection */
+ /** @var \Cake\Database\Connection|\Cake\Datasource\ConnectionInterface $connection */
$connection = ConnectionManager::get($connectionName);
if (!method_exists($connection, 'getSchemaCollection')) {