Add missing lock connection string in FrameworkExtension

This commit is contained in:
Jérémy Derussé 2019-10-21 08:58:12 +02:00
parent e2c625e78b
commit 2db24cf582
No known key found for this signature in database
GPG Key ID: 2083FA5758C473D2
8 changed files with 94 additions and 42 deletions

View File

@ -162,6 +162,8 @@ Lock
* Deprecated `Symfony\Component\Lock\StoreInterface` in favor of `Symfony\Component\Lock\BlockingStoreInterface` and
`Symfony\Component\Lock\PersistingStoreInterface`.
* `Factory` is deprecated, use `LockFactory` instead
* Deprecated services `lock.store.flock`, `lock.store.semaphore`, `lock.store.memcached.abstract` and `lock.store.redis.abstract`,
use `StoreFactory::createStore` instead.
Messenger
---------

View File

@ -28,7 +28,6 @@ use Symfony\Bundle\FrameworkBundle\Routing\RouteLoaderInterface;
use Symfony\Bundle\FullStack;
use Symfony\Component\Asset\PackageInterface;
use Symfony\Component\BrowserKit\AbstractBrowser;
use Symfony\Component\Cache\Adapter\AbstractAdapter;
use Symfony\Component\Cache\Adapter\AdapterInterface;
use Symfony\Component\Cache\Adapter\ArrayAdapter;
use Symfony\Component\Cache\Adapter\ChainAdapter;
@ -75,7 +74,6 @@ use Symfony\Component\Lock\Lock;
use Symfony\Component\Lock\LockFactory;
use Symfony\Component\Lock\LockInterface;
use Symfony\Component\Lock\PersistingStoreInterface;
use Symfony\Component\Lock\Store\FlockStore;
use Symfony\Component\Lock\Store\StoreFactory;
use Symfony\Component\Lock\StoreInterface;
use Symfony\Component\Mailer\Bridge\Amazon\Transport\SesTransportFactory;
@ -1621,42 +1619,13 @@ class FrameworkExtension extends Extension
$storeDefinitions = [];
foreach ($resourceStores as $storeDsn) {
$storeDsn = $container->resolveEnvPlaceholders($storeDsn, null, $usedEnvs);
switch (true) {
case 'flock' === $storeDsn:
$storeDefinition = new Reference('lock.store.flock');
break;
case 0 === strpos($storeDsn, 'flock://'):
$flockPath = substr($storeDsn, 8);
$storeDefinition = new Definition(PersistingStoreInterface::class);
$storeDefinition->setFactory([StoreFactory::class, 'createStore']);
$storeDefinition->setArguments([$storeDsn]);
$storeDefinitionId = '.lock.flock.store.'.$container->hash($storeDsn);
$container->register($storeDefinitionId, FlockStore::class)->addArgument($flockPath);
$container->setDefinition($storeDefinitionId = '.lock.'.$resourceName.'.store.'.$container->hash($storeDsn), $storeDefinition);
$storeDefinition = new Reference($storeDefinitionId);
break;
case 'semaphore' === $storeDsn:
$storeDefinition = new Reference('lock.store.semaphore');
break;
case $usedEnvs || preg_match('#^[a-z]++://#', $storeDsn):
if (!$container->hasDefinition($connectionDefinitionId = '.lock_connection.'.$container->hash($storeDsn))) {
$connectionDefinition = new Definition(\stdClass::class);
$connectionDefinition->setPublic(false);
$connectionDefinition->setFactory([AbstractAdapter::class, 'createConnection']);
$connectionDefinition->setArguments([$storeDsn, ['lazy' => true]]);
$container->setDefinition($connectionDefinitionId, $connectionDefinition);
}
$storeDefinition = new Definition(PersistingStoreInterface::class);
$storeDefinition->setPublic(false);
$storeDefinition->setFactory([StoreFactory::class, 'createStore']);
$storeDefinition->setArguments([new Reference($connectionDefinitionId)]);
$container->setDefinition($storeDefinitionId = '.lock.'.$resourceName.'.store.'.$container->hash($storeDsn), $storeDefinition);
$storeDefinition = new Reference($storeDefinitionId);
break;
default:
throw new InvalidArgumentException(sprintf('Lock store DSN "%s" is not valid in resource "%s"', $storeDsn, $resourceName));
}
$storeDefinition = new Reference($storeDefinitionId);
$storeDefinitions[] = $storeDefinition;
}

View File

@ -7,16 +7,22 @@
<services>
<defaults public="false" />
<service id="lock.store.flock" class="Symfony\Component\Lock\Store\FlockStore" />
<service id="lock.store.flock" class="Symfony\Component\Lock\Store\FlockStore">
<deprecated>The "%service_id%" service is deprecated since Symfony 4.4 and will be removed in 5.0.</deprecated>
</service>
<service id="lock.store.semaphore" class="Symfony\Component\Lock\Store\SemaphoreStore" />
<service id="lock.store.semaphore" class="Symfony\Component\Lock\Store\SemaphoreStore">
<deprecated>The "%service_id%" service is deprecated since Symfony 4.4 and will be removed in 5.0.</deprecated>
</service>
<service id="lock.store.memcached.abstract" class="Symfony\Component\Lock\Store\MemcachedStore" abstract="true">
<argument /> <!-- Memcached connection service -->
<deprecated>The "%service_id%" service is deprecated since Symfony 4.4 and will be removed in 5.0.</deprecated>
</service>
<service id="lock.store.redis.abstract" class="Symfony\Component\Lock\Store\RedisStore" abstract="true">
<argument /> <!-- Redis connection service -->
<deprecated>The "%service_id%" service is deprecated since Symfony 4.4 and will be removed in 5.0.</deprecated>
</service>
<service id="lock.store.combined.abstract" class="Symfony\Component\Lock\Store\CombinedStore" abstract="true">

View File

@ -7,7 +7,10 @@ CHANGELOG
* added InvalidTtlException
* deprecated `StoreInterface` in favor of `BlockingStoreInterface` and `PersistingStoreInterface`
* `Factory` is deprecated, use `LockFactory` instead
* `StoreFactory::createStore` allows PDO and Zookeeper DSN.
* deprecated services `lock.store.flock`, `lock.store.semaphore`, `lock.store.memcached.abstract` and `lock.store.redis.abstract`,
use `StoreFactory::createStore` instead.
4.2.0
-----

View File

@ -58,8 +58,24 @@ class StoreFactory
return new FlockStore(substr($connection, 8));
case 'semaphore' === $connection:
return new SemaphoreStore();
case class_exists(AbstractAdapter::class) && preg_match('#^[a-z]++://#', $connection):
return static::createStore(AbstractAdapter::createConnection($connection));
case 0 === strpos($connection, 'redis://') && class_exists(AbstractAdapter::class):
case 0 === strpos($connection, 'rediss://') && class_exists(AbstractAdapter::class):
return new RedisStore(AbstractAdapter::createConnection($connection, ['lazy' => true]));
case 0 === strpos($connection, 'memcached://') && class_exists(AbstractAdapter::class):
return new MemcachedStore(AbstractAdapter::createConnection($connection, ['lazy' => true]));
case 0 === strpos($connection, 'sqlite:'):
case 0 === strpos($connection, 'mysql:'):
case 0 === strpos($connection, 'pgsql:'):
case 0 === strpos($connection, 'oci:'):
case 0 === strpos($connection, 'sqlsrv:'):
case 0 === strpos($connection, 'sqlite3://'):
case 0 === strpos($connection, 'mysql2://'):
case 0 === strpos($connection, 'postgres://'):
case 0 === strpos($connection, 'postgresql://'):
case 0 === strpos($connection, 'mssql://'):
return new PdoStore($connection);
case 0 === strpos($connection, 'zookeeper://'):
return new ZookeeperStore(ZookeeperStore::createConnection($connection));
default:
throw new InvalidArgumentException(sprintf('Unsupported Connection: %s.', $connection));
}

View File

@ -11,6 +11,7 @@
namespace Symfony\Component\Lock\Store;
use Symfony\Component\Lock\Exception\InvalidArgumentException;
use Symfony\Component\Lock\Exception\LockAcquiringException;
use Symfony\Component\Lock\Exception\LockConflictedException;
use Symfony\Component\Lock\Exception\LockReleasingException;
@ -34,6 +35,24 @@ class ZookeeperStore implements StoreInterface
$this->zookeeper = $zookeeper;
}
public static function createConnection(string $dsn): \Zookeeper
{
if (0 !== strpos($dsn, 'zookeeper:')) {
throw new InvalidArgumentException(sprintf('Unsupported DSN: %s.', $dsn));
}
if (false === $params = parse_url($dsn)) {
throw new InvalidArgumentException(sprintf('Invalid Zookeeper DSN: %s.', $dsn));
}
$host = $params['host'] ?? '';
if (isset($params['port'])) {
$host .= ':'.$params['port'];
}
return new \Zookeeper($host);
}
/**
* {@inheritdoc}
*/

View File

@ -16,6 +16,7 @@ use Symfony\Component\Cache\Adapter\AbstractAdapter;
use Symfony\Component\Cache\Traits\RedisProxy;
use Symfony\Component\Lock\Store\FlockStore;
use Symfony\Component\Lock\Store\MemcachedStore;
use Symfony\Component\Lock\Store\PdoStore;
use Symfony\Component\Lock\Store\RedisStore;
use Symfony\Component\Lock\Store\SemaphoreStore;
use Symfony\Component\Lock\Store\StoreFactory;
@ -50,6 +51,7 @@ class StoreFactoryTest extends TestCase
}
if (class_exists(\Zookeeper::class)) {
yield [$this->createMock(\Zookeeper::class), ZookeeperStore::class];
yield ['zookeeper://localhost:2181', ZookeeperStore::class];
}
if (\extension_loaded('sysvsem')) {
yield ['semaphore', SemaphoreStore::class];
@ -57,6 +59,26 @@ class StoreFactoryTest extends TestCase
if (class_exists(\Memcached::class) && class_exists(AbstractAdapter::class)) {
yield ['memcached://server.com', MemcachedStore::class];
}
if (class_exists(\Redis::class) && class_exists(AbstractAdapter::class)) {
yield ['redis://localhost', RedisStore::class];
}
if (class_exists(\PDO::class)) {
yield ['sqlite:/tmp/sqlite.db', PdoStore::class];
yield ['sqlite::memory:', PdoStore::class];
yield ['mysql:host=localhost;dbname=test;', PdoStore::class];
yield ['pgsql:host=localhost;dbname=test;', PdoStore::class];
yield ['oci:host=localhost;dbname=test;', PdoStore::class];
yield ['sqlsrv:server=localhost;Database=test', PdoStore::class];
yield ['mysql://server.com/test', PdoStore::class];
yield ['mysql2://server.com/test', PdoStore::class];
yield ['pgsql://server.com/test', PdoStore::class];
yield ['postgres://server.com/test', PdoStore::class];
yield ['postgresql://server.com/test', PdoStore::class];
yield ['sqlite:///tmp/test', PdoStore::class];
yield ['sqlite3:///tmp/test', PdoStore::class];
yield ['oci:///server.com/test', PdoStore::class];
yield ['mssql:///server.com/test', PdoStore::class];
}
yield ['flock', FlockStore::class];
yield ['flock://'.sys_get_temp_dir(), FlockStore::class];

View File

@ -30,11 +30,26 @@ class ZookeeperStoreTest extends AbstractStoreTest
{
$zookeeper_server = getenv('ZOOKEEPER_HOST').':2181';
$zookeeper = new \Zookeeper(implode(',', [$zookeeper_server]));
$zookeeper = new \Zookeeper($zookeeper_server);
return StoreFactory::createStore($zookeeper);
}
/**
* @dataProvider provideValidConnectionString
*/
public function testCreateConnection(string $connectionString)
{
$this->assertInstanceOf(\Zookeeper::class, ZookeeperStore::createConnection($connectionString));
}
public function provideValidConnectionString(): iterable
{
yield 'single host' => ['zookeeper://localhost:2181'];
yield 'single multiple host' => ['zookeeper://localhost:2181,localhost:2181'];
yield 'with extra attributes' => ['zookeeper://localhost:2181/path?option=value'];
}
public function testSaveSucceedsWhenPathContainsMoreThanOneNode()
{
$store = $this->getStore();