diff --git a/.travis/setup.mysql.sh b/.travis/setup.mysql.sh
index e837c116b..b66581fc3 100755
--- a/.travis/setup.mysql.sh
+++ b/.travis/setup.mysql.sh
@@ -6,6 +6,7 @@ TRAVIS_BUILD_DIR="${TRAVIS_BUILD_DIR:-$(dirname $(dirname $CURRENT_DIR))}"
echo -e "Create MySQL database..."
mysql -h 127.0.0.1 -u root -e "CREATE DATABASE IF NOT EXISTS hyperf charset=utf8mb4 collate=utf8mb4_unicode_ci;"
mysql -h 127.0.0.1 -u root -e "CREATE DATABASE IF NOT EXISTS hyperf2 charset=utf8mb4 collate=utf8mb4_unicode_ci;"
+mysql -h 127.0.0.1 -u root -e "CREATE DATABASE IF NOT EXISTS hyperf3 charset=utf8mb4 collate=utf8mb4_unicode_ci;"
cat "${TRAVIS_BUILD_DIR}/.travis/hyperf.sql" | mysql -h 127.0.0.1 -u root hyperf
echo -e "Done\n"
diff --git a/CHANGELOG-3.1.md b/CHANGELOG-3.1.md
index 4bd226d1c..6e178def3 100644
--- a/CHANGELOG-3.1.md
+++ b/CHANGELOG-3.1.md
@@ -1,5 +1,9 @@
# v3.1.37 - TBD
+## Optimized
+
+- [#6839](https://github.com/hyperf/hyperf/pull/6839) Use `anonymous classes` to avoid the duplicated class name for database migrations.
+
# v3.1.36 - 2024-08-15
## Added
diff --git a/src/database/src/Migrations/MigrationCreator.php b/src/database/src/Migrations/MigrationCreator.php
index e01fc7b53..f0ff6a098 100755
--- a/src/database/src/Migrations/MigrationCreator.php
+++ b/src/database/src/Migrations/MigrationCreator.php
@@ -52,7 +52,7 @@ class MigrationCreator
$this->files->put(
$path = $this->getPath($name, $path),
- $this->populateStub($name, $stub, $table)
+ $this->populateStub($stub, $table)
);
// Next, we will fire any hooks that are supposed to fire after a migration is
@@ -127,10 +127,8 @@ class MigrationCreator
/**
* Populate the place-holders in the migration stub.
*/
- protected function populateStub(string $name, string $stub, ?string $table): string
+ protected function populateStub(string $stub, ?string $table): string
{
- $stub = str_replace('DummyClass', $this->getClassName($name), $stub);
-
// Here we will replace the table place-holders with the table specified by
// the developer, which is useful for quickly creating a tables creation
// or update migration from the console instead of typing it manually.
diff --git a/src/database/src/Migrations/Migrator.php b/src/database/src/Migrations/Migrator.php
index 98b5c4729..aa4f68690 100755
--- a/src/database/src/Migrations/Migrator.php
+++ b/src/database/src/Migrations/Migrator.php
@@ -19,6 +19,7 @@ use Hyperf\Database\ConnectionResolverInterface as Resolver;
use Hyperf\Database\Schema\Grammars\Grammar;
use Hyperf\Stringable\Str;
use Hyperf\Support\Filesystem\Filesystem;
+use ReflectionClass;
use Symfony\Component\Console\Output\OutputInterface;
use Throwable;
@@ -164,7 +165,7 @@ class Migrator
*/
public function resolve(string $file): object
{
- $class = Str::studly(implode('_', array_slice(explode('_', $file), 4)));
+ $class = $this->getMigrationClass($file);
return new $class();
}
@@ -283,6 +284,27 @@ class Migrator
return $this;
}
+ /**
+ * Resolve a migration instance from migration path.
+ */
+ protected function resolvePath(string $path): object
+ {
+ $class = $this->getMigrationClass($this->getMigrationName($path));
+ if (class_exists($class)) {
+ return new $class();
+ }
+
+ return $this->files->getRequire($path);
+ }
+
+ /**
+ * Generate migration class name based on migration name.
+ */
+ protected function getMigrationClass(string $migrationName): string
+ {
+ return Str::studly(implode('_', array_slice(explode('_', $migrationName), 4)));
+ }
+
/**
* Get the migration files that have not yet run.
*/
@@ -304,9 +326,8 @@ class Migrator
// First we will resolve a "real" instance of the migration class from this
// migration file name. Once we have the instances we can run the actual
// command such as "up" or "down", or we can just simulate the action.
- $migration = $this->resolve(
- $name = $this->getMigrationName($file)
- );
+ $migration = $this->resolvePath($file);
+ $name = $this->getMigrationName($file);
if ($pretend) {
$this->pretendToRun($migration, 'up');
@@ -402,9 +423,8 @@ class Migrator
// First we will get the file name of the migration so we can resolve out an
// instance of the migration. Once we get an instance we can either run a
// pretend execution of the migration or we can run the real migration.
- $instance = $this->resolve(
- $name = $this->getMigrationName($file)
- );
+ $instance = $this->resolvePath($file);
+ $name = $this->getMigrationName($file);
$this->note("Rolling back: {$name}");
@@ -459,6 +479,11 @@ class Migrator
foreach ($this->getQueries($migration, $method) as $query) {
$name = get_class($migration);
+ $reflectionClass = new ReflectionClass($migration);
+ if ($reflectionClass->isAnonymous()) {
+ $name = $this->getMigrationName($reflectionClass->getFileName());
+ }
+
$this->note("{$name}: {$query['query']}");
}
}
diff --git a/src/database/src/Migrations/stubs/blank.stub b/src/database/src/Migrations/stubs/blank.stub
index 40b600922..4d2f36eca 100755
--- a/src/database/src/Migrations/stubs/blank.stub
+++ b/src/database/src/Migrations/stubs/blank.stub
@@ -4,7 +4,7 @@ use Hyperf\Database\Schema\Schema;
use Hyperf\Database\Schema\Blueprint;
use Hyperf\Database\Migrations\Migration;
-class DummyClass extends Migration
+return new class extends Migration
{
/**
* Run the migrations.
@@ -21,4 +21,4 @@ class DummyClass extends Migration
{
//
}
-}
+};
diff --git a/src/database/src/Migrations/stubs/create.stub b/src/database/src/Migrations/stubs/create.stub
index b00c4f513..1c5301146 100755
--- a/src/database/src/Migrations/stubs/create.stub
+++ b/src/database/src/Migrations/stubs/create.stub
@@ -4,7 +4,7 @@ use Hyperf\Database\Schema\Schema;
use Hyperf\Database\Schema\Blueprint;
use Hyperf\Database\Migrations\Migration;
-class DummyClass extends Migration
+return new class extends Migration
{
/**
* Run the migrations.
@@ -24,4 +24,4 @@ class DummyClass extends Migration
{
Schema::dropIfExists('DummyTable');
}
-}
+};
diff --git a/src/database/src/Migrations/stubs/update.stub b/src/database/src/Migrations/stubs/update.stub
index 62acd1da5..af8ba1262 100755
--- a/src/database/src/Migrations/stubs/update.stub
+++ b/src/database/src/Migrations/stubs/update.stub
@@ -4,7 +4,7 @@ use Hyperf\Database\Schema\Schema;
use Hyperf\Database\Schema\Blueprint;
use Hyperf\Database\Migrations\Migration;
-class DummyClass extends Migration
+return new class extends Migration
{
/**
* Run the migrations.
@@ -25,4 +25,4 @@ class DummyClass extends Migration
//
});
}
-}
+};
diff --git a/src/database/tests/DatabaseMigrationCreatorTest.php b/src/database/tests/DatabaseMigrationCreatorTest.php
index c117ac6f0..f07a0374b 100755
--- a/src/database/tests/DatabaseMigrationCreatorTest.php
+++ b/src/database/tests/DatabaseMigrationCreatorTest.php
@@ -45,8 +45,8 @@ class DatabaseMigrationCreatorTest extends TestCase
$creator = $this->getCreator();
$creator->expects($this->any())->method('getDatePrefix')->will($this->returnValue('foo'));
- $creator->getFilesystem()->shouldReceive('get')->once()->with($creator->stubPath() . '/blank.stub')->andReturn('DummyClass');
- $creator->getFilesystem()->shouldReceive('put')->once()->with('foo/foo_create_bar.php', 'CreateBar');
+ $creator->getFilesystem()->shouldReceive('get')->once()->with($creator->stubPath() . '/blank.stub')->andReturn('return new class');
+ $creator->getFilesystem()->shouldReceive('put')->once()->with('foo/foo_create_bar.php', 'return new class');
$creator->getFilesystem()->shouldReceive('glob')->once()->with('foo/*.php')->andReturn(['foo/foo_create_bar.php']);
$creator->getFilesystem()->shouldReceive('requireOnce')->once()->with('foo/foo_create_bar.php');
@@ -64,8 +64,8 @@ class DatabaseMigrationCreatorTest extends TestCase
});
$creator->expects($this->any())->method('getDatePrefix')->will($this->returnValue('foo'));
- $creator->getFilesystem()->shouldReceive('get')->once()->with($creator->stubPath() . '/update.stub')->andReturn('DummyClass DummyTable');
- $creator->getFilesystem()->shouldReceive('put')->once()->with('foo/foo_create_bar.php', 'CreateBar baz');
+ $creator->getFilesystem()->shouldReceive('get')->once()->with($creator->stubPath() . '/update.stub')->andReturn('return new class DummyTable');
+ $creator->getFilesystem()->shouldReceive('put')->once()->with('foo/foo_create_bar.php', 'return new class baz');
$creator->getFilesystem()->shouldReceive('glob')->once()->with('foo/*.php')->andReturn(['foo/foo_create_bar.php']);
$creator->getFilesystem()->shouldReceive('requireOnce')->once()->with('foo/foo_create_bar.php');
@@ -80,8 +80,8 @@ class DatabaseMigrationCreatorTest extends TestCase
{
$creator = $this->getCreator();
$creator->expects($this->any())->method('getDatePrefix')->will($this->returnValue('foo'));
- $creator->getFilesystem()->shouldReceive('get')->once()->with($creator->stubPath() . '/update.stub')->andReturn('DummyClass DummyTable');
- $creator->getFilesystem()->shouldReceive('put')->once()->with('foo/foo_create_bar.php', 'CreateBar baz');
+ $creator->getFilesystem()->shouldReceive('get')->once()->with($creator->stubPath() . '/update.stub')->andReturn('return new class DummyTable');
+ $creator->getFilesystem()->shouldReceive('put')->once()->with('foo/foo_create_bar.php', 'return new class baz');
$creator->getFilesystem()->shouldReceive('glob')->once()->with('foo/*.php')->andReturn(['foo/foo_create_bar.php']);
$creator->getFilesystem()->shouldReceive('requireOnce')->once()->with('foo/foo_create_bar.php');
@@ -92,8 +92,8 @@ class DatabaseMigrationCreatorTest extends TestCase
{
$creator = $this->getCreator();
$creator->expects($this->any())->method('getDatePrefix')->will($this->returnValue('foo'));
- $creator->getFilesystem()->shouldReceive('get')->once()->with($creator->stubPath() . '/create.stub')->andReturn('DummyClass DummyTable');
- $creator->getFilesystem()->shouldReceive('put')->once()->with('foo/foo_create_bar.php', 'CreateBar baz');
+ $creator->getFilesystem()->shouldReceive('get')->once()->with($creator->stubPath() . '/create.stub')->andReturn('return new class DummyTable');
+ $creator->getFilesystem()->shouldReceive('put')->once()->with('foo/foo_create_bar.php', 'return new class baz');
$creator->getFilesystem()->shouldReceive('glob')->once()->with('foo/*.php')->andReturn(['foo/foo_create_bar.php']);
$creator->getFilesystem()->shouldReceive('requireOnce')->once()->with('foo/foo_create_bar.php');
diff --git a/src/database/tests/DatabaseMigratorIntegrationTest.php b/src/database/tests/DatabaseMigratorIntegrationTest.php
index e0c4fed66..0e7397bff 100644
--- a/src/database/tests/DatabaseMigratorIntegrationTest.php
+++ b/src/database/tests/DatabaseMigratorIntegrationTest.php
@@ -60,8 +60,10 @@ class DatabaseMigratorIntegrationTest extends TestCase
];
$connection = $connector->make($dbConfig);
+ $connection2 = $connector->make(array_merge($dbConfig, ['database' => 'hyperf2']));
+ $connection3 = $connector->make(array_merge($dbConfig, ['database' => 'hyperf3']));
- $resolver = new ConnectionResolver(['default' => $connection]);
+ $resolver = new ConnectionResolver(['default' => $connection, 'mysql2' => $connection2, 'mysql3' => $connection3]);
$container->shouldReceive('get')->with(ConnectionResolverInterface::class)->andReturn($resolver);
@@ -299,6 +301,23 @@ class DatabaseMigratorIntegrationTest extends TestCase
$builder->drop('test_change_types');
}
+ public function testMigrationsCanEachDefineConnection()
+ {
+ $schema = new Schema();
+
+ $ran = $this->migrator->run([__DIR__ . '/migrations/connection_configured']);
+ $this->assertFalse($schema->hasTable('failed_jobs'));
+ $this->assertFalse($schema->hasTable('jobs'));
+ $this->assertFalse($schema->connection('mysql2')->getSchemaBuilder()->hasTable('failed_jobs'));
+ $this->assertFalse($schema->connection('mysql2')->getSchemaBuilder()->hasTable('jobs'));
+ $this->assertTrue($schema->connection('mysql3')->getSchemaBuilder()->hasTable('failed_jobs'));
+ $this->assertTrue($schema->connection('mysql3')->getSchemaBuilder()->hasTable('jobs'));
+ $this->migrator->rollback([__DIR__ . '/migrations/connection_configured']);
+
+ $this->assertTrue(Str::contains($ran[0], 'failed_jobs'));
+ $this->assertTrue(Str::contains($ran[1], 'jobs'));
+ }
+
protected function getConnection(): Connection
{
return $this->migrator->resolveConnection('default');
diff --git a/src/database/tests/migrations/connection_configured/2024_06_12_000000_create_failed_jobs_table.php b/src/database/tests/migrations/connection_configured/2024_06_12_000000_create_failed_jobs_table.php
new file mode 100644
index 000000000..fa7001314
--- /dev/null
+++ b/src/database/tests/migrations/connection_configured/2024_06_12_000000_create_failed_jobs_table.php
@@ -0,0 +1,44 @@
+id();
+ $table->text('connection');
+ $table->text('queue');
+ $table->longText('payload');
+ $table->longText('exception');
+ $table->timestamp('failed_at')->useCurrent();
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down()
+ {
+ Schema::dropIfExists('failed_jobs');
+ }
+};
diff --git a/src/database/tests/migrations/connection_configured/2024_06_12_120000_create_jobs_table.php b/src/database/tests/migrations/connection_configured/2024_06_12_120000_create_jobs_table.php
new file mode 100644
index 000000000..43c7872be
--- /dev/null
+++ b/src/database/tests/migrations/connection_configured/2024_06_12_120000_create_jobs_table.php
@@ -0,0 +1,40 @@
+connection('mysql3')->getSchemaBuilder()->create('jobs', function (Blueprint $table) {
+ $table->bigIncrements('id');
+ $table->string('queue')->index();
+ $table->longText('payload');
+ $table->unsignedTinyInteger('attempts');
+ $table->unsignedInteger('reserved_at')->nullable();
+ $table->unsignedInteger('available_at');
+ $table->unsignedInteger('created_at');
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down()
+ {
+ (new Schema())->connection('mysql3')->getSchemaBuilder()->dropIfExists('jobs');
+ }
+};