Passed
Pull Request — master (#17)
by BENOIT
01:48
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
            $matchSubscriber = (null === $subscriber || $subscription->getSubscriber() === $subscriber);
92
            $matchTopic = (null === $topic || TopicMatcher::matchesTopicSelectors($subscription->getTopic(), [$topic]));
93
            if ($matchSubscriber && $matchTopic) {
94
                yield $subscription;
95
            }
96
        }
97
    }
98
99
    private function getMessagesAfterId(string $id, array $subscribedTopics): iterable
100
    {
101
        $ignore = true;
102
        foreach ($this->messages as [$topic, $message]) {
103
            if ($message->getId() === $id) {
104
                $ignore = false;
105
                continue;
106
            }
107
            if ($ignore || !TopicMatcher::matchesTopicSelectors($topic, $subscribedTopics)) {
108
                continue;
109
            }
110
            yield $topic => $message;
111
        }
112
    }
113
114
    private function getAllMessages(array $subscribedTopics): iterable
115
    {
116
        foreach ($this->messages as [$topic, $message]) {
117
            if (!TopicMatcher::matchesTopicSelectors($topic, $subscribedTopics)) {
118
                continue;
119
            }
120
            yield $topic => $message;
121
        }
122
    }
123
}
124