ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
class.ilAtomQueryBase.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
27abstract class ilAtomQueryBase
28{
29 protected const ITERATIONS = 10;
33 protected static array $available_isolations_levels = [
38 ];
42 protected static array $possible_anomalies = [
47 ];
51 protected static array $anomalies_map = [
57 ],
61 ],
64 ],
66 ];
71 protected array $tables = [];
75 protected $query;
76
81 public function __construct(protected \ilDBInterface $ilDBInstance, int $isolation_level = ilAtomQuery::ISOLATION_SERIALIZABLE)
82 {
83 static::checkIsolationLevel($isolation_level);
84 $this->isolation_level = $isolation_level;
85 }
86
87 //
88 //
89 //
93 public function getRisks(): array
94 {
95 return static::getPossibleAnomalies($this->getIsolationLevel());
96 }
97
104 public function addTableLock(string $table_name): ilTableLockInterface
105 {
106 $ilTableLock = new ilTableLock($table_name, $this->ilDBInstance);
107 $ilTableLock->setLockLevel($this->getDeterminedLockLevel());
108 $this->tables[] = $ilTableLock;
109
110 return $ilTableLock;
111 }
112
113 protected function getDeterminedLockLevel(): int
114 {
116 }
117
133 public function addQueryCallable(callable $query): void
134 {
135 if ($this->query) {
137 }
138 if (!$this->checkCallable($query)) {
140 }
141 $this->query = $query;
142 }
143
147 public function replaceQueryCallable(callable $query): void
148 {
149 if (!$this->checkCallable($query)) {
151 }
152 $this->query = $query;
153 }
154
159 abstract public function run(): void;
160
161 public function getIsolationLevel(): int
162 {
164 }
165
169 public static function isThereRiskThat(int $isolation_level, int $anomaly): bool
170 {
171 static::checkIsolationLevel($isolation_level);
172 static::checkAnomaly($anomaly);
173
174 return in_array($anomaly, static::getPossibleAnomalies($isolation_level));
175 }
176
180 public static function getPossibleAnomalies(int $isolation_level): array
181 {
182 static::checkIsolationLevel($isolation_level);
183
184 return self::$anomalies_map[$isolation_level];
185 }
186
190 public static function checkIsolationLevel(int $isolation_level): void
191 {
192 // The following Isolations are currently not supported
193 if (in_array($isolation_level, [
197 ])) {
199 }
200 // Check if a available Isolation level is selected
201 if (!in_array($isolation_level, self::$available_isolations_levels)) {
203 }
204 }
205
209 public static function checkAnomaly(int $anomaly): void
210 {
211 if (!in_array($anomaly, self::$possible_anomalies)) {
213 }
214 }
215
219 protected function checkQueries(): void
220 {
221 if (!($this->query instanceof \Traversable) && (is_array($this->query) && [] === $this->query)) {
223 }
224
225 foreach ($this->query as $query) {
226 if (!$this->checkCallable($query)) {
228 }
229 }
230 }
231
232 public function checkCallable(callable $query): bool
233 {
234 if (!is_callable($query)) {
235 return false; // Won't be triggered sidn type-hinting already checks this
236 }
237 if (is_array($query)) {
238 return false;
239 }
240 if (is_string($query)) {
241 return false;
242 }
243
244 $is_a_closure = ($query instanceof Closure);
245 if (!$is_a_closure) {
246 $ref = new ReflectionClass($query);
247 foreach ($ref->getMethods() as $method) {
248 if ($method->getName() === '__invoke') {
249 return true;
250 }
251 }
252
253 return false;
254 }
255 if ($is_a_closure) {
256 $ref = new ReflectionFunction($query);
257 $parameters = $ref->getParameters();
258 if (count($parameters) !== 1) {
259 return false;
260 }
261 $reflectionClass = $parameters[0]->getType();
262 return $reflectionClass && $reflectionClass->getName() === ilDBInterface::class;
263 }
264
265 return true;
266 }
267
268 protected function hasWriteLocks(): bool
269 {
270 $has_write_locks = false;
271 foreach ($this->tables as $table) {
272 if ($table->getLockLevel() === ilAtomQuery::LOCK_WRITE) {
273 $has_write_locks = true;
274 }
275 }
276
277 return $has_write_locks;
278 }
279
283 protected function runQueries(): void
284 {
286 $query($this->ilDBInstance);
287 }
288
292 protected function checkBeforeRun(): void
293 {
294 $this->checkQueries();
295
296 if ($this->hasWriteLocks() && $this->getIsolationLevel() != ilAtomQuery::ISOLATION_SERIALIZABLE) {
298 }
299
300 if ($this->tables === []) {
302 }
303 }
304}
Class ilAtomQuery Use ilAtomQuery to fire Database-Actions which have to be done without beeing influ...
addTableLock(string $table_name)
Add table-names which are influenced by your queries, MyISAm has to lock those tables.
static getPossibleAnomalies(int $isolation_level)
__construct(protected \ilDBInterface $ilDBInstance, int $isolation_level=ilAtomQuery::ISOLATION_SERIALIZABLE)
ilAtomQuery constructor.
static checkAnomaly(int $anomaly)
static array $possible_anomalies
static array $available_isolations_levels
static checkIsolationLevel(int $isolation_level)
static isThereRiskThat(int $isolation_level, int $anomaly)
addQueryCallable(callable $query)
All action on the database during this isolation has to be passed as Callable to ilAtomQuery.
checkCallable(callable $query)
run()
Fire your Queries.
replaceQueryCallable(callable $query)
static array $anomalies_map
Class ilAtomQueryException.
Class ilTableLock.
Interface ilDBInterface.
Class ilTableLockInterface Defines methods, which a Table-Lock used in ilAtomQuery provides.