Lines 100.00% 17 / 17
Functions and Methods 100.00% 5 / 5
Classes and Traits 100.00% 1 / 1
Name Lines Functions and Methods CRAP Classes and Traits
EntityFilterIndex 100.00% 17 / 17 100.00% 5 / 5 10 100.00% 1 / 1
 __construct 100.00% 1 / 1 100.00% 1 / 1 1
 add 100.00% 3 / 3 100.00% 1 / 1 1
 remove 100.00% 2 / 2 100.00% 1 / 1 1
 findMatching 100.00% 6 / 6 100.00% 1 / 1 4
 matchFilters 100.00% 5 / 5 100.00% 1 / 1 3
1<?php
2
3declare(strict_types=1);
4
5namespace Stewart\Runtime\Dispatch;
6
7use Stewart\Contracts\Entity\EntityId;
8use Stewart\Contracts\Registry\EntityFilter;
9use Stewart\Runtime\Model\Collection\SubscriptionIdCollection;
10use Stewart\Runtime\Model\SubscriptionId;
11use Stewart\Runtime\Registry\RegistryCache;
12
13final class EntityFilterIndex
14{
15    private const int CACHE_LIMIT = 10_000;
16
17    /** @var array<string, EntityFilter> */
18    private array $filters = [];
19
20    /** @var array<string, SubscriptionId> */
21    private array $subscriptionIds = [];
22
23    /** @var array<string, SubscriptionIdCollection> */
24    private array $cache = [];
25
26    private int $cachedRevision = 0;
27
28    public function __construct(private readonly RegistryCache $registry) {}
29
30    public function add(SubscriptionId $subscriptionId, EntityFilter $filter): void
31    {
32        $this->filters[$subscriptionId->value] = $filter;
33        $this->subscriptionIds[$subscriptionId->value] = $subscriptionId;
34        $this->cache = [];
35    }
36
37    public function remove(SubscriptionId $subscriptionId): void
38    {
39        unset($this->filters[$subscriptionId->value], $this->subscriptionIds[$subscriptionId->value]);
40        $this->cache = [];
41    }
42
43    public function findMatching(EntityId $entityId): SubscriptionIdCollection
44    {
45        if ($this->filters === []) {
46            return SubscriptionIdCollection::empty();
47        }
48
49        if ($this->cachedRevision !== $this->registry->getRevision() || \count($this->cache) >= self::CACHE_LIMIT) {
50            $this->cache = [];
51            $this->cachedRevision = $this->registry->getRevision();
52        }
53
54        return $this->cache[$entityId->value] ??= $this->matchFilters($entityId);
55    }
56
57    private function matchFilters(EntityId $entityId): SubscriptionIdCollection
58    {
59        $matched = [];
60
61        foreach ($this->filters as $key => $filter) {
62            if ($filter->matchesEntity($entityId, $this->registry)) {
63                $matched[] = $this->subscriptionIds[$key];
64            }
65        }
66
67        return SubscriptionIdCollection::fromList($matched);
68    }
69}