diff --git a/README.md b/README.md
index 5cff204e..22321f04 100644
--- a/README.md
+++ b/README.md
@@ -69,6 +69,7 @@ Add following line into the `Register Service Providers` section.
```php
$app->register(\KitLoong\MigrationsGenerator\MigrationsGeneratorServiceProvider::class);
```
+
## Usage
@@ -105,7 +106,7 @@ php artisan migrate:generate --connection="connection_name"
### Squash Migrations
-By default, Generator will generate multiple migration files for each table.
+By default, Generator will generate multiple migration files for each table.
You can squash all migrations into a single file with:
@@ -134,6 +135,7 @@ Run `php artisan help migrate:generate` for a list of options.
| --default-fk-names | Don\'t use DB foreign key names for migrations |
| --use-db-collation | Generate migrations with existing DB collation |
| --skip-log | Don\'t log into migrations table |
+| --skip-vendor | Don\'t generate vendor migrations |
| --skip-views | Don\'t generate views |
| --skip-proc | Don\'t generate stored procedures |
| --squash | Generate all migrations into a single file |
diff --git a/phpcs.xml b/phpcs.xml
index 23afd992..69b85ae5 100644
--- a/phpcs.xml
+++ b/phpcs.xml
@@ -144,6 +144,7 @@
+
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index bfcbc1ab..b18123a7 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -1,21 +1,23 @@
-
-
+
+
+
+ tests
+
+
+
-
-
- tests
-
-
+
diff --git a/src/MigrateGenerateCommand.php b/src/MigrateGenerateCommand.php
index 0194dfba..ef2e9154 100644
--- a/src/MigrateGenerateCommand.php
+++ b/src/MigrateGenerateCommand.php
@@ -11,6 +11,7 @@
use Illuminate\Support\Facades\DB;
use KitLoong\MigrationsGenerator\Enum\Driver;
use KitLoong\MigrationsGenerator\Migration\ForeignKeyMigration;
+use KitLoong\MigrationsGenerator\Migration\Migrator\Migrator;
use KitLoong\MigrationsGenerator\Migration\ProcedureMigration;
use KitLoong\MigrationsGenerator\Migration\Squash;
use KitLoong\MigrationsGenerator\Migration\TableMigration;
@@ -50,6 +51,7 @@ class MigrateGenerateCommand extends Command
{--default-fk-names : Don\'t use DB foreign key names for migrations}
{--use-db-collation : Generate migrations with existing DB collation}
{--skip-log : Don\'t log into migrations table}
+ {--skip-vendor : Don\'t generate vendor migrations}
{--skip-views : Don\'t generate views}
{--skip-proc : Don\'t generate stored procedures}
{--squash : Generate all migrations into a single file}
@@ -300,7 +302,12 @@ protected function getExcludedTables(): array
$ignore = (string) $this->option('ignore');
if (!empty($ignore)) {
- return array_merge([$migrationTable], explode(',', $ignore));
+ $excludes = array_merge($excludes, explode(',', $ignore));
+ }
+
+ if ($this->option('skip-vendor')) {
+ $vendorTables = app(Migrator::class)->getVendorTableNames();
+ $excludes = array_merge($excludes, $vendorTables);
}
return $excludes;
diff --git a/src/Migration/Migrator/Migrator.php b/src/Migration/Migrator/Migrator.php
new file mode 100644
index 00000000..1e82a4b2
--- /dev/null
+++ b/src/Migration/Migrator/Migrator.php
@@ -0,0 +1,91 @@
+ 'sqlite',
+ 'database' => ':memory:',
+ ]);
+
+ DB::setDefaultConnection('lgm_sqlite');
+
+ $vendorPaths = app('migrator')->paths();
+
+ foreach ($vendorPaths as $path) {
+ $files = File::files($path);
+
+ foreach ($files as $file) {
+ $queries = $this->getMigrationQueries($file->getPathname());
+
+ foreach ($queries as $q) {
+ $matched = Regex::match('/^create table ["|`](.*?)["|`]/', $q['query']);
+
+ if ($matched === '') {
+ continue;
+ }
+
+ $tables[] = $matched;
+ }
+ }
+ }
+ } finally {
+ // Restore backup DB connection.
+ DB::setDefaultConnection($previousConnection);
+ }
+
+ return $tables;
+ }
+
+ /**
+ * Resolve migration instance from `$path` and get all of the queries that would be run for a migration.
+ *
+ * @return array>, 'time': float|null}>
+ */
+ protected function getMigrationQueries(string $path): array
+ {
+ $migration = $this->resolveMigration($path);
+
+ return $this->getQueries($migration, 'up');
+ }
+
+ /**
+ * Resolve migration instance with backward compatibility.
+ *
+ * @return object
+ */
+ protected function resolveMigration(string $path)
+ {
+ if (method_exists(DefaultMigrator::class, 'resolvePath')) {
+ return $this->resolvePath($path);
+ }
+
+ // @codeCoverageIgnoreStart
+ return $this->resolve(
+ $this->getMigrationName($path)
+ );
+ // @codeCoverageIgnoreEnd
+ }
+}
diff --git a/src/MigrationsGeneratorServiceProvider.php b/src/MigrationsGeneratorServiceProvider.php
index 17ff7fe9..b5d66a22 100644
--- a/src/MigrationsGeneratorServiceProvider.php
+++ b/src/MigrationsGeneratorServiceProvider.php
@@ -20,6 +20,7 @@
use KitLoong\MigrationsGenerator\Migration\Generator\Columns\PresetValuesColumn;
use KitLoong\MigrationsGenerator\Migration\Generator\Columns\SoftDeleteColumn;
use KitLoong\MigrationsGenerator\Migration\Generator\Columns\StringColumn;
+use KitLoong\MigrationsGenerator\Migration\Migrator\Migrator;
use KitLoong\MigrationsGenerator\Repositories\MariaDBRepository;
use KitLoong\MigrationsGenerator\Repositories\MySQLRepository;
use KitLoong\MigrationsGenerator\Repositories\PgSQLRepository;
@@ -34,9 +35,6 @@ class MigrationsGeneratorServiceProvider extends ServiceProvider
{
/**
* Register the service provider.
- *
- * @throws \Illuminate\Contracts\Container\BindingResolutionException
- * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
*/
public function register(): void
{
@@ -69,13 +67,23 @@ public function register(): void
}
// Bind the Repository Interface to $app['migrations.repository']
- $this->app->bind(
+ $this->app->singleton(
MigrationRepositoryInterface::class,
function ($app) {
return $app['migration.repository'];
}
);
+ // Backward compatible for older Laravel version which failed to resolve Illuminate\Database\ConnectionResolverInterface.
+ $this->app->singleton(
+ Migrator::class,
+ function ($app) {
+ $repository = $app['migration.repository'];
+
+ return new Migrator($repository, $app['db'], $app['files'], $app['events']);
+ }
+ );
+
$this->registerColumnTypeGenerator();
}
@@ -92,9 +100,6 @@ public function boot(): void
/**
* Register the config path.
- *
- * @throws \Illuminate\Contracts\Container\BindingResolutionException
- * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
*/
protected function registerConfig(): void
{
diff --git a/tests/Feature/FeatureTestCase.php b/tests/Feature/FeatureTestCase.php
index 950efa77..ddeac5b6 100644
--- a/tests/Feature/FeatureTestCase.php
+++ b/tests/Feature/FeatureTestCase.php
@@ -81,6 +81,11 @@ protected function getStorageFromPath(string $path = ''): string
return storage_path('from') . ($path ? DIRECTORY_SEPARATOR . $path : $path);
}
+ protected function getStorageFromVendorsPath(string $path = ''): string
+ {
+ return storage_path("from/vendors") . ($path ? DIRECTORY_SEPARATOR . $path : $path);
+ }
+
protected function getStorageSqlPath(string $path = ''): string
{
return storage_path('sql') . ($path ? DIRECTORY_SEPARATOR . $path : $path);
@@ -96,6 +101,11 @@ protected function migrateCollation(string $connection): void
$this->migrateFromTemplate($connection, base_path('tests/resources/database/migrations/collation'));
}
+ protected function migrateVendors(string $connection): void
+ {
+ $this->migrateFromVendorsTemplate($connection, base_path('tests/resources/database/migrations/vendors'));
+ }
+
protected function migrateFromTemplate(string $connection, string $templatePath): void
{
File::copyDirectory($templatePath, $this->getStorageFromPath());
@@ -119,6 +129,29 @@ protected function migrateFromTemplate(string $connection, string $templatePath)
$this->runMigrationsFrom($connection, $this->getStorageFromPath());
}
+ protected function migrateFromVendorsTemplate(string $connection, string $templatePath): void
+ {
+ File::copyDirectory($templatePath, $this->getStorageFromVendorsPath());
+
+ foreach (File::files($this->getStorageFromVendorsPath()) as $file) {
+ $content = str_replace([
+ '[db]',
+ '_DB_',
+ ], [
+ $connection,
+ ucfirst("$connection"),
+ ], $file->getContents());
+
+ File::put($this->getStorageFromVendorsPath($file->getBasename()), $content);
+ File::move(
+ $this->getStorageFromVendorsPath($file->getBasename()),
+ $this->getStorageFromVendorsPath(str_replace('_db_', "_{$connection}_", $file->getBasename()))
+ );
+ }
+
+ $this->runMigrationsFrom($connection, $this->getStorageFromVendorsPath());
+ }
+
protected function runMigrationsFrom(string $connection, string $path): void
{
$this->artisan('migrate', [
diff --git a/tests/Feature/MySQL57/CommandTest.php b/tests/Feature/MySQL57/CommandTest.php
index 4fce7119..033e2882 100644
--- a/tests/Feature/MySQL57/CommandTest.php
+++ b/tests/Feature/MySQL57/CommandTest.php
@@ -3,6 +3,7 @@
namespace KitLoong\MigrationsGenerator\Tests\Feature\MySQL57;
use Illuminate\Database\Migrations\MigrationRepositoryInterface;
+use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Schema;
@@ -508,6 +509,48 @@ public function testLogWithBatchNaN(): void
);
}
+ public function testSkipVendor(): void
+ {
+ $this->migrateGeneral('mysql57');
+
+ $this->migrateVendors('mysql57');
+
+ // Load migrations from vendors path to mock vendors migration.
+ // Loaded migrations should not be generated.
+ app('migrator')->path($this->getStorageFromVendorsPath());
+
+ $tables = $this->getTableNames();
+
+ $vendors = [
+ 'personal_access_tokens_mysql57',
+ 'telescope_entries_mysql57',
+ 'telescope_entries_tags_mysql57',
+ 'telescope_monitoring_mysql57',
+ ];
+
+ foreach ($vendors as $vendor) {
+ $this->assertContains($vendor, $tables);
+ }
+
+ $tablesWithoutVendors = (new Collection($tables))->filter(function ($table) use ($vendors) {
+ return !in_array($table, $vendors);
+ })
+ ->values()
+ ->all();
+
+ $this->truncateMigrationsTable();
+
+ $this->generateMigrations(['--skip-vendor' => true]);
+
+ $this->refreshDatabase();
+
+ $this->runMigrationsFrom('mysql57', $this->getStorageMigrationsPath());
+
+ $generatedTables = $this->getTableNames();
+
+ $this->assertSame($tablesWithoutVendors, $generatedTables);
+ }
+
private function verify(callable $migrateTemplates, callable $generateMigrations): void
{
$migrateTemplates();
diff --git a/tests/Feature/MySQL8/CommandTest.php b/tests/Feature/MySQL8/CommandTest.php
index 2af4358c..c877d0e3 100644
--- a/tests/Feature/MySQL8/CommandTest.php
+++ b/tests/Feature/MySQL8/CommandTest.php
@@ -2,6 +2,7 @@
namespace KitLoong\MigrationsGenerator\Tests\Feature\MySQL8;
+use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
/**
@@ -54,6 +55,48 @@ public function testCollation(): void
$this->verify($migrateTemplates, $generateMigrations);
}
+ public function testSkipVendor(): void
+ {
+ $this->migrateGeneral('mysql8');
+
+ $this->migrateVendors('mysql8');
+
+ // Load migrations from vendors path to mock vendors migration.
+ // Loaded migrations should not be generated.
+ app('migrator')->path($this->getStorageFromVendorsPath());
+
+ $tables = $this->getTableNames();
+
+ $vendors = [
+ 'personal_access_tokens_mysql8',
+ 'telescope_entries_mysql8',
+ 'telescope_entries_tags_mysql8',
+ 'telescope_monitoring_mysql8',
+ ];
+
+ foreach ($vendors as $vendor) {
+ $this->assertContains($vendor, $tables);
+ }
+
+ $tablesWithoutVendors = (new Collection($tables))->filter(function ($table) use ($vendors) {
+ return !in_array($table, $vendors);
+ })
+ ->values()
+ ->all();
+
+ $this->truncateMigrationsTable();
+
+ $this->generateMigrations(['--skip-vendor' => true]);
+
+ $this->refreshDatabase();
+
+ $this->runMigrationsFrom('mysql8', $this->getStorageMigrationsPath());
+
+ $generatedTables = $this->getTableNames();
+
+ $this->assertSame($tablesWithoutVendors, $generatedTables);
+ }
+
private function verify(callable $migrateTemplates, callable $generateMigrations): void
{
$migrateTemplates();
diff --git a/tests/Feature/PgSQL/CommandTest.php b/tests/Feature/PgSQL/CommandTest.php
index bca5de8c..816a7386 100644
--- a/tests/Feature/PgSQL/CommandTest.php
+++ b/tests/Feature/PgSQL/CommandTest.php
@@ -2,6 +2,7 @@
namespace KitLoong\MigrationsGenerator\Tests\Feature\PgSQL;
+use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
@@ -170,6 +171,51 @@ public function testWithHasTableSquash(): void
$this->verify($migrateTemplates, $generateMigrations);
}
+ public function testSkipVendor(): void
+ {
+ $this->migrateGeneral('pgsql');
+
+ $this->migrateVendors('pgsql');
+
+ // Load migrations from vendors path to mock vendors migration.
+ // Loaded migrations should not be generated.
+ app('migrator')->path($this->getStorageFromVendorsPath());
+
+ $tables = $this->getTableNames();
+
+ $vendors = [
+ 'personal_access_tokens_pgsql',
+ 'telescope_entries_pgsql',
+ 'telescope_entries_tags_pgsql',
+ 'telescope_monitoring_pgsql',
+ ];
+
+ foreach ($vendors as $vendor) {
+ $this->assertContains($vendor, $tables);
+ }
+
+ $tablesWithoutVendors = (new Collection($tables))->filter(function ($table) use ($vendors) {
+ return !in_array($table, $vendors);
+ })
+ ->values()
+ ->all();
+
+ $this->truncateMigrationsTable();
+
+ $this->generateMigrations(['--skip-vendor' => true]);
+
+ $this->refreshDatabase();
+
+ $this->runMigrationsFrom('pgsql', $this->getStorageMigrationsPath());
+
+ $generatedTables = $this->getTableNames();
+
+ sort($tablesWithoutVendors);
+ sort($generatedTables);
+
+ $this->assertSame($tablesWithoutVendors, $generatedTables);
+ }
+
private function verify(callable $migrateTemplates, callable $generateMigrations, ?callable $beforeVerify = null): void
{
$migrateTemplates();
diff --git a/tests/Feature/SQLSrv/CommandTest.php b/tests/Feature/SQLSrv/CommandTest.php
index 07966cfb..c5e03b92 100644
--- a/tests/Feature/SQLSrv/CommandTest.php
+++ b/tests/Feature/SQLSrv/CommandTest.php
@@ -2,6 +2,7 @@
namespace KitLoong\MigrationsGenerator\Tests\Feature\SQLSrv;
+use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
@@ -126,6 +127,48 @@ public function testGenerateXml(): void
$this->assertTrue(true);
}
+ public function testSkipVendor(): void
+ {
+ $this->migrateGeneral('sqlsrv');
+
+ $this->migrateVendors('sqlsrv');
+
+ // Load migrations from vendors path to mock vendors migration.
+ // Loaded migrations should not be generated.
+ app('migrator')->path($this->getStorageFromVendorsPath());
+
+ $tables = $this->getTableNames();
+
+ $vendors = [
+ 'personal_access_tokens_sqlsrv',
+ 'telescope_entries_sqlsrv',
+ 'telescope_entries_tags_sqlsrv',
+ 'telescope_monitoring_sqlsrv',
+ ];
+
+ foreach ($vendors as $vendor) {
+ $this->assertContains($vendor, $tables);
+ }
+
+ $tablesWithoutVendors = (new Collection($tables))->filter(function ($table) use ($vendors) {
+ return !in_array($table, $vendors);
+ })
+ ->values()
+ ->all();
+
+ $this->truncateMigrationsTable();
+
+ $this->generateMigrations(['--skip-vendor' => true]);
+
+ $this->refreshDatabase();
+
+ $this->runMigrationsFrom('sqlsrv', $this->getStorageMigrationsPath());
+
+ $generatedTables = $this->getTableNames();
+
+ $this->assertSame($tablesWithoutVendors, $generatedTables);
+ }
+
/**
* @throws \Doctrine\DBAL\Exception
*/
diff --git a/tests/Feature/SQLite/CommandTest.php b/tests/Feature/SQLite/CommandTest.php
index b4ddc55f..4ded17f3 100644
--- a/tests/Feature/SQLite/CommandTest.php
+++ b/tests/Feature/SQLite/CommandTest.php
@@ -2,6 +2,7 @@
namespace KitLoong\MigrationsGenerator\Tests\Feature\SQLite;
+use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use KitLoong\MigrationsGenerator\Support\CheckMigrationMethod;
@@ -57,6 +58,48 @@ public function testCollation(): void
$this->verify($migrateTemplates, $generateMigrations);
}
+ public function testSkipVendor(): void
+ {
+ $this->migrateGeneral('sqlite');
+
+ $this->migrateVendors('sqlite');
+
+ // Load migrations from vendors path to mock vendors migration.
+ // Loaded migrations should not be generated.
+ app('migrator')->path($this->getStorageFromVendorsPath());
+
+ $tables = $this->getTableNames();
+
+ $vendors = [
+ 'personal_access_tokens_sqlite',
+ 'telescope_entries_sqlite',
+ 'telescope_entries_tags_sqlite',
+ 'telescope_monitoring_sqlite',
+ ];
+
+ foreach ($vendors as $vendor) {
+ $this->assertContains($vendor, $tables);
+ }
+
+ $tablesWithoutVendors = (new Collection($tables))->filter(function ($table) use ($vendors) {
+ return !in_array($table, $vendors);
+ })
+ ->values()
+ ->all();
+
+ $this->truncateMigrationsTable();
+
+ $this->generateMigrations(['--skip-vendor' => true]);
+
+ $this->refreshDatabase();
+
+ $this->runMigrationsFrom('sqlite', $this->getStorageMigrationsPath());
+
+ $generatedTables = $this->getTableNames();
+
+ $this->assertSame($tablesWithoutVendors, $generatedTables);
+ }
+
private function verify(callable $migrateTemplates, callable $generateMigrations): void
{
$migrateTemplates();
diff --git a/tests/resources/database/migrations/general/2020_03_21_000000_expected_create_primary_db_table.php b/tests/resources/database/migrations/general/2020_03_21_000000_expected_create_primary_db_table.php
index 042fd29e..59b9e5a3 100644
--- a/tests/resources/database/migrations/general/2020_03_21_000000_expected_create_primary_db_table.php
+++ b/tests/resources/database/migrations/general/2020_03_21_000000_expected_create_primary_db_table.php
@@ -39,7 +39,7 @@ public function up()
});
// Test short table name
- Schema::create('s[db]', function (Blueprint $table) {
+ Schema::create('s_[db]', function (Blueprint $table) {
$table->bigIncrements('id');
});
}
@@ -55,6 +55,6 @@ public function down()
Schema::dropIfExists('primary_name_[db]');
Schema::dropIfExists('signed_primary_id_[db]');
Schema::dropIfExists('composite_primary_[db]');
- Schema::dropIfExists('s[db]');
+ Schema::dropIfExists('s_[db]');
}
}
diff --git a/tests/resources/database/migrations/vendors/2018_08_08_100000_create_telescope_db_table.php b/tests/resources/database/migrations/vendors/2018_08_08_100000_create_telescope_db_table.php
new file mode 100644
index 00000000..e59a0fe5
--- /dev/null
+++ b/tests/resources/database/migrations/vendors/2018_08_08_100000_create_telescope_db_table.php
@@ -0,0 +1,74 @@
+getConnection());
+
+ $schema->create('telescope_entries_[db]', function (Blueprint $table) {
+ $table->bigIncrements('sequence');
+ $table->uuid('uuid');
+ $table->uuid('batch_id');
+ $table->string('family_hash')->nullable();
+ $table->boolean('should_display_on_index')->default(true);
+ $table->string('type', 20);
+ $table->longText('content');
+ $table->dateTime('created_at')->nullable();
+
+ $table->unique('uuid');
+ $table->index('batch_id');
+ $table->index('family_hash');
+ $table->index('created_at');
+ $table->index(['type', 'should_display_on_index']);
+ });
+
+ $schema->create('telescope_entries_tags_[db]', function (Blueprint $table) {
+ $table->uuid('entry_uuid');
+ $table->string('tag');
+
+ $table->index(['entry_uuid', 'tag']);
+ $table->index('tag');
+
+ $table->foreign('entry_uuid')
+ ->references('uuid')
+ ->on('telescope_entries_[db]')
+ ->onDelete('cascade');
+ });
+
+ $schema->create('telescope_monitoring_[db]', function (Blueprint $table) {
+ $table->string('tag');
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ $schema = Schema::connection($this->getConnection());
+
+ $schema->dropIfExists('telescope_entries_tags_[db]');
+ $schema->dropIfExists('telescope_entries_[db]');
+ $schema->dropIfExists('telescope_monitoring_[db]');
+ }
+}
diff --git a/tests/resources/database/migrations/vendors/2019_12_14_000001_create_personal_access_tokens_db_table.php b/tests/resources/database/migrations/vendors/2019_12_14_000001_create_personal_access_tokens_db_table.php
new file mode 100644
index 00000000..5e1d9010
--- /dev/null
+++ b/tests/resources/database/migrations/vendors/2019_12_14_000001_create_personal_access_tokens_db_table.php
@@ -0,0 +1,37 @@
+bigIncrements('id');
+ $table->morphs('tokenable');
+ $table->string('name');
+ $table->string('token', 64)->unique();
+ $table->text('abilities')->nullable();
+ $table->timestamp('last_used_at')->nullable();
+ $table->timestamp('expires_at')->nullable();
+ $table->timestamps();
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ Schema::dropIfExists('personal_access_tokens_[db]');
+ }
+}