Skip to content

Commit

Permalink
Fix #240: Remove hard dependency on Yii DI, improve config (#246)
Browse files Browse the repository at this point in the history
  • Loading branch information
vjik committed Dec 21, 2023
1 parent 02b6ba5 commit e0e4e49
Show file tree
Hide file tree
Showing 10 changed files with 225 additions and 167 deletions.
61 changes: 0 additions & 61 deletions bin/MigrationContainer.php

This file was deleted.

82 changes: 66 additions & 16 deletions bin/yii-db-migration
Expand Up @@ -3,26 +3,76 @@

declare(strict_types=1);

require './vendor/autoload.php';
require 'MigrationContainer.php';

use Psr\SimpleCache\CacheInterface;
use Psr\Container\ContainerInterface;
use Symfony\Component\Console\Application;
use Yiisoft\Aliases\Aliases;
use Yiisoft\Db\Connection\ConnectionInterface;
use Yiisoft\Di\Container;
use Yiisoft\Di\ContainerConfig;
use Yiisoft\Db\Migration\Command\CreateCommand;
use Yiisoft\Db\Migration\Command\DownCommand;
use Yiisoft\Db\Migration\Command\HistoryCommand;
use Yiisoft\Db\Migration\Command\NewCommand;
use Yiisoft\Db\Migration\Command\RedoCommand;
use Yiisoft\Db\Migration\Command\UpdateCommand;
use Yiisoft\Db\Migration\Informer\ConsoleMigrationInformer;
use Yiisoft\Db\Migration\Migrator;
use Yiisoft\Db\Migration\Runner\DownRunner;
use Yiisoft\Db\Migration\Runner\UpdateRunner;
use Yiisoft\Db\Migration\Service\Generate\CreateService;
use Yiisoft\Db\Migration\Service\MigrationService;
use Yiisoft\Injector\Injector;

$rootPath = dirname(__DIR__, 4);

/** @psalm-suppress UnresolvableInclude, MissingFile */
require $_composer_autoload_path ?? $rootPath . '/vendor/autoload.php';

/**
* @psalm-suppress MissingFile
* @psalm-var array{
* container: ContainerInterface|null,
* db: ConnectionInterface|null,
* useTablePrefix: bool,
* historyTable: string,
* migrationNameLimit: int|null,
* maxSqlOutputLength: int|null,
* createNamespace: string,
* createPath: string,
* updateNamespaces: list<string>,
* updatePaths: list<string>,
* } $params
*/
$params = require $rootPath . '/yii-db-migration.php';

$db = $params['db'] ?? throw new LogicException('DB connection is not configured.');

$containerConfig = ContainerConfig::create()->withDefinitions(MigrationContainer::definitions());
$container = new Container($containerConfig);
$aliases = new Aliases();
$injector = new Injector($params['container']);
$migrationInformer = new ConsoleMigrationInformer();
$migrator = new Migrator(
$db,
$migrationInformer,
$params['historyTable'],
$params['migrationNameLimit'],
$params['maxSqlOutputLength']
);
$createService = new CreateService($aliases, $db, $params['useTablePrefix']);
$downRunner = new DownRunner($migrator);
$updateRunner = new UpdateRunner($migrator);

if ($container->has(CacheInterface::class) === false) {
throw new \RuntimeException('CacheInterface not found in container.');
}
$migrationService = new MigrationService($aliases, $db, $injector, $migrator);
$migrationService->setCreateNamespace($params['createNamespace']);
$migrationService->setCreatePath($params['createPath']);
$migrationService->setUpdateNamespaces($params['updateNamespaces']);
$migrationService->setUpdatePaths($params['updatePaths']);

if ($container->has(ConnectionInterface::class) === false) {
throw new \RuntimeException('ConnectionInterface not found in container.');
}
$application = new Application('Yii Database Migration Tool', '1.0.0');
$application->addCommands([
new CreateCommand($createService, $migrationService, $migrator),
new DownCommand($downRunner, $migrationService, $migrator),
new HistoryCommand($migrationService, $migrator),
new NewCommand($migrationService, $migrator),
new RedoCommand($migrationService, $migrator, $downRunner, $updateRunner),
new UpdateCommand($updateRunner, $migrationService, $migrator),
]);

/** @var Application $application */
$application = $container->get(Application::class);
$application->run();
11 changes: 0 additions & 11 deletions bin/yii-db-migration.bat

This file was deleted.

67 changes: 67 additions & 0 deletions bin/yii-db-migration.php
@@ -0,0 +1,67 @@
<?php

declare(strict_types=1);

return [
/**
* Database connection instance. For example, MySQL connection:
*
* ```php
* 'db' => new \Yiisoft\Db\Mysql\Connection(
* new \Yiisoft\Db\Mysql\Driver('mysql:host=mysql;dbname=mydb', 'user', 'q1w2e3r4'),
* new \Yiisoft\Db\Cache\SchemaCache(new \Yiisoft\Cache\ArrayCache()),
* ),
* ```
*
* @see https://github.com/yiisoft/db/blob/master/docs/en/README.md#create-connection
*/
'db' => null,

/**
* Namespace of new migration classes.
*/
'createNamespace' => '',

/**
* List of namespaces containing the migration classes.
*/
'updateNamespaces' => [],

/**
* Path to the directory for new migration classes. This path is used when you are using migrations without
* namespaces.
*/
'createPath' => '',

/**
* List of directories containing the migration classes. Migration classes located at this paths should be declared
* without a namespace. Use "updateNamespaces" option in case you are using namespaced migrations.
*/
'updatePaths' => [],

/**
* The name of the database table for storing migration history information.
*/
'historyTable' => '{{%migration}}',

/**
* The maximum length of a migration name.
*/
'migrationNameLimit' => 180,

/**
* Indicates whether the table names generated should consider the `tablePrefix` setting of the DB connection.
* For example, if the table name is `post` the generator will return `{{%post}}`.
*/
'useTablePrefix' => true,

/**
* PSR-11 compatible DI container that used for automatic dependencies resolving when creating migration instances.
*/
'container' => null,

/**
* The maximum length of a SQL output in console.
*/
'maxSqlOutputLength' => null,
];
5 changes: 2 additions & 3 deletions composer.json
Expand Up @@ -26,9 +26,7 @@
"symfony/console": "^6.0|^7.0",
"yiisoft/aliases": "^1.1|^2.0|^3.0",
"yiisoft/db": "^1.1",
"yiisoft/di": "^1.0",
"yiisoft/definitions": "^3.0",
"yiisoft/injector": "^1.0"
"yiisoft/injector": "^1.2"
},
"require-dev": {
"maglnet/composer-require-checker": "^4.4",
Expand All @@ -38,6 +36,7 @@
"spatie/phpunit-watcher": "^1.23",
"vimeo/psalm": "^4.30|^5.12",
"yiisoft/db-sqlite": "^1.1",
"yiisoft/di": "^1.2",
"yiisoft/files": "^1.0|^2.0",
"yiisoft/test-support": "^3.0",
"yiisoft/yii-console": "^1.0|^2.0"
Expand Down
87 changes: 12 additions & 75 deletions docs/en/usage-standalone.md
@@ -1,87 +1,24 @@
# Standalone usage

1. Copy configuration file `./vendor/yiisoft/db-migration/bin/MigrationContainer.php` to `root` folder of your project.
1. Copy configuration file `./vendor/yiisoft/db-migration/bin/yii-db-migration.php` to root folder of your project:

```shell
cp ./vendor/yiisoft/db-migration/bin/MigrationContainer.php ./
cp ./vendor/yiisoft/db-migration/bin/yii-db-migration.php ./yii-db-migration.php
```

2. Edit `./MigrationContainer.php` and add definitions for `Psr\SimpleCache\CacheInterface`
and `Yiisoft\Db\Connection\ConnectionInterface`.

Also, configure `MigrationService::class` and `MigrationInformerInterface::class`.

Here's a sample configuration.

2. Define DB connection in configuration file (see
[Yii DB documentation](https://github.com/yiisoft/db/blob/master/docs/en/README.md#create-connection)). For example, MySQL connection:

```php
<?php

declare(strict_types=1);

use Psr\SimpleCache\CacheInterface;
use Symfony\Component\Console\Application;
use Yiisoft\Cache\ArrayCache;
use Yiisoft\Db\Connection\ConnectionInterface;
use Yiisoft\Db\Migration\Command\CreateCommand;
use Yiisoft\Db\Migration\Command\DownCommand;
use Yiisoft\Db\Migration\Command\HistoryCommand;
use Yiisoft\Db\Migration\Command\NewCommand;
use Yiisoft\Db\Migration\Command\RedoCommand;
use Yiisoft\Db\Migration\Command\UpdateCommand;
use Yiisoft\Db\Migration\Informer\MigrationInformerInterface;
use Yiisoft\Db\Migration\Informer\NullMigrationInformer;
use Yiisoft\Db\Migration\Service\MigrationService;
use Yiisoft\Db\Sqlite\Connection;
use Yiisoft\Db\Sqlite\Driver;
use Yiisoft\Definitions\ReferencesArray;

final class MigrationContainer
{
public static function definitions(): array
{
return [
Application::class => [
'__construct()' => [
'name' => 'Yii Database Migration Tool',
'version' => '1.0.0',
],
'addCommands()' => [self::getCommands()],
],
CacheInterface::class => ArrayCache::class,
ConnectionInterface::class => [
'class' => Connection::class,
'__construct()' => [
new Driver('sqlite:./tests/_output/runtime/yiitest.sq3'),
],
],
MigrationService::class => [
'class' => MigrationService::class,
'setCreateNamespace()' => [''],
'setCreatePath()' => [''],
'setUpdateNamespaces()' => [['Yii\\User\\Framework\\Migration']],
'setUpdatePaths()' => [[]],
],
MigrationInformerInterface::class => ConsoleMigrationInformer::class,
];
}

public static function getCommands(): array
{
return ReferencesArray::from(
[
CreateCommand::class,
DownCommand::class,
HistoryCommand::class,
NewCommand::class,
RedoCommand::class,
UpdateCommand::class,
]
);
}
}
'db' => new \Yiisoft\Db\Mysql\Connection(
new \Yiisoft\Db\Mysql\Driver('mysql:host=mysql;dbname=mydb', 'user', 'q1w2e3r4'),
new \Yiisoft\Db\Cache\SchemaCache(new \Yiisoft\Cache\ArrayCache()),
),
```

3. Optionally, modify other options in configuration file. Each option has a comment with description.

3. Run the console command without arguments to see the list of available migration commands:
4. Run the console command without arguments to see the list of available migration commands:

```shell
./vendor/bin/yii-db-migration
Expand Down
1 change: 0 additions & 1 deletion phpunit.xml.dist
Expand Up @@ -35,7 +35,6 @@
<source>
<include>
<directory>./src</directory>
<directory>./bin</directory>
<directory>./config</directory>
</include>
<exclude>
Expand Down
1 change: 1 addition & 0 deletions psalm.xml
Expand Up @@ -10,6 +10,7 @@
<projectFiles>
<directory name="src" />
<directory name="bin" />
<file name="bin/yii-db-migration" />
<ignoreFiles>
<directory name="vendor" />
</ignoreFiles>
Expand Down

0 comments on commit e0e4e49

Please sign in to comment.