feature #34057 [Lock][Cache] Allows URL DSN in PDO adapters (jderusse)

This PR was merged into the 4.4 branch.

Discussion
----------

[Lock][Cache] Allows URL DSN in PDO adapters

| Q             | A
| ------------- | ---
| Branch?       | 4.4
| Bug fix?      | no
| New feature?  | yes
| Deprecations? | no
| Tickets       | -
| License       | MIT
| Doc PR        | TODO

This PR duplicate a feature from PdoSessionHandler that convert URL DSN ( ie. mysql://localhost/test) into PDO DSN (ie. mysql:host=localhost;dbname=test)

that would ease configuration by using the same well-known variable
```
framework:
  lock: '%env(DATABASE_URL)%'
```

note: I applied the same change on Cache component for consistency.

Commits
-------

474daf976e Allows URL DSN in Lock and Cache
This commit is contained in:
Nicolas Grekas 2019-10-29 14:07:00 +01:00
commit e2c625e78b
5 changed files with 83 additions and 5 deletions

View File

@ -71,4 +71,33 @@ class PdoAdapterTest extends AdapterTestCase
$this->assertFalse($newItem->isHit());
$this->assertSame(0, $getCacheItemCount(), 'PDOAdapter must clean up expired items');
}
/**
* @dataProvider provideDsn
*/
public function testDsn(string $dsn, string $file = null)
{
try {
$pool = new PdoAdapter($dsn);
$pool->createTable();
$item = $pool->getItem('key');
$item->set('value');
$this->assertTrue($pool->save($item));
} finally {
if (null !== $file) {
@unlink($file);
}
}
}
public function provideDsn()
{
$dbFile = tempnam(sys_get_temp_dir(), 'sf_sqlite_cache');
yield ['sqlite://localhost/'.$dbFile, ''.$dbFile];
yield ['sqlite:'.$dbFile, ''.$dbFile];
yield ['sqlite3:///'.$dbFile, ''.$dbFile];
yield ['sqlite://localhost/:memory:'];
yield ['sqlite::memory:'];
}
}

View File

@ -14,6 +14,7 @@ namespace Symfony\Component\Cache\Traits;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\DBALException;
use Doctrine\DBAL\Driver\ServerInfoAwareConnection;
use Doctrine\DBAL\DriverManager;
use Doctrine\DBAL\Exception\TableNotFoundException;
use Doctrine\DBAL\Schema\Schema;
use Symfony\Component\Cache\Exception\InvalidArgumentException;
@ -370,8 +371,15 @@ trait PdoTrait
private function getConnection()
{
if (null === $this->conn) {
$this->conn = new \PDO($this->dsn, $this->username, $this->password, $this->connectionOptions);
$this->conn->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
if (strpos($this->dsn, '://')) {
if (!class_exists(DriverManager::class)) {
throw new InvalidArgumentException(sprintf('Failed to parse the DSN "%s". Try running "composer require doctrine/dbal".', $this->dsn));
}
$this->conn = DriverManager::getConnection(['url' => $this->dsn]);
} else {
$this->conn = new \PDO($this->dsn, $this->username, $this->password, $this->connectionOptions);
$this->conn->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
}
}
if (null === $this->driver) {
if ($this->conn instanceof \PDO) {

View File

@ -13,6 +13,7 @@ namespace Symfony\Component\Lock\Store;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\DBALException;
use Doctrine\DBAL\DriverManager;
use Doctrine\DBAL\Schema\Schema;
use Symfony\Component\Lock\Exception\InvalidArgumentException;
use Symfony\Component\Lock\Exception\InvalidTtlException;
@ -229,8 +230,15 @@ class PdoStore implements StoreInterface
private function getConnection()
{
if (null === $this->conn) {
$this->conn = new \PDO($this->dsn, $this->username, $this->password, $this->connectionOptions);
$this->conn->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
if (strpos($this->dsn, '://')) {
if (!class_exists(DriverManager::class)) {
throw new InvalidArgumentException(sprintf('Failed to parse the DSN "%s". Try running "composer require doctrine/dbal".', $this->dsn));
}
$this->conn = DriverManager::getConnection(['url' => $this->dsn]);
} else {
$this->conn = new \PDO($this->dsn, $this->username, $this->password, $this->connectionOptions);
$this->conn->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
}
}
return $this->conn;

View File

@ -73,4 +73,34 @@ class PdoStoreTest extends AbstractStoreTest
return new PdoStore('sqlite:'.self::$dbFile, [], 0.1, 0.1);
}
/**
* @dataProvider provideDsn
*/
public function testDsn(string $dsn, string $file = null)
{
$key = new Key(uniqid(__METHOD__, true));
try {
$store = new PdoStore($dsn);
$store->createTable();
$store->save($key);
$this->assertTrue($store->exists($key));
} finally {
if (null !== $file) {
@unlink($file);
}
}
}
public function provideDsn()
{
$dbFile = tempnam(sys_get_temp_dir(), 'sf_sqlite_cache');
yield ['sqlite://localhost/'.$dbFile, ''.$dbFile];
yield ['sqlite:'.$dbFile, ''.$dbFile];
yield ['sqlite3:///'.$dbFile, ''.$dbFile];
yield ['sqlite://localhost/:memory:'];
yield ['sqlite::memory:'];
}
}

View File

@ -20,10 +20,13 @@
"psr/log": "~1.0"
},
"require-dev": {
"doctrine/dbal": "~2.4",
"doctrine/dbal": "~2.5",
"mongodb/mongodb": "~1.1",
"predis/predis": "~1.0"
},
"conflict": {
"doctrine/dbal": "<2.5"
},
"autoload": {
"psr-4": { "Symfony\\Component\\Lock\\": "" },
"exclude-from-classmap": [