diff --git a/composer.json b/composer.json index 9c958f1c4..68ec8bc4f 100644 --- a/composer.json +++ b/composer.json @@ -30,7 +30,8 @@ "illuminate/database": "^10.30|^11", "illuminate/events": "^10.0|^11", "illuminate/support": "^10.0|^11", - "mongodb/mongodb": "^1.18" + "mongodb/mongodb": "^1.18", + "symfony/http-foundation": "^6.4|^7" }, "require-dev": { "mongodb/builder": "^0.2", diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index e85adb7d2..7b34210ad 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -5,6 +5,11 @@ parameters: count: 3 path: src/MongoDBBusServiceProvider.php + - + message: "#^Access to an undefined property Illuminate\\\\Foundation\\\\Application\\:\\:\\$config\\.$#" + count: 4 + path: src/MongoDBServiceProvider.php + - message: "#^Method Illuminate\\\\Database\\\\Eloquent\\\\Model\\:\\:push\\(\\) invoked with 3 parameters, 0 required\\.$#" count: 3 diff --git a/src/MongoDBServiceProvider.php b/src/MongoDBServiceProvider.php index 0932048c9..9db2122dc 100644 --- a/src/MongoDBServiceProvider.php +++ b/src/MongoDBServiceProvider.php @@ -10,6 +10,7 @@ use Illuminate\Filesystem\FilesystemAdapter; use Illuminate\Filesystem\FilesystemManager; use Illuminate\Foundation\Application; +use Illuminate\Session\SessionManager; use Illuminate\Support\ServiceProvider; use InvalidArgumentException; use League\Flysystem\Filesystem; @@ -20,6 +21,7 @@ use MongoDB\Laravel\Eloquent\Model; use MongoDB\Laravel\Queue\MongoConnector; use RuntimeException; +use Symfony\Component\HttpFoundation\Session\Storage\Handler\MongoDbSessionHandler; use function assert; use function class_exists; @@ -53,6 +55,25 @@ public function register() }); }); + // Session handler for MongoDB + $this->app->resolving(SessionManager::class, function (SessionManager $sessionManager) { + $sessionManager->extend('mongodb', function (Application $app) { + $connectionName = $app->config->get('session.connection') ?: 'mongodb'; + $connection = $app->make('db')->connection($connectionName); + + assert($connection instanceof Connection, new InvalidArgumentException(sprintf('The database connection "%s" used for the session does not use the "mongodb" driver.', $connectionName))); + + return new MongoDbSessionHandler( + $connection->getMongoClient(), + $app->config->get('session.options', []) + [ + 'database' => $connection->getDatabaseName(), + 'collection' => $app->config->get('session.table') ?: 'sessions', + 'ttl' => $app->config->get('session.lifetime'), + ], + ); + }); + }); + // Add cache and lock drivers. $this->app->resolving('cache', function (CacheManager $cache) { $cache->extend('mongodb', function (Application $app, array $config): Repository { diff --git a/tests/SessionTest.php b/tests/SessionTest.php index 7ffbb51f0..ee086f5b8 100644 --- a/tests/SessionTest.php +++ b/tests/SessionTest.php @@ -3,7 +3,9 @@ namespace MongoDB\Laravel\Tests; use Illuminate\Session\DatabaseSessionHandler; +use Illuminate\Session\SessionManager; use Illuminate\Support\Facades\DB; +use Symfony\Component\HttpFoundation\Session\Storage\Handler\MongoDbSessionHandler; class SessionTest extends TestCase { @@ -14,7 +16,7 @@ protected function tearDown(): void parent::tearDown(); } - public function testDatabaseSessionHandler() + public function testDatabaseSessionHandlerCompatibility() { $sessionId = '123'; @@ -30,4 +32,43 @@ public function testDatabaseSessionHandler() $handler->write($sessionId, 'bar'); $this->assertEquals('bar', $handler->read($sessionId)); } + + public function testDatabaseSessionHandlerRegistration() + { + $this->app['config']->set('session.driver', 'database'); + $this->app['config']->set('session.connection', 'mongodb'); + + $session = $this->app['session']; + $this->assertInstanceOf(SessionManager::class, $session); + $this->assertInstanceOf(DatabaseSessionHandler::class, $session->getHandler()); + + $this->assertSessionCanStoreInMongoDB($session); + } + + public function testMongoDBSessionHandlerRegistration() + { + $this->app['config']->set('session.driver', 'mongodb'); + $this->app['config']->set('session.connection', 'mongodb'); + + $session = $this->app['session']; + $this->assertInstanceOf(SessionManager::class, $session); + $this->assertInstanceOf(MongoDbSessionHandler::class, $session->getHandler()); + + $this->assertSessionCanStoreInMongoDB($session); + } + + private function assertSessionCanStoreInMongoDB(SessionManager $session): void + { + $session->put('foo', 'bar'); + $session->save(); + + $this->assertNotNull($session->getId()); + + $data = DB::connection('mongodb') + ->getCollection('sessions') + ->findOne(['_id' => $session->getId()]); + + self::assertIsObject($data); + self::assertSame($session->getId(), $data->_id); + } }