Passed
Pull Request — master (#17)
by BENOIT
02:04
created

PHPStorage::retrieveMessagesAfterID()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 2
nop 2
dl 0
loc 7
rs 10
c 0
b 0
f 0
ccs 3
cts 3
cp 1
crap 2
1
<?php
2
3
namespace BenTools\MercurePHP\Storage\PHP;
4
5
use BenTools\MercurePHP\Model\Message;
6
use BenTools\MercurePHP\Model\Subscription;
7
use BenTools\MercurePHP\Security\TopicMatcher;
8
use BenTools\MercurePHP\Storage\StorageInterface;
9
use React\Promise\PromiseInterface;
10
11
use function React\Promise\resolve;
12
13
final class PHPStorage implements StorageInterface
14
{
15
    private int $messagesMaxSize;
16
    private int $currentMessagesSize = 0;
17
    private array $messages = [];
18
19
    /**
20
     * @var Subscription[]
21
     */
22 5
    private array $subscriptions = [];
23
    private ?string $lastEventID = null;
24 5
25 5
    public function __construct(int $size)
26
    {
27 1
        $this->messagesMaxSize = $size;
28
    }
29 1
30 1
    public function getLastEventID(): PromiseInterface
31
    {
32
        return resolve($this->lastEventID);
33 1
    }
34
35
    public function retrieveMessagesAfterID(string $id, array $subscribedTopics): PromiseInterface
36 4
    {
37
        if (self::EARLIEST === $id) {
38 4
            return resolve($this->getAllMessages($subscribedTopics));
39 1
        }
40
41
        return resolve($this->getMessagesAfterId($id, $subscribedTopics));
42 3
    }
43 1
44
    public function storeMessage(string $topic, Message $message): PromiseInterface
45 3
    {
46 3
        if (0 === $this->messagesMaxSize) {
47
            return resolve(true);
48 3
        }
49
50
        if ($this->currentMessagesSize >= $this->messagesMaxSize) {
51 1
            \array_shift($this->messages);
52
        }
53 1
        $this->messages[] = [$topic, $message];
54 1
        $this->currentMessagesSize++;
55 1
        $this->lastEventID = $message->getId();
56 1
57 1
        return resolve(true);
58
    }
59 1
60 1
    public function storeSubscriptions(array $subscriptions): PromiseInterface
61
    {
62 1
        foreach ($subscriptions as $subscription) {
63
            $this->subscriptions[] = $subscription;
64 1
        }
65
66 1
        return resolve();
67
    }
68 1
69 1
    public function removeSubscriptions(iterable $subscriptions): PromiseInterface
70 1
    {
71
        $subscriptions = \iterable_to_array($subscriptions);
72 1
        foreach ($subscriptions as $subscription) {
73
            foreach ($this->subscriptions as $key => $_subscription) {
74 1
                if ($_subscription->getId() === $subscription->getId()) {
75
                    unset($this->subscriptions[$key]);
76
                }
77
            }
78
        }
79
80
        return resolve();
81
    }
82
83
    public function findSubscriptions(?string $topic = null, ?string $subscriber = null): PromiseInterface
84
    {
85
        return resolve($this->filterSubscriptions($topic, $subscriber));
86
    }
87
88
    private function filterSubscriptions(?string $topic, ?string $subscriber): iterable
89
    {
90
        foreach ($this->subscriptions as $subscription) {
91
            $matchSubscriberPattern = TopicMatcher::matchesTopicSelectors(
92
                $subscription->getSubscriber(),
93
                [$subscriber ?? '{subscriber}']
94
            );
95
            $matchSubscriber = (null === $subscriber || $matchSubscriberPattern);
96
            $matchTopicPattern = TopicMatcher::matchesTopicSelectors(
97
                $subscription->getTopic(),
98
                [$topic ?? '{topic}']
99
            );
100
            $matchTopic = (null === $topic || $matchTopicPattern);
101
            if ($matchSubscriber && $matchTopic) {
102
                yield $subscription;
103
            }
104
        }
105
    }
106
107
    private function getMessagesAfterId(string $id, array $subscribedTopics): iterable
108
    {
109
        $ignore = true;
110
        foreach ($this->messages as [$topic, $message]) {
111
            if ($message->getId() === $id) {
112
                $ignore = false;
113
                continue;
114
            }
115
            if ($ignore || !TopicMatcher::matchesTopicSelectors($topic, $subscribedTopics)) {
116
                continue;
117
            }
118
            yield $topic => $message;
119
        }
120
    }
121
122
    private function getAllMessages(array $subscribedTopics): iterable
123
    {
124
        foreach ($this->messages as [$topic, $message]) {
125
            if (!TopicMatcher::matchesTopicSelectors($topic, $subscribedTopics)) {
126
                continue;
127
            }
128
            yield $topic => $message;
129
        }
130
    }
131
}
132