From 45373b557107ba4776529cc030c25fe9914b9646 Mon Sep 17 00:00:00 2001 From: michalsn Date: Fri, 16 Jan 2026 11:52:44 +0100 Subject: [PATCH 1/3] fix: make seeder to respect database group --- system/Database/Seeder.php | 16 ++-- .../Database/Seeds/SeederWithDBGroup.php | 51 +++++++++++++ .../Database/Seeds/SeederWithoutDBGroup.php | 49 +++++++++++++ tests/system/Database/DatabaseSeederTest.php | 73 ++++++++++++++++++- user_guide_src/source/changelogs/v4.6.5.rst | 2 + user_guide_src/source/dbmgmt/seeds.rst | 23 ++++++ user_guide_src/source/dbmgmt/seeds/005.php | 4 + user_guide_src/source/dbmgmt/seeds/006.php | 15 ++++ 8 files changed, 227 insertions(+), 6 deletions(-) create mode 100644 tests/_support/Database/Seeds/SeederWithDBGroup.php create mode 100644 tests/_support/Database/Seeds/SeederWithoutDBGroup.php create mode 100644 user_guide_src/source/dbmgmt/seeds/005.php create mode 100644 user_guide_src/source/dbmgmt/seeds/006.php diff --git a/system/Database/Seeder.php b/system/Database/Seeder.php index aacc8e9905ce..e3c867f1cff2 100644 --- a/system/Database/Seeder.php +++ b/system/Database/Seeder.php @@ -92,10 +92,16 @@ public function __construct(Database $config, ?BaseConnection $db = null) $this->config = &$config; - $db ??= Database::connect($this->DBGroup); - - $this->db = $db; - $this->forge = Database::forge($this->DBGroup); + if (isset($this->DBGroup)) { + $this->db = Database::connect($this->DBGroup); + $this->forge = Database::forge($this->DBGroup); + } elseif ($db instanceof BaseConnection) { + $this->db = $db; + $this->forge = Database::forge($db); + } else { + $this->db = Database::connect($config->defaultGroup); + $this->forge = Database::forge($config->defaultGroup); + } } /** @@ -145,7 +151,7 @@ public function call(string $class) } /** @var Seeder $seeder */ - $seeder = new $class($this->config); + $seeder = new $class($this->config, $this->db); $seeder->setSilent($this->silent)->run(); unset($seeder); diff --git a/tests/_support/Database/Seeds/SeederWithDBGroup.php b/tests/_support/Database/Seeds/SeederWithDBGroup.php new file mode 100644 index 000000000000..d25fb657bebf --- /dev/null +++ b/tests/_support/Database/Seeds/SeederWithDBGroup.php @@ -0,0 +1,51 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace Tests\Support\Database\Seeds; + +use CodeIgniter\Database\BaseConnection; +use CodeIgniter\Database\Seeder; + +/** + * Test seeder with explicit DBGroup set. + */ +class SeederWithDBGroup extends Seeder +{ + protected $DBGroup = 'tests'; + + /** + * Store the connection used during run() for testing. + */ + public static ?BaseConnection $lastConnection = null; + + public function run(): void + { + self::$lastConnection = $this->db; + } + + /** + * Expose the db connection for testing. + */ + public function getDatabase(): BaseConnection + { + return $this->db; + } + + /** + * Reset static state for testing. + */ + public static function reset(): void + { + self::$lastConnection = null; + } +} diff --git a/tests/_support/Database/Seeds/SeederWithoutDBGroup.php b/tests/_support/Database/Seeds/SeederWithoutDBGroup.php new file mode 100644 index 000000000000..31ff72598eaf --- /dev/null +++ b/tests/_support/Database/Seeds/SeederWithoutDBGroup.php @@ -0,0 +1,49 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace Tests\Support\Database\Seeds; + +use CodeIgniter\Database\BaseConnection; +use CodeIgniter\Database\Seeder; + +/** + * Test seeder without DBGroup set (should inherit connection). + */ +class SeederWithoutDBGroup extends Seeder +{ + /** + * Store the connection used during run() for testing. + */ + public static ?BaseConnection $lastConnection = null; + + public function run(): void + { + self::$lastConnection = $this->db; + } + + /** + * Expose the db connection for testing. + */ + public function getDatabase(): BaseConnection + { + return $this->db; + } + + /** + * Reset static state for testing. + */ + public static function reset(): void + { + self::$lastConnection = null; + } +} diff --git a/tests/system/Database/DatabaseSeederTest.php b/tests/system/Database/DatabaseSeederTest.php index 398052636246..9e6fbfc4dfe8 100644 --- a/tests/system/Database/DatabaseSeederTest.php +++ b/tests/system/Database/DatabaseSeederTest.php @@ -17,13 +17,27 @@ use Config\Database; use Faker\Generator; use PHPUnit\Framework\Attributes\Group; +use Tests\Support\Database\Seeds\SeederWithDBGroup; +use Tests\Support\Database\Seeds\SeederWithoutDBGroup; /** * @internal */ -#[Group('Others')] +#[Group('DatabaseLive')] final class DatabaseSeederTest extends CIUnitTestCase { + protected function tearDown(): void + { + parent::tearDown(); + + $instances = Database::getConnections(); + unset($instances['default']); + $this->setPrivateProperty(Database::class, 'instances', $instances); + + SeederWithDBGroup::reset(); + SeederWithoutDBGroup::reset(); + } + public function testInstantiateNoSeedPath(): void { $this->expectException('InvalidArgumentException'); @@ -57,4 +71,61 @@ public function testCallOnEmptySeeder(): void $seeder = new Seeder(new Database()); $seeder->call(''); } + + public function testSeederWithDBGroupUsesOwnConnection(): void + { + $config = new Database(); + $db = Database::connect('default'); + + $seeder = new SeederWithDBGroup($config, $db); + + // Should use 'tests' connection (from DBGroup), not the passed 'default' connection + $testsDb = Database::connect('tests'); + $this->assertSame($testsDb, $seeder->getDatabase()); + $this->assertNotSame($db, $seeder->getDatabase()); + } + + public function testSeederWithoutDBGroupUsesPassedConnection(): void + { + $config = new Database(); + $db = Database::connect('tests'); + + $seeder = new SeederWithoutDBGroup($config, $db); + + $this->assertSame($db, $seeder->getDatabase()); + } + + public function testSeederWithoutDBGroupAndNoConnectionUsesDefault(): void + { + $config = new Database(); + + $seeder = new SeederWithoutDBGroup($config); + + $defaultDb = Database::connect($config->defaultGroup); + $this->assertSame($defaultDb, $seeder->getDatabase()); + } + + public function testCallPassesConnectionToChildSeeder(): void + { + $config = new Database(); + $db = Database::connect('tests'); + + $seeder = new Seeder($config, $db); + $seeder->setSilent(true)->call(SeederWithoutDBGroup::class); + + $this->assertSame($db, SeederWithoutDBGroup::$lastConnection); + } + + public function testCallChildWithDBGroupUsesOwnConnection(): void + { + $config = new Database(); + $db = Database::connect('default'); + + $seeder = new Seeder($config, $db); + $seeder->setSilent(true)->call(SeederWithDBGroup::class); + + $testsDb = Database::connect('tests'); + $this->assertSame($testsDb, SeederWithDBGroup::$lastConnection); + $this->assertNotSame($db, SeederWithDBGroup::$lastConnection); + } } diff --git a/user_guide_src/source/changelogs/v4.6.5.rst b/user_guide_src/source/changelogs/v4.6.5.rst index 0ae6d47fe1be..98f3558dee92 100644 --- a/user_guide_src/source/changelogs/v4.6.5.rst +++ b/user_guide_src/source/changelogs/v4.6.5.rst @@ -30,6 +30,8 @@ Deprecations Bugs Fixed ********** +- **Database:** Fixed a bug where ``Seeder::call()`` did not pass the database connection to child seeders, causing them to use the default connection instead of the one specified via ``Database::seeder('group')``. + See the repo's `CHANGELOG.md `_ for a complete list of bugs fixed. diff --git a/user_guide_src/source/dbmgmt/seeds.rst b/user_guide_src/source/dbmgmt/seeds.rst index ded3836f36cd..dce9aa7cb6fc 100644 --- a/user_guide_src/source/dbmgmt/seeds.rst +++ b/user_guide_src/source/dbmgmt/seeds.rst @@ -44,6 +44,29 @@ You can grab a copy of the main seeder through the database config class: .. literalinclude:: seeds/004.php +Using a Different Database Group +================================ + +You can specify a different database group when obtaining a seeder instance by passing the group name +as the first parameter: + +.. literalinclude:: seeds/005.php + +When using ``call()`` to run child seeders, the database connection is automatically passed to them. +This means child seeders will use the same connection as the parent seeder, unless they explicitly +specify their own ``$DBGroup`` property. + +If a seeder needs to always use a specific database group regardless of the parent seeder's connection, +you can set the ``$DBGroup`` property in the seeder class: + +.. literalinclude:: seeds/006.php + +The connection priority is: + +1. If ``$DBGroup`` is set in the seeder class, that connection group is always used +2. Otherwise, if a connection was passed (from parent seeder via ``call()`` or from ``Database::seeder()``), it is used +3. Otherwise, the default connection group is used + Command Line Seeding ==================== diff --git a/user_guide_src/source/dbmgmt/seeds/005.php b/user_guide_src/source/dbmgmt/seeds/005.php new file mode 100644 index 000000000000..e709278fc4be --- /dev/null +++ b/user_guide_src/source/dbmgmt/seeds/005.php @@ -0,0 +1,4 @@ +call('TestSeeder'); diff --git a/user_guide_src/source/dbmgmt/seeds/006.php b/user_guide_src/source/dbmgmt/seeds/006.php new file mode 100644 index 000000000000..2ed2044c93c8 --- /dev/null +++ b/user_guide_src/source/dbmgmt/seeds/006.php @@ -0,0 +1,15 @@ + Date: Fri, 16 Jan 2026 12:01:28 +0100 Subject: [PATCH 2/3] fix phpstan --- system/Database/Seeder.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/Database/Seeder.php b/system/Database/Seeder.php index e3c867f1cff2..632008176031 100644 --- a/system/Database/Seeder.php +++ b/system/Database/Seeder.php @@ -27,7 +27,7 @@ class Seeder /** * The name of the database group to use. * - * @var non-empty-string + * @var non-empty-string|null */ protected $DBGroup; From 2cac8cc8b2c8bb7ba9a5dbb5f703da7a2bdfdadb Mon Sep 17 00:00:00 2001 From: michalsn Date: Fri, 16 Jan 2026 18:13:47 +0100 Subject: [PATCH 3/3] update tests --- tests/system/Database/DatabaseSeederTest.php | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/tests/system/Database/DatabaseSeederTest.php b/tests/system/Database/DatabaseSeederTest.php index 9e6fbfc4dfe8..e00599e26507 100644 --- a/tests/system/Database/DatabaseSeederTest.php +++ b/tests/system/Database/DatabaseSeederTest.php @@ -30,10 +30,6 @@ protected function tearDown(): void { parent::tearDown(); - $instances = Database::getConnections(); - unset($instances['default']); - $this->setPrivateProperty(Database::class, 'instances', $instances); - SeederWithDBGroup::reset(); SeederWithoutDBGroup::reset(); } @@ -75,11 +71,10 @@ public function testCallOnEmptySeeder(): void public function testSeederWithDBGroupUsesOwnConnection(): void { $config = new Database(); - $db = Database::connect('default'); + $db = Database::connect('tests', false); $seeder = new SeederWithDBGroup($config, $db); - // Should use 'tests' connection (from DBGroup), not the passed 'default' connection $testsDb = Database::connect('tests'); $this->assertSame($testsDb, $seeder->getDatabase()); $this->assertNotSame($db, $seeder->getDatabase()); @@ -119,7 +114,7 @@ public function testCallPassesConnectionToChildSeeder(): void public function testCallChildWithDBGroupUsesOwnConnection(): void { $config = new Database(); - $db = Database::connect('default'); + $db = Database::connect('tests', false); $seeder = new Seeder($config, $db); $seeder->setSilent(true)->call(SeederWithDBGroup::class);