[BUGFIX] Multiple fixes for Locking API and TSFE locking
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / Locking / LockFactory.php
1 <?php
2 namespace TYPO3\CMS\Core\Locking;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Core\Locking\Exception\LockCreateException;
18 use TYPO3\CMS\Core\SingletonInterface;
19
20 /**
21 * Factory class to retrieve a locking method
22 *
23 * @author Markus Klein <klein.t3@reelworx.at>
24 */
25 class LockFactory implements SingletonInterface {
26
27 /**
28 * @var bool[]
29 */
30 protected $lockingStrategy = array(
31 SemaphoreLockStrategy::class => TRUE,
32 FileLockStrategy::class => TRUE,
33 SimpleLockStrategy::class => TRUE
34 );
35
36 /**
37 * Add a locking method
38 *
39 * @param string $className
40 * @throws \InvalidArgumentException
41 */
42 public function addLockingStrategy($className) {
43 $interfaces = class_implements($className);
44 if (isset($interfaces[LockingStrategyInterface::class])) {
45 $this->lockingStrategy[$className] = TRUE;
46 } else {
47 throw new \InvalidArgumentException('The given class name ' . $className . ' does not implement the required LockingStrategyInterface interface.', 1425990198);
48 }
49 }
50
51 /**
52 * Remove a locking method
53 *
54 * @param string $className
55 */
56 public function removeLockingStrategy($className) {
57 unset($this->lockingStrategy[$className]);
58 }
59
60 /**
61 * Get best matching locking method
62 *
63 * @param string $id ID to identify this lock in the system
64 * @param int $capabilities LockingStrategyInterface::LOCK_CAPABILITY_* elements combined with bit-wise OR
65 * @return LockingStrategyInterface Class name for a locking method
66 * @throws LockCreateException if no locker could be created with the requested capabilities
67 */
68 public function createLocker($id, $capabilities = LockingStrategyInterface::LOCK_CAPABILITY_EXCLUSIVE) {
69 $queue = new \SplPriorityQueue();
70
71 /** @var LockingStrategyInterface $method */
72 foreach ($this->lockingStrategy as $method => $_) {
73 $supportedCapabilities = $capabilities & $method::getCapabilities();
74 if ($supportedCapabilities === $capabilities) {
75 $queue->insert($method, $method::getPriority());
76 }
77 }
78 if ($queue->count() > 0) {
79 $className = $queue->top();
80 // We use 'new' here on purpose!
81 // Locking might be used very early in the bootstrap process, where makeInstance() does not work
82 return new $className($id);
83 }
84 throw new LockCreateException('Could not find a matching locking method with requested capabilities.', 1425990190);
85 }
86
87 }