Passed
Pull Request — master (#17)
by BENOIT
01:49
created

PHPStorage   A

Complexity

Total Complexity 27

Size/Duplication

Total Lines 101
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 42
c 2
b 0
f 0
dl 0
loc 101
rs 10
ccs 31
cts 31
cp 1
wmc 27

9 Methods

Rating   Name   Duplication   Size   Complexity  
A storeMessage() 0 13 3
A storeSubscriptions() 0 7 2
A __construct() 0 3 1
A retrieveMessagesAfterId() 0 7 2
A removeSubscriptions() 0 12 4
A getMessagesAfterId() 0 12 5
A findSubscriptions() 0 3 1
A getAllMessages() 0 7 3
A filterSubscriptions() 0 7 6
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
24 5
    public function __construct(int $size)
25 5
    {
26
        $this->messagesMaxSize = $size;
27 1
    }
28
29 1
    public function retrieveMessagesAfterId(string $id, array $subscribedTopics): PromiseInterface
30 1
    {
31
        if (self::EARLIEST === $id) {
32
            return resolve($this->getAllMessages($subscribedTopics));
33 1
        }
34
35
        return resolve($this->getMessagesAfterId($id, $subscribedTopics));
36 4
    }
37
38 4
    public function storeMessage(string $topic, Message $message): PromiseInterface
39 1
    {
40
        if (0 === $this->messagesMaxSize) {
41
            return resolve(true);
42 3
        }
43 1
44
        if ($this->currentMessagesSize >= $this->messagesMaxSize) {
45 3
            \array_shift($this->messages);
46 3
        }
47
        $this->messages[] = [$topic, $message];
48 3
        $this->currentMessagesSize++;
49
50
        return resolve(true);
51 1
    }
52
53 1
    public function storeSubscriptions(array $subscriptions): PromiseInterface
54 1
    {
55 1
        foreach ($subscriptions as $subscription) {
56 1
            $this->subscriptions[] = $subscription;
57 1
        }
58
59 1
        return resolve();
60 1
    }
61
62 1
    public function removeSubscriptions(iterable $subscriptions): PromiseInterface
63
    {
64 1
        $subscriptions = \iterable_to_array($subscriptions);
65
        foreach ($subscriptions as $subscription) {
66 1
            foreach ($this->subscriptions as $key => $_subscription) {
67
                if ($_subscription->getId() === $subscription->getId()) {
68 1
                    unset($this->subscriptions[$key]);
69 1
                }
70 1
            }
71
        }
72 1
73
        return resolve();
74 1
    }
75
76
    public function findSubscriptions(?string $subscriber = null, ?string $topic = null): PromiseInterface
77
    {
78
        return resolve($this->filterSubscriptions($subscriber, $topic));
79
    }
80
81
    private function filterSubscriptions(?string $subscriber, ?string $topic): iterable
82
    {
83
        foreach ($this->subscriptions as $subscription) {
84
            $matchSubscriber = (null === $subscriber || $subscription->getSubscriber() === $subscriber);
85
            $matchTopic = (null === $topic || TopicMatcher::matchesTopicSelectors($subscription->getTopic(), [$topic]));
86
            if ($matchSubscriber && $matchTopic) {
87
                yield $subscription;
88
            }
89
        }
90
    }
91
92
    private function getMessagesAfterId(string $id, array $subscribedTopics): iterable
93
    {
94
        $ignore = true;
95
        foreach ($this->messages as [$topic, $message]) {
96
            if ($message->getId() === $id) {
97
                $ignore = false;
98
                continue;
99
            }
100
            if ($ignore || !TopicMatcher::matchesTopicSelectors($topic, $subscribedTopics)) {
101
                continue;
102
            }
103
            yield $topic => $message;
104
        }
105
    }
106
107
    private function getAllMessages(array $subscribedTopics): iterable
108
    {
109
        foreach ($this->messages as [$topic, $message]) {
110
            if (!TopicMatcher::matchesTopicSelectors($topic, $subscribedTopics)) {
111
                continue;
112
            }
113
            yield $topic => $message;
114
        }
115
    }
116
}
117