pdo = new PDO('sqlite::memory:', null, null, [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, ]); $config = new Config([ 'paths' => ['migrations' => __DIR__ . '/../../../db/migrations'], 'environments' => [ 'default_migration_table' => 'phinxlog', 'default_database' => 'test', 'test' => ['adapter' => 'sqlite', 'connection' => $this->pdo], ], ]); (new Manager($config, new ArrayInput([]), new NullOutput()))->migrate('test'); $this->pdo->exec('PRAGMA foreign_keys = ON'); } public function testRepositoriesShareSamePdoInstance(): void { // L5: assert that the container would wire both repositories to the SAME PDO // instance so the job repository's atomic() is a real transaction, not a no-op. $catalog = new PdoCatalogRepository($this->pdo); $jobs = new PdoImportJobRepository($this->pdo); $reflectionCatalog = new \ReflectionObject($catalog); $reflectionJobs = new \ReflectionObject($jobs); $pdoCatalog = $reflectionCatalog->getProperty('pdo'); $pdoCatalog->setAccessible(true); $pdoJobs = $reflectionJobs->getProperty('pdo'); $pdoJobs->setAccessible(true); self::assertSame( $pdoCatalog->getValue($catalog), $pdoJobs->getValue($jobs), 'CatalogRepository and ImportJobRepository must share the same PDO instance for atomic() to work' ); } public function testAtomicCallbackUsesSharedConnection(): void { $catalog = new PdoCatalogRepository($this->pdo); $jobs = new PdoImportJobRepository($this->pdo); // Test that atomic() on jobs uses the same connection as catalog $called = false; $jobs->atomic(function () use ($jobs, $catalog, &$called): void { $called = true; // Inside the transaction, both repositories should see each other's changes $jobId = $jobs->create('/tmp/source', [ ['source_path' => '/tmp/source/file.stl', 'size' => 100, 'model_id' => null], ]); $items = $jobs->items($jobId); self::assertCount(1, $items); }); self::assertTrue($called); // After commit, the job should be visible $allJobs = $this->pdo->query('SELECT * FROM import_jobs')->fetchAll(PDO::FETCH_ASSOC); self::assertCount(1, $allJobs); } }