Skip to content

Commit 82d8e0e

Browse files
committed
[Lock] Split "StoreInterface" into multiple interfaces with less responsability
1 parent 80e28a0 commit 82d8e0e

21 files changed

+650
-69
lines changed

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,9 @@
7070
use Symfony\Component\Lock\Factory;
7171
use Symfony\Component\Lock\Lock;
7272
use Symfony\Component\Lock\LockInterface;
73+
use Symfony\Component\Lock\PersistStoreInterface;
7374
use Symfony\Component\Lock\Store\FlockStore;
75+
use Symfony\Component\Lock\Store\LegacyStore;
7476
use Symfony\Component\Lock\Store\StoreFactory;
7577
use Symfony\Component\Lock\StoreInterface;
7678
use Symfony\Component\Mailer\Mailer;
@@ -1564,18 +1566,23 @@ private function registerLockConfiguration(array $config, ContainerBuilder $cont
15641566
$storeDsn = $container->resolveEnvPlaceholders($storeDsn, null, $usedEnvs);
15651567
switch (true) {
15661568
case 'flock' === $storeDsn:
1567-
$storeDefinition = new Reference('lock.store.flock');
1569+
$storeDefinition = new Definition(LegacyStore::class);
1570+
$storeDefinition->setPublic(false);
1571+
$storeDefinition->setArguments([new Reference('lock.store_persist.flock')]);
15681572
break;
15691573
case 0 === strpos($storeDsn, 'flock://'):
15701574
$flockPath = substr($storeDsn, 8);
15711575

1572-
$storeDefinitionId = '.lock.flock.store.'.$container->hash($storeDsn);
1576+
$storeDefinitionId = '.lock.flock.store_persist.'.$container->hash($storeDsn);
15731577
$container->register($storeDefinitionId, FlockStore::class)->addArgument($flockPath);
1574-
1575-
$storeDefinition = new Reference($storeDefinitionId);
1578+
$storeDefinition = new Definition(LegacyStore::class);
1579+
$storeDefinition->setPublic(false);
1580+
$storeDefinition->setArguments([new Reference($storeDefinitionId)]);
15761581
break;
15771582
case 'semaphore' === $storeDsn:
1578-
$storeDefinition = new Reference('lock.store.semaphore');
1583+
$storeDefinition = new Definition(LegacyStore::class);
1584+
$storeDefinition->setPublic(false);
1585+
$storeDefinition->setArguments([new Reference('lock.store_persist.semaphore')]);
15791586
break;
15801587
case $usedEnvs || preg_match('#^[a-z]++://#', $storeDsn):
15811588
if (!$container->hasDefinition($connectionDefinitionId = '.lock_connection.'.$container->hash($storeDsn))) {
@@ -1586,14 +1593,19 @@ private function registerLockConfiguration(array $config, ContainerBuilder $cont
15861593
$container->setDefinition($connectionDefinitionId, $connectionDefinition);
15871594
}
15881595

1589-
$storeDefinition = new Definition(StoreInterface::class);
1596+
$storeDefinition = new Definition(PersistStoreInterface::class);
15901597
$storeDefinition->setPublic(false);
15911598
$storeDefinition->setFactory([StoreFactory::class, 'createStore']);
15921599
$storeDefinition->setArguments([new Reference($connectionDefinitionId)]);
15931600

1594-
$container->setDefinition($storeDefinitionId = '.lock.'.$resourceName.'.store.'.$container->hash($storeDsn), $storeDefinition);
1601+
$legacyStoreDefinition = new Definition(LegacyStore::class);
1602+
$legacyStoreDefinition->setPublic(false);
1603+
$legacyStoreDefinition->setArguments([new Reference($storeDefinition)]);
1604+
1605+
$container->setDefinition($legacyStoreDefinitionId = 'lock.'.$resourceName.'.store.'.$container->hash($storeDsn), $legacyStoreDefinition)->setDeprecated(true, 'The "%service_id%" service is deprecated.');
1606+
$container->setDefinition($storeDefinitionId = 'lock.'.$resourceName.'.persist_store.'.$container->hash($storeDsn), $storeDefinition);
15951607

1596-
$storeDefinition = new Reference($storeDefinitionId);
1608+
$storeDefinition = new Reference($legacyStoreDefinitionId);
15971609
break;
15981610
default:
15991611
throw new InvalidArgumentException(sprintf('Lock store DSN "%s" is not valid in resource "%s"', $storeDsn, $resourceName));
@@ -1604,9 +1616,16 @@ private function registerLockConfiguration(array $config, ContainerBuilder $cont
16041616

16051617
// Wrap array of stores with CombinedStore
16061618
if (\count($storeDefinitions) > 1) {
1619+
16071620
$combinedDefinition = new ChildDefinition('lock.store.combined.abstract');
16081621
$combinedDefinition->replaceArgument(0, $storeDefinitions);
1609-
$container->setDefinition('lock.'.$resourceName.'.store', $combinedDefinition);
1622+
1623+
$legacyDefinition = new ChildDefinition('lock.store.legacy.abstract');
1624+
$legacyDefinition->replaceArgument(0, $combinedDefinition);
1625+
1626+
$container->setDefinition('lock.'.$resourceName.'.persist_store', $combinedDefinition);
1627+
$container->setDefinition('lock.'.$resourceName.'.store', $legacyDefinition);
1628+
16101629
} else {
16111630
$container->setAlias('lock.'.$resourceName.'.store', new Alias((string) $storeDefinitions[0], false));
16121631
}
@@ -1628,11 +1647,14 @@ private function registerLockConfiguration(array $config, ContainerBuilder $cont
16281647
$container->setAlias('lock.store', new Alias('lock.'.$resourceName.'.store', false));
16291648
$container->setAlias('lock.factory', new Alias('lock.'.$resourceName.'.factory', false));
16301649
$container->setAlias('lock', new Alias('lock.'.$resourceName, false));
1631-
$container->setAlias(StoreInterface::class, new Alias('lock.store', false));
1650+
$container->setAlias(StoreInterface::class, new Alias('lock.store', false))->setDeprecated(true, 'The "%alias_id%" service is deprecated.');
1651+
$container->setAlias(PersistStoreInterface::class, new Alias('lock.persist_store', false));
1652+
16321653
$container->setAlias(Factory::class, new Alias('lock.factory', false));
16331654
$container->setAlias(LockInterface::class, new Alias('lock', false));
16341655
} else {
1635-
$container->registerAliasForArgument('lock.'.$resourceName.'.store', StoreInterface::class, $resourceName.'.lock.store');
1656+
$container->setAlias(PersistStoreInterface::class, new Alias('lock.persist_store', false));
1657+
$container->registerAliasForArgument('lock.'.$resourceName.'.store', StoreInterface::class, $resourceName.'.lock.store')->setDeprecated(true, 'The "%alias_id%" service is deprecated.');
16361658
$container->registerAliasForArgument('lock.'.$resourceName.'.factory', Factory::class, $resourceName.'.lock.factory');
16371659
$container->registerAliasForArgument('lock.'.$resourceName, LockInterface::class, $resourceName.'.lock');
16381660
}

src/Symfony/Bundle/FrameworkBundle/Resources/config/lock.xml

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,49 @@
77
<services>
88
<defaults public="false" />
99

10-
<service id="lock.store.flock" class="Symfony\Component\Lock\Store\FlockStore" />
10+
<service id="lock.store.flock" class="Symfony\Component\Lock\Store\FlockStore" >
11+
<deprecated>The "%service_id%" service is deprecated since Symfony 4.4 use "lock.store_persist.flock" instead.</deprecated>
12+
</service>
13+
<service id="lock.store_persist.flock" class="Symfony\Component\Lock\Store\FlockStore" />
1114

12-
<service id="lock.store.semaphore" class="Symfony\Component\Lock\Store\SemaphoreStore" />
15+
<service id="lock.store.semaphore" class="Symfony\Component\Lock\Store\SemaphoreStore" >
16+
<deprecated>The "%service_id%" service is deprecated since Symfony 4.4 use "lock.store_persist.semaphore" instead.</deprecated>
17+
</service>
18+
<service id="lock.store_persist.semaphore" class="Symfony\Component\Lock\Store\SemaphoreStore" />
19+
<service id="lock.store_persist.memcached.abstract" class="Symfony\Component\Lock\Store\MemcachedStore" abstract="true">
20+
<argument /> <!-- Memcached connection service -->
21+
</service>
22+
23+
<service id="lock.store_persist.redis.abstract" class="Symfony\Component\Lock\Store\RedisStore" abstract="true">
24+
<argument /> <!-- Redis connection service -->
25+
</service>
26+
<service id="lock.store_persist.combined.abstract" class="Symfony\Component\Lock\Store\CombinedStore" abstract="true">
27+
<argument /> <!-- List of stores -->
28+
<argument type="service" id="lock.strategy.majority" /> <!-- Strategy -->
29+
</service>
1330

1431
<service id="lock.store.memcached.abstract" class="Symfony\Component\Lock\Store\MemcachedStore" abstract="true">
32+
<deprecated>The "%service_id%" service is deprecated since Symfony 4.4 use "lock.store_persist.memcached.abstract" instead.</deprecated>
1533
<argument /> <!-- Memcached connection service -->
1634
</service>
1735

1836
<service id="lock.store.redis.abstract" class="Symfony\Component\Lock\Store\RedisStore" abstract="true">
37+
<deprecated>The "%service_id%" service is deprecated since Symfony 4.4 use "lock.store_persist.redis.abstract" instead.</deprecated>
1938
<argument /> <!-- Redis connection service -->
2039
</service>
2140

2241
<service id="lock.store.combined.abstract" class="Symfony\Component\Lock\Store\CombinedStore" abstract="true">
42+
<deprecated>The "%service_id%" service is deprecated since Symfony 4.4 use "lock.store_persist.combined.abstract" instead.</deprecated>
2343
<argument /> <!-- List of stores -->
2444
<argument type="service" id="lock.strategy.majority" /> <!-- Strategy -->
2545
</service>
2646

47+
<service id="lock.store.legacy.abstract" class="Symfony\Component\Lock\Store\LegacyStore" abstract="true">
48+
<argument /> <!-- List of stores -->
49+
<argument type="service" id="lock.strategy.majority" /> <!-- Strategy -->
50+
</service>
51+
52+
2753
<service id="lock.strategy.majority" class="Symfony\Component\Lock\Strategy\ConsensusStrategy" />
2854

2955
<service id="lock.factory.abstract" class="Symfony\Component\Lock\Factory" abstract="true">
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Lock;
13+
14+
use Symfony\Component\Lock\Exception\LockConflictedException;
15+
use Symfony\Component\Lock\Exception\NotSupportedException;
16+
17+
/**
18+
* BlockingStoreInterface defines an interface to manipulate a lock store.
19+
*
20+
* @author Hamza Amrouche <hamza.simperfit@gmail.com>
21+
*/
22+
interface BlockingStoreInterface
23+
{
24+
/**
25+
* Waits until a key becomes free, then stores the resource.
26+
*
27+
* If the store does not support this feature it should throw a NotSupportedException.
28+
*
29+
* @throws LockConflictedException
30+
* @throws NotSupportedException
31+
*/
32+
public function waitAndSave(Key $key);
33+
34+
/**
35+
* Check if the store can wait until a key becomes free before storing the resource.
36+
*/
37+
public function supportsWaitAndSave(): bool;
38+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Lock;
13+
14+
use Symfony\Component\Lock\Exception\LockConflictedException;
15+
use Symfony\Component\Lock\Exception\NotSupportedException;
16+
17+
/**
18+
* ExpiringStoreInterface defines an interface to manipulate a lock store.
19+
*
20+
* @author Hamza Amrouche <hamza.simperfit@gmail.com>
21+
*/
22+
interface ExpiringStoreInterface
23+
{
24+
/**
25+
* Extends the ttl of a resource.
26+
*
27+
* If the store does not support this feature it should throw a NotSupportedException.
28+
*
29+
* @param float $ttl amount of seconds to keep the lock in the store
30+
*
31+
* @throws LockConflictedException
32+
* @throws NotSupportedException
33+
*/
34+
public function putOffExpiration(Key $key, $ttl);
35+
36+
/**
37+
* Check if the store supports extending the ttl of a resource.
38+
*
39+
* @throws LockConflictedException
40+
* @throws NotSupportedException
41+
*/
42+
public function supportsPutOffExpiration(): bool;
43+
}

src/Symfony/Component/Lock/Factory.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ class Factory implements LoggerAwareInterface
2626

2727
private $store;
2828

29-
public function __construct(StoreInterface $store)
29+
public function __construct($store)
3030
{
3131
$this->store = $store;
3232

src/Symfony/Component/Lock/Lock.php

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,21 @@ final class Lock implements LockInterface, LoggerAwareInterface
3636
private $dirty = false;
3737

3838
/**
39-
* @param Key $key Resource to lock
40-
* @param StoreInterface $store Store used to handle lock persistence
41-
* @param float|null $ttl Maximum expected lock duration in seconds
42-
* @param bool $autoRelease Whether to automatically release the lock or not when the lock instance is destroyed
39+
* @param Key $key Resource to lock
40+
* @param PersistStoreInterface $store Store used to handle lock persistence
41+
* @param float|null $ttl Maximum expected lock duration in seconds
42+
* @param bool $autoRelease Whether to automatically release the lock or not when the lock instance is destroyed
4343
*/
44-
public function __construct(Key $key, StoreInterface $store, float $ttl = null, bool $autoRelease = true)
44+
public function __construct(Key $key, $store, float $ttl = null, bool $autoRelease = true)
4545
{
46+
if ($store instanceof StoreInterface) {
47+
@trigger_error(sprintf('"%s" is deprecated since Symfony 4.4 and has been splitted into "%s", "%s", "%s".', StoreInterface::class, PersistStoreInterface::class, ExpiringStoreInterface::class, BlockingStoreInterface::class), E_USER_DEPRECATED);
48+
}
49+
50+
if (!($store instanceof PersistStoreInterface || $store instanceof StoreInterface)) {
51+
throw new InvalidArgumentException(sprintf('$store should implement %s.', PersistStoreInterface::class));
52+
}
53+
4654
$this->store = $store;
4755
$this->key = $key;
4856
$this->ttl = $ttl;
@@ -69,7 +77,7 @@ public function __destruct()
6977
public function acquire($blocking = false)
7078
{
7179
try {
72-
if ($blocking) {
80+
if ($blocking && $this->store instanceof BlockingStoreInterface && $this->store->supportsWaitAndSave()) {
7381
$this->store->waitAndSave($this->key);
7482
} else {
7583
$this->store->save($this->key);
@@ -121,7 +129,9 @@ public function refresh($ttl = null)
121129

122130
try {
123131
$this->key->resetLifetime();
124-
$this->store->putOffExpiration($this->key, $ttl);
132+
if ($this->store instanceof ExpiringStoreInterface && $this->store->supportsPutOffExpiration()) {
133+
$this->store->putOffExpiration($this->key, $ttl);
134+
}
125135
$this->dirty = true;
126136

127137
if ($this->key->isExpired()) {
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Lock;
13+
14+
use Symfony\Component\Lock\Exception\LockAcquiringException;
15+
use Symfony\Component\Lock\Exception\LockConflictedException;
16+
use Symfony\Component\Lock\Exception\LockReleasingException;
17+
18+
/**
19+
* StoreInterface defines an interface to manipulate a lock store.
20+
*
21+
* @author Jérémy Derussé <jeremy@derusse.com>
22+
*/
23+
interface PersistStoreInterface
24+
{
25+
/**
26+
* Stores the resource if it's not locked by someone else.
27+
*
28+
* @throws LockAcquiringException
29+
* @throws LockConflictedException
30+
*/
31+
public function save(Key $key);
32+
33+
/**
34+
* Removes a resource from the storage.
35+
*
36+
* @throws LockReleasingException
37+
*/
38+
public function delete(Key $key);
39+
40+
/**
41+
* Returns whether or not the resource exists in the storage.
42+
*
43+
* @return bool
44+
*/
45+
public function exists(Key $key);
46+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy