Passed
Push — master ( 1b8f81...55fd15 )
by Blizzz
14:05 queued 11s
created
lib/public/WorkflowEngine/IManager.php 1 patch
Indentation   +33 added lines, -33 removed lines patch added patch discarded remove patch
@@ -32,42 +32,42 @@
 block discarded – undo
32 32
  */
33 33
 interface IManager {
34 34
 
35
-	const SCOPE_ADMIN = 0;
36
-	const SCOPE_USER = 1;
35
+    const SCOPE_ADMIN = 0;
36
+    const SCOPE_USER = 1;
37 37
 
38
-	/**
39
-	 * @depreacted Will be removed in NC19. Use the dedicated events in OCP\WorkflowEngine\Events
40
-	 */
41
-	const EVENT_NAME_REG_OPERATION = 'OCP\WorkflowEngine::registerOperations';
42
-	const EVENT_NAME_REG_ENTITY = 'OCP\WorkflowEngine::registerEntities';
43
-	const EVENT_NAME_REG_CHECK = 'OCP\WorkflowEngine::registerChecks';
38
+    /**
39
+     * @depreacted Will be removed in NC19. Use the dedicated events in OCP\WorkflowEngine\Events
40
+     */
41
+    const EVENT_NAME_REG_OPERATION = 'OCP\WorkflowEngine::registerOperations';
42
+    const EVENT_NAME_REG_ENTITY = 'OCP\WorkflowEngine::registerEntities';
43
+    const EVENT_NAME_REG_CHECK = 'OCP\WorkflowEngine::registerChecks';
44 44
 
45
-	/**
46
-	 * Listen to `OCP\WorkflowEngine\Events\RegisterEntitiesEvent` at the
47
-	 * IEventDispatcher for registering your entities.
48
-	 *
49
-	 * @since 18.0.0
50
-	 */
51
-	public function registerEntity(IEntity $entity): void;
45
+    /**
46
+     * Listen to `OCP\WorkflowEngine\Events\RegisterEntitiesEvent` at the
47
+     * IEventDispatcher for registering your entities.
48
+     *
49
+     * @since 18.0.0
50
+     */
51
+    public function registerEntity(IEntity $entity): void;
52 52
 
53
-	/**
54
-	 * Listen to `OCP\WorkflowEngine\Events\RegisterOperationsEvent` at the
55
-	 * IEventDispatcher for registering your operators.
56
-	 *
57
-	 * @since 18.0.0
58
-	 */
59
-	public function registerOperation(IOperation $operator): void;
53
+    /**
54
+     * Listen to `OCP\WorkflowEngine\Events\RegisterOperationsEvent` at the
55
+     * IEventDispatcher for registering your operators.
56
+     *
57
+     * @since 18.0.0
58
+     */
59
+    public function registerOperation(IOperation $operator): void;
60 60
 
61
-	/**
62
-	 * Listen to `OCP\WorkflowEngine\Events\RegisterChecksEvent` at the
63
-	 * IEventDispatcher for registering your operators.
64
-	 *
65
-	 * @since 18.0.0
66
-	 */
67
-	public function registerCheck(ICheck $check): void;
61
+    /**
62
+     * Listen to `OCP\WorkflowEngine\Events\RegisterChecksEvent` at the
63
+     * IEventDispatcher for registering your operators.
64
+     *
65
+     * @since 18.0.0
66
+     */
67
+    public function registerCheck(ICheck $check): void;
68 68
 
69
-	/**
70
-	 * @since 18.0.0
71
-	 */
72
-	public function getRuleMatcher(): IRuleMatcher;
69
+    /**
70
+     * @since 18.0.0
71
+     */
72
+    public function getRuleMatcher(): IRuleMatcher;
73 73
 }
Please login to merge, or discard this patch.
lib/public/WorkflowEngine/Events/RegisterOperationsEvent.php 1 patch
Indentation   +15 added lines, -15 removed lines patch added patch discarded remove patch
@@ -33,22 +33,22 @@
 block discarded – undo
33 33
  */
34 34
 class RegisterOperationsEvent extends Event {
35 35
 
36
-	/** @var IManager */
37
-	private $manager;
36
+    /** @var IManager */
37
+    private $manager;
38 38
 
39
-	/**
40
-	 * @since 18.0.0
41
-	 */
42
-	public function __construct(IManager $manager) {
43
-		parent::__construct();
39
+    /**
40
+     * @since 18.0.0
41
+     */
42
+    public function __construct(IManager $manager) {
43
+        parent::__construct();
44 44
 
45
-		$this->manager = $manager;
46
-	}
45
+        $this->manager = $manager;
46
+    }
47 47
 
48
-	/**
49
-	 * @since 18.0.0
50
-	 */
51
-	public function registerOperation(IOperation $operation): void {
52
-		$this->manager->registerOperation($operation);
53
-	}
48
+    /**
49
+     * @since 18.0.0
50
+     */
51
+    public function registerOperation(IOperation $operation): void {
52
+        $this->manager->registerOperation($operation);
53
+    }
54 54
 }
Please login to merge, or discard this patch.
lib/public/WorkflowEngine/Events/RegisterChecksEvent.php 1 patch
Indentation   +15 added lines, -15 removed lines patch added patch discarded remove patch
@@ -33,22 +33,22 @@
 block discarded – undo
33 33
  */
34 34
 class RegisterChecksEvent extends Event {
35 35
 
36
-	/** @var IManager */
37
-	private $manager;
36
+    /** @var IManager */
37
+    private $manager;
38 38
 
39
-	/**
40
-	 * @since 18.0.0
41
-	 */
42
-	public function __construct(IManager $manager) {
43
-		parent::__construct();
39
+    /**
40
+     * @since 18.0.0
41
+     */
42
+    public function __construct(IManager $manager) {
43
+        parent::__construct();
44 44
 
45
-		$this->manager = $manager;
46
-	}
45
+        $this->manager = $manager;
46
+    }
47 47
 
48
-	/**
49
-	 * @since 18.0.0
50
-	 */
51
-	public function registerCheck(ICheck $check): void {
52
-		$this->manager->registerCheck($check);
53
-	}
48
+    /**
49
+     * @since 18.0.0
50
+     */
51
+    public function registerCheck(ICheck $check): void {
52
+        $this->manager->registerCheck($check);
53
+    }
54 54
 }
Please login to merge, or discard this patch.
lib/public/WorkflowEngine/Events/RegisterEntitiesEvent.php 1 patch
Indentation   +15 added lines, -15 removed lines patch added patch discarded remove patch
@@ -33,22 +33,22 @@
 block discarded – undo
33 33
  */
34 34
 class RegisterEntitiesEvent extends Event {
35 35
 
36
-	/** @var IManager */
37
-	private $manager;
36
+    /** @var IManager */
37
+    private $manager;
38 38
 
39
-	/**
40
-	 * @since 18.0.0
41
-	 */
42
-	public function __construct(IManager $manager) {
43
-		parent::__construct();
39
+    /**
40
+     * @since 18.0.0
41
+     */
42
+    public function __construct(IManager $manager) {
43
+        parent::__construct();
44 44
 
45
-		$this->manager = $manager;
46
-	}
45
+        $this->manager = $manager;
46
+    }
47 47
 
48
-	/**
49
-	 * @since 18.0.0
50
-	 */
51
-	public function registerEntity(IEntity $entity): void {
52
-		$this->manager->registerEntity($entity);
53
-	}
48
+    /**
49
+     * @since 18.0.0
50
+     */
51
+    public function registerEntity(IEntity $entity): void {
52
+        $this->manager->registerEntity($entity);
53
+    }
54 54
 }
Please login to merge, or discard this patch.
apps/workflowengine/lib/Manager.php 1 patch
Indentation   +624 added lines, -624 removed lines patch added patch discarded remove patch
@@ -59,642 +59,642 @@
 block discarded – undo
59 59
 
60 60
 class Manager implements IManager {
61 61
 
62
-	/** @var IStorage */
63
-	protected $storage;
62
+    /** @var IStorage */
63
+    protected $storage;
64 64
 
65
-	/** @var string */
66
-	protected $path;
65
+    /** @var string */
66
+    protected $path;
67 67
 
68
-	/** @var object */
69
-	protected $entity;
68
+    /** @var object */
69
+    protected $entity;
70 70
 
71
-	/** @var array[] */
72
-	protected $operations = [];
71
+    /** @var array[] */
72
+    protected $operations = [];
73 73
 
74
-	/** @var array[] */
75
-	protected $checks = [];
74
+    /** @var array[] */
75
+    protected $checks = [];
76 76
 
77
-	/** @var IDBConnection */
78
-	protected $connection;
77
+    /** @var IDBConnection */
78
+    protected $connection;
79 79
 
80
-	/** @var IServerContainer|\OC\Server */
81
-	protected $container;
80
+    /** @var IServerContainer|\OC\Server */
81
+    protected $container;
82 82
 
83
-	/** @var IL10N */
84
-	protected $l;
83
+    /** @var IL10N */
84
+    protected $l;
85 85
 
86
-	/** @var LegacyDispatcher */
87
-	protected $legacyEventDispatcher;
86
+    /** @var LegacyDispatcher */
87
+    protected $legacyEventDispatcher;
88 88
 
89
-	/** @var IEntity[] */
90
-	protected $registeredEntities = [];
89
+    /** @var IEntity[] */
90
+    protected $registeredEntities = [];
91 91
 
92
-	/** @var IOperation[] */
93
-	protected $registeredOperators = [];
92
+    /** @var IOperation[] */
93
+    protected $registeredOperators = [];
94 94
 
95
-	/** @var ICheck[] */
96
-	protected $registeredChecks = [];
97
-
98
-	/** @var ILogger */
99
-	protected $logger;
95
+    /** @var ICheck[] */
96
+    protected $registeredChecks = [];
97
+
98
+    /** @var ILogger */
99
+    protected $logger;
100 100
 
101
-	/** @var CappedMemoryCache */
102
-	protected $operationsByScope = [];
101
+    /** @var CappedMemoryCache */
102
+    protected $operationsByScope = [];
103 103
 
104
-	/** @var IUserSession */
105
-	protected $session;
104
+    /** @var IUserSession */
105
+    protected $session;
106 106
 
107
-	/** @var IEventDispatcher */
108
-	private $dispatcher;
109
-
110
-	public function __construct(
111
-		IDBConnection $connection,
112
-		IServerContainer $container,
113
-		IL10N $l,
114
-		LegacyDispatcher $eventDispatcher,
115
-		ILogger $logger,
116
-		IUserSession $session,
117
-		IEventDispatcher $dispatcher
118
-	) {
119
-		$this->connection = $connection;
120
-		$this->container = $container;
121
-		$this->l = $l;
122
-		$this->legacyEventDispatcher = $eventDispatcher;
123
-		$this->logger = $logger;
124
-		$this->operationsByScope = new CappedMemoryCache(64);
125
-		$this->session = $session;
126
-		$this->dispatcher = $dispatcher;
127
-	}
128
-
129
-	public function getRuleMatcher(): IRuleMatcher {
130
-		return new RuleMatcher($this->session, $this->container, $this->l, $this);
131
-	}
132
-
133
-	public function getAllConfiguredEvents() {
134
-		$query = $this->connection->getQueryBuilder();
135
-
136
-		$query->selectDistinct('class')
137
-			->addSelect('entity', 'events')
138
-			->from('flow_operations')
139
-			->where($query->expr()->neq('events', $query->createNamedParameter('[]'), IQueryBuilder::PARAM_STR));
140
-
141
-		$result = $query->execute();
142
-		$operations = [];
143
-		while($row = $result->fetch()) {
144
-			$eventNames = \json_decode($row['events']);
145
-
146
-			$operation = $row['class'];
147
-			$entity =  $row['entity'];
148
-
149
-			$operations[$operation] = $operations[$row['class']] ?? [];
150
-			$operations[$operation][$entity] = $operations[$operation][$entity] ?? [];
151
-
152
-			$operations[$operation][$entity] = array_unique(array_merge($operations[$operation][$entity], $eventNames ?? []));
153
-		}
154
-		$result->closeCursor();
155
-
156
-		return $operations;
157
-	}
158
-
159
-	public function getAllConfiguredScopesForOperation(string $operationClass): array {
160
-		static $scopesByOperation = [];
161
-		if (isset($scopesByOperation[$operationClass])) {
162
-			return $scopesByOperation[$operationClass];
163
-		}
164
-
165
-		$query = $this->connection->getQueryBuilder();
166
-
167
-		$query->selectDistinct('s.type')
168
-			->addSelect('s.value')
169
-			->from('flow_operations', 'o')
170
-			->leftJoin('o', 'flow_operations_scope', 's', $query->expr()->eq('o.id', 's.operation_id'))
171
-			->where($query->expr()->eq('o.class', $query->createParameter('operationClass')));
172
-
173
-		$query->setParameters(['operationClass' => $operationClass]);
174
-		$result = $query->execute();
175
-
176
-		$scopesByOperation[$operationClass] = [];
177
-		while ($row = $result->fetch()) {
178
-			$scope = new ScopeContext($row['type'], $row['value']);
179
-			$scopesByOperation[$operationClass][$scope->getHash()] = $scope;
180
-		}
181
-
182
-		return $scopesByOperation[$operationClass];
183
-	}
184
-
185
-	public function getAllOperations(ScopeContext $scopeContext): array {
186
-		if(isset($this->operations[$scopeContext->getHash()])) {
187
-			return $this->operations[$scopeContext->getHash()];
188
-		}
189
-
190
-		$query = $this->connection->getQueryBuilder();
191
-
192
-		$query->select('o.*')
193
-			->selectAlias('s.type', 'scope_type')
194
-			->selectAlias('s.value', 'scope_actor_id')
195
-			->from('flow_operations', 'o')
196
-			->leftJoin('o', 'flow_operations_scope', 's', $query->expr()->eq('o.id', 's.operation_id'))
197
-			->where($query->expr()->eq('s.type', $query->createParameter('scope')));
198
-
199
-		if($scopeContext->getScope() === IManager::SCOPE_USER) {
200
-			$query->andWhere($query->expr()->eq('s.value', $query->createParameter('scopeId')));
201
-		}
202
-
203
-		$query->setParameters(['scope' => $scopeContext->getScope(), 'scopeId' => $scopeContext->getScopeId()]);
204
-		$result = $query->execute();
205
-
206
-		$this->operations[$scopeContext->getHash()] = [];
207
-		while ($row = $result->fetch()) {
208
-			if(!isset($this->operations[$scopeContext->getHash()][$row['class']])) {
209
-				$this->operations[$scopeContext->getHash()][$row['class']] = [];
210
-			}
211
-			$this->operations[$scopeContext->getHash()][$row['class']][] = $row;
212
-		}
213
-
214
-		return $this->operations[$scopeContext->getHash()];
215
-	}
216
-
217
-	public function getOperations(string $class, ScopeContext $scopeContext): array {
218
-		if (!isset($this->operations[$scopeContext->getHash()])) {
219
-			$this->getAllOperations($scopeContext);
220
-		}
221
-		return $this->operations[$scopeContext->getHash()][$class] ?? [];
222
-	}
223
-
224
-	/**
225
-	 * @param int $id
226
-	 * @return array
227
-	 * @throws \UnexpectedValueException
228
-	 */
229
-	protected function getOperation($id) {
230
-		$query = $this->connection->getQueryBuilder();
231
-		$query->select('*')
232
-			->from('flow_operations')
233
-			->where($query->expr()->eq('id', $query->createNamedParameter($id)));
234
-		$result = $query->execute();
235
-		$row = $result->fetch();
236
-		$result->closeCursor();
237
-
238
-		if ($row) {
239
-			return $row;
240
-		}
241
-
242
-		throw new \UnexpectedValueException($this->l->t('Operation #%s does not exist', [$id]));
243
-	}
244
-
245
-	protected function insertOperation(
246
-		string $class,
247
-		string $name,
248
-		array $checkIds,
249
-		string $operation,
250
-		string $entity,
251
-		array $events
252
-	): int {
253
-		$query = $this->connection->getQueryBuilder();
254
-		$query->insert('flow_operations')
255
-			->values([
256
-				'class' => $query->createNamedParameter($class),
257
-				'name' => $query->createNamedParameter($name),
258
-				'checks' => $query->createNamedParameter(json_encode(array_unique($checkIds))),
259
-				'operation' => $query->createNamedParameter($operation),
260
-				'entity' => $query->createNamedParameter($entity),
261
-				'events' => $query->createNamedParameter(json_encode($events))
262
-			]);
263
-		$query->execute();
264
-
265
-		return $query->getLastInsertId();
266
-	}
267
-
268
-	/**
269
-	 * @param string $class
270
-	 * @param string $name
271
-	 * @param array[] $checks
272
-	 * @param string $operation
273
-	 * @return array The added operation
274
-	 * @throws \UnexpectedValueException
275
-	 * @throws DBALException
276
-	 */
277
-	public function addOperation(
278
-		string $class,
279
-		string $name,
280
-		array $checks,
281
-		string $operation,
282
-		ScopeContext $scope,
283
-		string $entity,
284
-		array $events
285
-	) {
286
-		$this->validateOperation($class, $name, $checks, $operation, $entity, $events);
287
-
288
-		$this->connection->beginTransaction();
289
-
290
-		try {
291
-			$checkIds = [];
292
-			foreach ($checks as $check) {
293
-				$checkIds[] = $this->addCheck($check['class'], $check['operator'], $check['value']);
294
-			}
295
-
296
-			$id = $this->insertOperation($class, $name, $checkIds, $operation, $entity, $events);
297
-			$this->addScope($id, $scope);
298
-
299
-			$this->connection->commit();
300
-		} catch (DBALException $e) {
301
-			$this->connection->rollBack();
302
-			throw $e;
303
-		}
304
-
305
-		return $this->getOperation($id);
306
-	}
307
-
308
-	protected function canModify(int $id, ScopeContext $scopeContext):bool {
309
-		if(isset($this->operationsByScope[$scopeContext->getHash()])) {
310
-			return in_array($id, $this->operationsByScope[$scopeContext->getHash()], true);
311
-		}
312
-
313
-		$qb = $this->connection->getQueryBuilder();
314
-		$qb = $qb->select('o.id')
315
-			->from('flow_operations', 'o')
316
-			->leftJoin('o', 'flow_operations_scope', 's', $qb->expr()->eq('o.id', 's.operation_id'))
317
-			->where($qb->expr()->eq('s.type', $qb->createParameter('scope')));
318
-
319
-		if($scopeContext->getScope() !== IManager::SCOPE_ADMIN) {
320
-			$qb->where($qb->expr()->eq('s.value', $qb->createParameter('scopeId')));
321
-		}
322
-
323
-		$qb->setParameters(['scope' => $scopeContext->getScope(), 'scopeId' => $scopeContext->getScopeId()]);
324
-		$result = $qb->execute();
325
-
326
-		$this->operationsByScope[$scopeContext->getHash()] = [];
327
-		while($opId = $result->fetchColumn(0)) {
328
-			$this->operationsByScope[$scopeContext->getHash()][] = (int)$opId;
329
-		}
330
-		$result->closeCursor();
331
-
332
-		return in_array($id, $this->operationsByScope[$scopeContext->getHash()], true);
333
-	}
334
-
335
-	/**
336
-	 * @param int $id
337
-	 * @param string $name
338
-	 * @param array[] $checks
339
-	 * @param string $operation
340
-	 * @return array The updated operation
341
-	 * @throws \UnexpectedValueException
342
-	 * @throws \DomainException
343
-	 * @throws DBALException
344
-	 */
345
-	public function updateOperation(
346
-		int $id,
347
-		string $name,
348
-		array $checks,
349
-		string $operation,
350
-		ScopeContext $scopeContext,
351
-		string $entity,
352
-		array $events
353
-	): array {
354
-		if(!$this->canModify($id, $scopeContext)) {
355
-			throw new \DomainException('Target operation not within scope');
356
-		};
357
-		$row = $this->getOperation($id);
358
-		$this->validateOperation($row['class'], $name, $checks, $operation, $entity, $events);
359
-
360
-		$checkIds = [];
361
-		try {
362
-			$this->connection->beginTransaction();
363
-			foreach ($checks as $check) {
364
-				$checkIds[] = $this->addCheck($check['class'], $check['operator'], $check['value']);
365
-			}
366
-
367
-			$query = $this->connection->getQueryBuilder();
368
-			$query->update('flow_operations')
369
-				->set('name', $query->createNamedParameter($name))
370
-				->set('checks', $query->createNamedParameter(json_encode(array_unique($checkIds))))
371
-				->set('operation', $query->createNamedParameter($operation))
372
-				->set('entity', $query->createNamedParameter($entity))
373
-				->set('events', $query->createNamedParameter(json_encode($events)))
374
-				->where($query->expr()->eq('id', $query->createNamedParameter($id)));
375
-			$query->execute();
376
-			$this->connection->commit();
377
-		} catch (DBALException $e) {
378
-			$this->connection->rollBack();
379
-			throw $e;
380
-		}
381
-		unset($this->operations[$scopeContext->getHash()]);
382
-
383
-		return $this->getOperation($id);
384
-	}
385
-
386
-	/**
387
-	 * @param int $id
388
-	 * @return bool
389
-	 * @throws \UnexpectedValueException
390
-	 * @throws DBALException
391
-	 * @throws \DomainException
392
-	 */
393
-	public function deleteOperation($id, ScopeContext $scopeContext) {
394
-		if(!$this->canModify($id, $scopeContext)) {
395
-			throw new \DomainException('Target operation not within scope');
396
-		};
397
-		$query = $this->connection->getQueryBuilder();
398
-		try {
399
-			$this->connection->beginTransaction();
400
-			$result = (bool)$query->delete('flow_operations')
401
-				->where($query->expr()->eq('id', $query->createNamedParameter($id)))
402
-				->execute();
403
-			if($result) {
404
-				$qb = $this->connection->getQueryBuilder();
405
-				$result &= (bool)$qb->delete('flow_operations_scope')
406
-					->where($qb->expr()->eq('operation_id', $qb->createNamedParameter($id)))
407
-					->execute();
408
-			}
409
-			$this->connection->commit();
410
-		} catch (DBALException $e) {
411
-			$this->connection->rollBack();
412
-			throw $e;
413
-		}
414
-
415
-		if(isset($this->operations[$scopeContext->getHash()])) {
416
-			unset($this->operations[$scopeContext->getHash()]);
417
-		}
418
-
419
-		return $result;
420
-	}
421
-
422
-	protected function validateEvents(string $entity, array $events, IOperation $operation) {
423
-		try {
424
-			/** @var IEntity $instance */
425
-			$instance = $this->container->query($entity);
426
-		} catch (QueryException $e) {
427
-			throw new \UnexpectedValueException($this->l->t('Entity %s does not exist', [$entity]));
428
-		}
429
-
430
-		if(!$instance instanceof IEntity) {
431
-			throw new \UnexpectedValueException($this->l->t('Entity %s is invalid', [$entity]));
432
-		}
433
-
434
-		if(empty($events)) {
435
-			if(!$operation instanceof IComplexOperation) {
436
-				throw new \UnexpectedValueException($this->l->t('No events are chosen.'));
437
-			}
438
-			return;
439
-		}
440
-
441
-		$availableEvents = [];
442
-		foreach ($instance->getEvents() as $event) {
443
-			/** @var IEntityEvent $event */
444
-			$availableEvents[] = $event->getEventName();
445
-		}
446
-
447
-		$diff = array_diff($events, $availableEvents);
448
-		if(!empty($diff)) {
449
-			throw new \UnexpectedValueException($this->l->t('Entity %s has no event %s', [$entity, array_shift($diff)]));
450
-		}
451
-	}
452
-
453
-	/**
454
-	 * @param string $class
455
-	 * @param string $name
456
-	 * @param array[] $checks
457
-	 * @param string $operation
458
-	 * @throws \UnexpectedValueException
459
-	 */
460
-	public function validateOperation($class, $name, array $checks, $operation, string $entity, array $events) {
461
-		try {
462
-			/** @var IOperation $instance */
463
-			$instance = $this->container->query($class);
464
-		} catch (QueryException $e) {
465
-			throw new \UnexpectedValueException($this->l->t('Operation %s does not exist', [$class]));
466
-		}
467
-
468
-		if (!($instance instanceof IOperation)) {
469
-			throw new \UnexpectedValueException($this->l->t('Operation %s is invalid', [$class]));
470
-		}
471
-
472
-		$this->validateEvents($entity, $events, $instance);
473
-
474
-		if (count($checks) === 0) {
475
-			throw new \UnexpectedValueException($this->l->t('At least one check needs to be provided'));
476
-		}
477
-		$instance->validateOperation($name, $checks, $operation);
478
-
479
-		foreach ($checks as $check) {
480
-			if (!is_string($check['class'])) {
481
-				throw new \UnexpectedValueException($this->l->t('Invalid check provided'));
482
-			}
483
-
484
-			try {
485
-				/** @var ICheck $instance */
486
-				$instance = $this->container->query($check['class']);
487
-			} catch (QueryException $e) {
488
-				throw new \UnexpectedValueException($this->l->t('Check %s does not exist', [$class]));
489
-			}
490
-
491
-			if (!($instance instanceof ICheck)) {
492
-				throw new \UnexpectedValueException($this->l->t('Check %s is invalid', [$class]));
493
-			}
494
-
495
-			if (!empty($instance->supportedEntities())
496
-				&& !in_array($entity, $instance->supportedEntities())
497
-			) {
498
-				throw new \UnexpectedValueException($this->l->t('Check %s is not allowed with this entity', [$class]));
499
-			}
500
-
501
-			$instance->validateCheck($check['operator'], $check['value']);
502
-		}
503
-	}
504
-
505
-	/**
506
-	 * @param int[] $checkIds
507
-	 * @return array[]
508
-	 */
509
-	public function getChecks(array $checkIds) {
510
-		$checkIds = array_map('intval', $checkIds);
511
-
512
-		$checks = [];
513
-		foreach ($checkIds as $i => $checkId) {
514
-			if (isset($this->checks[$checkId])) {
515
-				$checks[$checkId] = $this->checks[$checkId];
516
-				unset($checkIds[$i]);
517
-			}
518
-		}
519
-
520
-		if (empty($checkIds)) {
521
-			return $checks;
522
-		}
523
-
524
-		$query = $this->connection->getQueryBuilder();
525
-		$query->select('*')
526
-			->from('flow_checks')
527
-			->where($query->expr()->in('id', $query->createNamedParameter($checkIds, IQueryBuilder::PARAM_INT_ARRAY)));
528
-		$result = $query->execute();
529
-
530
-		while ($row = $result->fetch()) {
531
-			$this->checks[(int) $row['id']] = $row;
532
-			$checks[(int) $row['id']] = $row;
533
-		}
534
-		$result->closeCursor();
535
-
536
-		$checkIds = array_diff($checkIds, array_keys($checks));
537
-
538
-		if (!empty($checkIds)) {
539
-			$missingCheck = array_pop($checkIds);
540
-			throw new \UnexpectedValueException($this->l->t('Check #%s does not exist', $missingCheck));
541
-		}
542
-
543
-		return $checks;
544
-	}
545
-
546
-	/**
547
-	 * @param string $class
548
-	 * @param string $operator
549
-	 * @param string $value
550
-	 * @return int Check unique ID
551
-	 */
552
-	protected function addCheck($class, $operator, $value) {
553
-		$hash = md5($class . '::' . $operator . '::' . $value);
554
-
555
-		$query = $this->connection->getQueryBuilder();
556
-		$query->select('id')
557
-			->from('flow_checks')
558
-			->where($query->expr()->eq('hash', $query->createNamedParameter($hash)));
559
-		$result = $query->execute();
560
-
561
-		if ($row = $result->fetch()) {
562
-			$result->closeCursor();
563
-			return (int) $row['id'];
564
-		}
565
-
566
-		$query = $this->connection->getQueryBuilder();
567
-		$query->insert('flow_checks')
568
-			->values([
569
-				'class' => $query->createNamedParameter($class),
570
-				'operator' => $query->createNamedParameter($operator),
571
-				'value' => $query->createNamedParameter($value),
572
-				'hash' => $query->createNamedParameter($hash),
573
-			]);
574
-		$query->execute();
575
-
576
-		return $query->getLastInsertId();
577
-	}
578
-
579
-	protected function addScope(int $operationId, ScopeContext $scope): void {
580
-		$query = $this->connection->getQueryBuilder();
581
-
582
-		$insertQuery = $query->insert('flow_operations_scope');
583
-		$insertQuery->values([
584
-			'operation_id' => $query->createNamedParameter($operationId),
585
-			'type' => $query->createNamedParameter($scope->getScope()),
586
-			'value' => $query->createNamedParameter($scope->getScopeId()),
587
-		]);
588
-		$insertQuery->execute();
589
-	}
590
-
591
-	public function formatOperation(array $operation): array {
592
-		$checkIds = json_decode($operation['checks'], true);
593
-		$checks = $this->getChecks($checkIds);
594
-
595
-		$operation['checks'] = [];
596
-		foreach ($checks as $check) {
597
-			// Remove internal values
598
-			unset($check['id']);
599
-			unset($check['hash']);
600
-
601
-			$operation['checks'][] = $check;
602
-		}
603
-		$operation['events'] = json_decode($operation['events'], true) ?? [];
604
-
605
-
606
-		return $operation;
607
-	}
608
-
609
-	/**
610
-	 * @return IEntity[]
611
-	 */
612
-	public function getEntitiesList(): array {
613
-		$this->dispatcher->dispatchTyped(new RegisterEntitiesEvent($this));
614
-		$this->legacyEventDispatcher->dispatch(IManager::EVENT_NAME_REG_ENTITY, new GenericEvent($this));
615
-
616
-		return array_values(array_merge($this->getBuildInEntities(), $this->registeredEntities));
617
-	}
618
-
619
-	/**
620
-	 * @return IOperation[]
621
-	 */
622
-	public function getOperatorList(): array {
623
-		$this->dispatcher->dispatchTyped(new RegisterOperationsEvent($this));
624
-		$this->legacyEventDispatcher->dispatch(IManager::EVENT_NAME_REG_OPERATION, new GenericEvent($this));
625
-
626
-		return array_merge($this->getBuildInOperators(), $this->registeredOperators);
627
-	}
628
-
629
-	/**
630
-	 * @return ICheck[]
631
-	 */
632
-	public function getCheckList(): array {
633
-		$this->dispatcher->dispatchTyped(new RegisterChecksEvent($this));
634
-		$this->legacyEventDispatcher->dispatch(IManager::EVENT_NAME_REG_CHECK, new GenericEvent($this));
635
-
636
-		return array_merge($this->getBuildInChecks(), $this->registeredChecks);
637
-	}
638
-
639
-	public function registerEntity(IEntity $entity): void {
640
-		$this->registeredEntities[get_class($entity)] = $entity;
641
-	}
642
-
643
-	public function registerOperation(IOperation $operator): void {
644
-		$this->registeredOperators[get_class($operator)] = $operator;
645
-	}
646
-
647
-	public function registerCheck(ICheck $check): void {
648
-		$this->registeredChecks[get_class($check)] = $check;
649
-	}
650
-
651
-	/**
652
-	 * @return IEntity[]
653
-	 */
654
-	protected function getBuildInEntities(): array {
655
-		try {
656
-			return [
657
-				File::class => $this->container->query(File::class),
658
-			];
659
-		} catch (QueryException $e) {
660
-			$this->logger->logException($e);
661
-			return [];
662
-		}
663
-	}
664
-
665
-	/**
666
-	 * @return IOperation[]
667
-	 */
668
-	protected function getBuildInOperators(): array {
669
-		try {
670
-			return [
671
-				// None yet
672
-			];
673
-		} catch (QueryException $e) {
674
-			$this->logger->logException($e);
675
-			return [];
676
-		}
677
-	}
678
-
679
-	/**
680
-	 * @return IEntity[]
681
-	 */
682
-	protected function getBuildInChecks(): array {
683
-		try {
684
-			return [
685
-				$this->container->query(FileMimeType::class),
686
-				$this->container->query(FileName::class),
687
-				$this->container->query(FileSize::class),
688
-				$this->container->query(FileSystemTags::class),
689
-				$this->container->query(RequestRemoteAddress::class),
690
-				$this->container->query(RequestTime::class),
691
-				$this->container->query(RequestURL::class),
692
-				$this->container->query(RequestUserAgent::class),
693
-				$this->container->query(UserGroupMembership::class),
694
-			];
695
-		} catch (QueryException $e) {
696
-			$this->logger->logException($e);
697
-			return [];
698
-		}
699
-	}
107
+    /** @var IEventDispatcher */
108
+    private $dispatcher;
109
+
110
+    public function __construct(
111
+        IDBConnection $connection,
112
+        IServerContainer $container,
113
+        IL10N $l,
114
+        LegacyDispatcher $eventDispatcher,
115
+        ILogger $logger,
116
+        IUserSession $session,
117
+        IEventDispatcher $dispatcher
118
+    ) {
119
+        $this->connection = $connection;
120
+        $this->container = $container;
121
+        $this->l = $l;
122
+        $this->legacyEventDispatcher = $eventDispatcher;
123
+        $this->logger = $logger;
124
+        $this->operationsByScope = new CappedMemoryCache(64);
125
+        $this->session = $session;
126
+        $this->dispatcher = $dispatcher;
127
+    }
128
+
129
+    public function getRuleMatcher(): IRuleMatcher {
130
+        return new RuleMatcher($this->session, $this->container, $this->l, $this);
131
+    }
132
+
133
+    public function getAllConfiguredEvents() {
134
+        $query = $this->connection->getQueryBuilder();
135
+
136
+        $query->selectDistinct('class')
137
+            ->addSelect('entity', 'events')
138
+            ->from('flow_operations')
139
+            ->where($query->expr()->neq('events', $query->createNamedParameter('[]'), IQueryBuilder::PARAM_STR));
140
+
141
+        $result = $query->execute();
142
+        $operations = [];
143
+        while($row = $result->fetch()) {
144
+            $eventNames = \json_decode($row['events']);
145
+
146
+            $operation = $row['class'];
147
+            $entity =  $row['entity'];
148
+
149
+            $operations[$operation] = $operations[$row['class']] ?? [];
150
+            $operations[$operation][$entity] = $operations[$operation][$entity] ?? [];
151
+
152
+            $operations[$operation][$entity] = array_unique(array_merge($operations[$operation][$entity], $eventNames ?? []));
153
+        }
154
+        $result->closeCursor();
155
+
156
+        return $operations;
157
+    }
158
+
159
+    public function getAllConfiguredScopesForOperation(string $operationClass): array {
160
+        static $scopesByOperation = [];
161
+        if (isset($scopesByOperation[$operationClass])) {
162
+            return $scopesByOperation[$operationClass];
163
+        }
164
+
165
+        $query = $this->connection->getQueryBuilder();
166
+
167
+        $query->selectDistinct('s.type')
168
+            ->addSelect('s.value')
169
+            ->from('flow_operations', 'o')
170
+            ->leftJoin('o', 'flow_operations_scope', 's', $query->expr()->eq('o.id', 's.operation_id'))
171
+            ->where($query->expr()->eq('o.class', $query->createParameter('operationClass')));
172
+
173
+        $query->setParameters(['operationClass' => $operationClass]);
174
+        $result = $query->execute();
175
+
176
+        $scopesByOperation[$operationClass] = [];
177
+        while ($row = $result->fetch()) {
178
+            $scope = new ScopeContext($row['type'], $row['value']);
179
+            $scopesByOperation[$operationClass][$scope->getHash()] = $scope;
180
+        }
181
+
182
+        return $scopesByOperation[$operationClass];
183
+    }
184
+
185
+    public function getAllOperations(ScopeContext $scopeContext): array {
186
+        if(isset($this->operations[$scopeContext->getHash()])) {
187
+            return $this->operations[$scopeContext->getHash()];
188
+        }
189
+
190
+        $query = $this->connection->getQueryBuilder();
191
+
192
+        $query->select('o.*')
193
+            ->selectAlias('s.type', 'scope_type')
194
+            ->selectAlias('s.value', 'scope_actor_id')
195
+            ->from('flow_operations', 'o')
196
+            ->leftJoin('o', 'flow_operations_scope', 's', $query->expr()->eq('o.id', 's.operation_id'))
197
+            ->where($query->expr()->eq('s.type', $query->createParameter('scope')));
198
+
199
+        if($scopeContext->getScope() === IManager::SCOPE_USER) {
200
+            $query->andWhere($query->expr()->eq('s.value', $query->createParameter('scopeId')));
201
+        }
202
+
203
+        $query->setParameters(['scope' => $scopeContext->getScope(), 'scopeId' => $scopeContext->getScopeId()]);
204
+        $result = $query->execute();
205
+
206
+        $this->operations[$scopeContext->getHash()] = [];
207
+        while ($row = $result->fetch()) {
208
+            if(!isset($this->operations[$scopeContext->getHash()][$row['class']])) {
209
+                $this->operations[$scopeContext->getHash()][$row['class']] = [];
210
+            }
211
+            $this->operations[$scopeContext->getHash()][$row['class']][] = $row;
212
+        }
213
+
214
+        return $this->operations[$scopeContext->getHash()];
215
+    }
216
+
217
+    public function getOperations(string $class, ScopeContext $scopeContext): array {
218
+        if (!isset($this->operations[$scopeContext->getHash()])) {
219
+            $this->getAllOperations($scopeContext);
220
+        }
221
+        return $this->operations[$scopeContext->getHash()][$class] ?? [];
222
+    }
223
+
224
+    /**
225
+     * @param int $id
226
+     * @return array
227
+     * @throws \UnexpectedValueException
228
+     */
229
+    protected function getOperation($id) {
230
+        $query = $this->connection->getQueryBuilder();
231
+        $query->select('*')
232
+            ->from('flow_operations')
233
+            ->where($query->expr()->eq('id', $query->createNamedParameter($id)));
234
+        $result = $query->execute();
235
+        $row = $result->fetch();
236
+        $result->closeCursor();
237
+
238
+        if ($row) {
239
+            return $row;
240
+        }
241
+
242
+        throw new \UnexpectedValueException($this->l->t('Operation #%s does not exist', [$id]));
243
+    }
244
+
245
+    protected function insertOperation(
246
+        string $class,
247
+        string $name,
248
+        array $checkIds,
249
+        string $operation,
250
+        string $entity,
251
+        array $events
252
+    ): int {
253
+        $query = $this->connection->getQueryBuilder();
254
+        $query->insert('flow_operations')
255
+            ->values([
256
+                'class' => $query->createNamedParameter($class),
257
+                'name' => $query->createNamedParameter($name),
258
+                'checks' => $query->createNamedParameter(json_encode(array_unique($checkIds))),
259
+                'operation' => $query->createNamedParameter($operation),
260
+                'entity' => $query->createNamedParameter($entity),
261
+                'events' => $query->createNamedParameter(json_encode($events))
262
+            ]);
263
+        $query->execute();
264
+
265
+        return $query->getLastInsertId();
266
+    }
267
+
268
+    /**
269
+     * @param string $class
270
+     * @param string $name
271
+     * @param array[] $checks
272
+     * @param string $operation
273
+     * @return array The added operation
274
+     * @throws \UnexpectedValueException
275
+     * @throws DBALException
276
+     */
277
+    public function addOperation(
278
+        string $class,
279
+        string $name,
280
+        array $checks,
281
+        string $operation,
282
+        ScopeContext $scope,
283
+        string $entity,
284
+        array $events
285
+    ) {
286
+        $this->validateOperation($class, $name, $checks, $operation, $entity, $events);
287
+
288
+        $this->connection->beginTransaction();
289
+
290
+        try {
291
+            $checkIds = [];
292
+            foreach ($checks as $check) {
293
+                $checkIds[] = $this->addCheck($check['class'], $check['operator'], $check['value']);
294
+            }
295
+
296
+            $id = $this->insertOperation($class, $name, $checkIds, $operation, $entity, $events);
297
+            $this->addScope($id, $scope);
298
+
299
+            $this->connection->commit();
300
+        } catch (DBALException $e) {
301
+            $this->connection->rollBack();
302
+            throw $e;
303
+        }
304
+
305
+        return $this->getOperation($id);
306
+    }
307
+
308
+    protected function canModify(int $id, ScopeContext $scopeContext):bool {
309
+        if(isset($this->operationsByScope[$scopeContext->getHash()])) {
310
+            return in_array($id, $this->operationsByScope[$scopeContext->getHash()], true);
311
+        }
312
+
313
+        $qb = $this->connection->getQueryBuilder();
314
+        $qb = $qb->select('o.id')
315
+            ->from('flow_operations', 'o')
316
+            ->leftJoin('o', 'flow_operations_scope', 's', $qb->expr()->eq('o.id', 's.operation_id'))
317
+            ->where($qb->expr()->eq('s.type', $qb->createParameter('scope')));
318
+
319
+        if($scopeContext->getScope() !== IManager::SCOPE_ADMIN) {
320
+            $qb->where($qb->expr()->eq('s.value', $qb->createParameter('scopeId')));
321
+        }
322
+
323
+        $qb->setParameters(['scope' => $scopeContext->getScope(), 'scopeId' => $scopeContext->getScopeId()]);
324
+        $result = $qb->execute();
325
+
326
+        $this->operationsByScope[$scopeContext->getHash()] = [];
327
+        while($opId = $result->fetchColumn(0)) {
328
+            $this->operationsByScope[$scopeContext->getHash()][] = (int)$opId;
329
+        }
330
+        $result->closeCursor();
331
+
332
+        return in_array($id, $this->operationsByScope[$scopeContext->getHash()], true);
333
+    }
334
+
335
+    /**
336
+     * @param int $id
337
+     * @param string $name
338
+     * @param array[] $checks
339
+     * @param string $operation
340
+     * @return array The updated operation
341
+     * @throws \UnexpectedValueException
342
+     * @throws \DomainException
343
+     * @throws DBALException
344
+     */
345
+    public function updateOperation(
346
+        int $id,
347
+        string $name,
348
+        array $checks,
349
+        string $operation,
350
+        ScopeContext $scopeContext,
351
+        string $entity,
352
+        array $events
353
+    ): array {
354
+        if(!$this->canModify($id, $scopeContext)) {
355
+            throw new \DomainException('Target operation not within scope');
356
+        };
357
+        $row = $this->getOperation($id);
358
+        $this->validateOperation($row['class'], $name, $checks, $operation, $entity, $events);
359
+
360
+        $checkIds = [];
361
+        try {
362
+            $this->connection->beginTransaction();
363
+            foreach ($checks as $check) {
364
+                $checkIds[] = $this->addCheck($check['class'], $check['operator'], $check['value']);
365
+            }
366
+
367
+            $query = $this->connection->getQueryBuilder();
368
+            $query->update('flow_operations')
369
+                ->set('name', $query->createNamedParameter($name))
370
+                ->set('checks', $query->createNamedParameter(json_encode(array_unique($checkIds))))
371
+                ->set('operation', $query->createNamedParameter($operation))
372
+                ->set('entity', $query->createNamedParameter($entity))
373
+                ->set('events', $query->createNamedParameter(json_encode($events)))
374
+                ->where($query->expr()->eq('id', $query->createNamedParameter($id)));
375
+            $query->execute();
376
+            $this->connection->commit();
377
+        } catch (DBALException $e) {
378
+            $this->connection->rollBack();
379
+            throw $e;
380
+        }
381
+        unset($this->operations[$scopeContext->getHash()]);
382
+
383
+        return $this->getOperation($id);
384
+    }
385
+
386
+    /**
387
+     * @param int $id
388
+     * @return bool
389
+     * @throws \UnexpectedValueException
390
+     * @throws DBALException
391
+     * @throws \DomainException
392
+     */
393
+    public function deleteOperation($id, ScopeContext $scopeContext) {
394
+        if(!$this->canModify($id, $scopeContext)) {
395
+            throw new \DomainException('Target operation not within scope');
396
+        };
397
+        $query = $this->connection->getQueryBuilder();
398
+        try {
399
+            $this->connection->beginTransaction();
400
+            $result = (bool)$query->delete('flow_operations')
401
+                ->where($query->expr()->eq('id', $query->createNamedParameter($id)))
402
+                ->execute();
403
+            if($result) {
404
+                $qb = $this->connection->getQueryBuilder();
405
+                $result &= (bool)$qb->delete('flow_operations_scope')
406
+                    ->where($qb->expr()->eq('operation_id', $qb->createNamedParameter($id)))
407
+                    ->execute();
408
+            }
409
+            $this->connection->commit();
410
+        } catch (DBALException $e) {
411
+            $this->connection->rollBack();
412
+            throw $e;
413
+        }
414
+
415
+        if(isset($this->operations[$scopeContext->getHash()])) {
416
+            unset($this->operations[$scopeContext->getHash()]);
417
+        }
418
+
419
+        return $result;
420
+    }
421
+
422
+    protected function validateEvents(string $entity, array $events, IOperation $operation) {
423
+        try {
424
+            /** @var IEntity $instance */
425
+            $instance = $this->container->query($entity);
426
+        } catch (QueryException $e) {
427
+            throw new \UnexpectedValueException($this->l->t('Entity %s does not exist', [$entity]));
428
+        }
429
+
430
+        if(!$instance instanceof IEntity) {
431
+            throw new \UnexpectedValueException($this->l->t('Entity %s is invalid', [$entity]));
432
+        }
433
+
434
+        if(empty($events)) {
435
+            if(!$operation instanceof IComplexOperation) {
436
+                throw new \UnexpectedValueException($this->l->t('No events are chosen.'));
437
+            }
438
+            return;
439
+        }
440
+
441
+        $availableEvents = [];
442
+        foreach ($instance->getEvents() as $event) {
443
+            /** @var IEntityEvent $event */
444
+            $availableEvents[] = $event->getEventName();
445
+        }
446
+
447
+        $diff = array_diff($events, $availableEvents);
448
+        if(!empty($diff)) {
449
+            throw new \UnexpectedValueException($this->l->t('Entity %s has no event %s', [$entity, array_shift($diff)]));
450
+        }
451
+    }
452
+
453
+    /**
454
+     * @param string $class
455
+     * @param string $name
456
+     * @param array[] $checks
457
+     * @param string $operation
458
+     * @throws \UnexpectedValueException
459
+     */
460
+    public function validateOperation($class, $name, array $checks, $operation, string $entity, array $events) {
461
+        try {
462
+            /** @var IOperation $instance */
463
+            $instance = $this->container->query($class);
464
+        } catch (QueryException $e) {
465
+            throw new \UnexpectedValueException($this->l->t('Operation %s does not exist', [$class]));
466
+        }
467
+
468
+        if (!($instance instanceof IOperation)) {
469
+            throw new \UnexpectedValueException($this->l->t('Operation %s is invalid', [$class]));
470
+        }
471
+
472
+        $this->validateEvents($entity, $events, $instance);
473
+
474
+        if (count($checks) === 0) {
475
+            throw new \UnexpectedValueException($this->l->t('At least one check needs to be provided'));
476
+        }
477
+        $instance->validateOperation($name, $checks, $operation);
478
+
479
+        foreach ($checks as $check) {
480
+            if (!is_string($check['class'])) {
481
+                throw new \UnexpectedValueException($this->l->t('Invalid check provided'));
482
+            }
483
+
484
+            try {
485
+                /** @var ICheck $instance */
486
+                $instance = $this->container->query($check['class']);
487
+            } catch (QueryException $e) {
488
+                throw new \UnexpectedValueException($this->l->t('Check %s does not exist', [$class]));
489
+            }
490
+
491
+            if (!($instance instanceof ICheck)) {
492
+                throw new \UnexpectedValueException($this->l->t('Check %s is invalid', [$class]));
493
+            }
494
+
495
+            if (!empty($instance->supportedEntities())
496
+                && !in_array($entity, $instance->supportedEntities())
497
+            ) {
498
+                throw new \UnexpectedValueException($this->l->t('Check %s is not allowed with this entity', [$class]));
499
+            }
500
+
501
+            $instance->validateCheck($check['operator'], $check['value']);
502
+        }
503
+    }
504
+
505
+    /**
506
+     * @param int[] $checkIds
507
+     * @return array[]
508
+     */
509
+    public function getChecks(array $checkIds) {
510
+        $checkIds = array_map('intval', $checkIds);
511
+
512
+        $checks = [];
513
+        foreach ($checkIds as $i => $checkId) {
514
+            if (isset($this->checks[$checkId])) {
515
+                $checks[$checkId] = $this->checks[$checkId];
516
+                unset($checkIds[$i]);
517
+            }
518
+        }
519
+
520
+        if (empty($checkIds)) {
521
+            return $checks;
522
+        }
523
+
524
+        $query = $this->connection->getQueryBuilder();
525
+        $query->select('*')
526
+            ->from('flow_checks')
527
+            ->where($query->expr()->in('id', $query->createNamedParameter($checkIds, IQueryBuilder::PARAM_INT_ARRAY)));
528
+        $result = $query->execute();
529
+
530
+        while ($row = $result->fetch()) {
531
+            $this->checks[(int) $row['id']] = $row;
532
+            $checks[(int) $row['id']] = $row;
533
+        }
534
+        $result->closeCursor();
535
+
536
+        $checkIds = array_diff($checkIds, array_keys($checks));
537
+
538
+        if (!empty($checkIds)) {
539
+            $missingCheck = array_pop($checkIds);
540
+            throw new \UnexpectedValueException($this->l->t('Check #%s does not exist', $missingCheck));
541
+        }
542
+
543
+        return $checks;
544
+    }
545
+
546
+    /**
547
+     * @param string $class
548
+     * @param string $operator
549
+     * @param string $value
550
+     * @return int Check unique ID
551
+     */
552
+    protected function addCheck($class, $operator, $value) {
553
+        $hash = md5($class . '::' . $operator . '::' . $value);
554
+
555
+        $query = $this->connection->getQueryBuilder();
556
+        $query->select('id')
557
+            ->from('flow_checks')
558
+            ->where($query->expr()->eq('hash', $query->createNamedParameter($hash)));
559
+        $result = $query->execute();
560
+
561
+        if ($row = $result->fetch()) {
562
+            $result->closeCursor();
563
+            return (int) $row['id'];
564
+        }
565
+
566
+        $query = $this->connection->getQueryBuilder();
567
+        $query->insert('flow_checks')
568
+            ->values([
569
+                'class' => $query->createNamedParameter($class),
570
+                'operator' => $query->createNamedParameter($operator),
571
+                'value' => $query->createNamedParameter($value),
572
+                'hash' => $query->createNamedParameter($hash),
573
+            ]);
574
+        $query->execute();
575
+
576
+        return $query->getLastInsertId();
577
+    }
578
+
579
+    protected function addScope(int $operationId, ScopeContext $scope): void {
580
+        $query = $this->connection->getQueryBuilder();
581
+
582
+        $insertQuery = $query->insert('flow_operations_scope');
583
+        $insertQuery->values([
584
+            'operation_id' => $query->createNamedParameter($operationId),
585
+            'type' => $query->createNamedParameter($scope->getScope()),
586
+            'value' => $query->createNamedParameter($scope->getScopeId()),
587
+        ]);
588
+        $insertQuery->execute();
589
+    }
590
+
591
+    public function formatOperation(array $operation): array {
592
+        $checkIds = json_decode($operation['checks'], true);
593
+        $checks = $this->getChecks($checkIds);
594
+
595
+        $operation['checks'] = [];
596
+        foreach ($checks as $check) {
597
+            // Remove internal values
598
+            unset($check['id']);
599
+            unset($check['hash']);
600
+
601
+            $operation['checks'][] = $check;
602
+        }
603
+        $operation['events'] = json_decode($operation['events'], true) ?? [];
604
+
605
+
606
+        return $operation;
607
+    }
608
+
609
+    /**
610
+     * @return IEntity[]
611
+     */
612
+    public function getEntitiesList(): array {
613
+        $this->dispatcher->dispatchTyped(new RegisterEntitiesEvent($this));
614
+        $this->legacyEventDispatcher->dispatch(IManager::EVENT_NAME_REG_ENTITY, new GenericEvent($this));
615
+
616
+        return array_values(array_merge($this->getBuildInEntities(), $this->registeredEntities));
617
+    }
618
+
619
+    /**
620
+     * @return IOperation[]
621
+     */
622
+    public function getOperatorList(): array {
623
+        $this->dispatcher->dispatchTyped(new RegisterOperationsEvent($this));
624
+        $this->legacyEventDispatcher->dispatch(IManager::EVENT_NAME_REG_OPERATION, new GenericEvent($this));
625
+
626
+        return array_merge($this->getBuildInOperators(), $this->registeredOperators);
627
+    }
628
+
629
+    /**
630
+     * @return ICheck[]
631
+     */
632
+    public function getCheckList(): array {
633
+        $this->dispatcher->dispatchTyped(new RegisterChecksEvent($this));
634
+        $this->legacyEventDispatcher->dispatch(IManager::EVENT_NAME_REG_CHECK, new GenericEvent($this));
635
+
636
+        return array_merge($this->getBuildInChecks(), $this->registeredChecks);
637
+    }
638
+
639
+    public function registerEntity(IEntity $entity): void {
640
+        $this->registeredEntities[get_class($entity)] = $entity;
641
+    }
642
+
643
+    public function registerOperation(IOperation $operator): void {
644
+        $this->registeredOperators[get_class($operator)] = $operator;
645
+    }
646
+
647
+    public function registerCheck(ICheck $check): void {
648
+        $this->registeredChecks[get_class($check)] = $check;
649
+    }
650
+
651
+    /**
652
+     * @return IEntity[]
653
+     */
654
+    protected function getBuildInEntities(): array {
655
+        try {
656
+            return [
657
+                File::class => $this->container->query(File::class),
658
+            ];
659
+        } catch (QueryException $e) {
660
+            $this->logger->logException($e);
661
+            return [];
662
+        }
663
+    }
664
+
665
+    /**
666
+     * @return IOperation[]
667
+     */
668
+    protected function getBuildInOperators(): array {
669
+        try {
670
+            return [
671
+                // None yet
672
+            ];
673
+        } catch (QueryException $e) {
674
+            $this->logger->logException($e);
675
+            return [];
676
+        }
677
+    }
678
+
679
+    /**
680
+     * @return IEntity[]
681
+     */
682
+    protected function getBuildInChecks(): array {
683
+        try {
684
+            return [
685
+                $this->container->query(FileMimeType::class),
686
+                $this->container->query(FileName::class),
687
+                $this->container->query(FileSize::class),
688
+                $this->container->query(FileSystemTags::class),
689
+                $this->container->query(RequestRemoteAddress::class),
690
+                $this->container->query(RequestTime::class),
691
+                $this->container->query(RequestURL::class),
692
+                $this->container->query(RequestUserAgent::class),
693
+                $this->container->query(UserGroupMembership::class),
694
+            ];
695
+        } catch (QueryException $e) {
696
+            $this->logger->logException($e);
697
+            return [];
698
+        }
699
+    }
700 700
 }
Please login to merge, or discard this patch.