Channel::verify()   A
last analyzed

Complexity

Conditions 4
Paths 4

Size

Total Lines 23
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 18
CRAP Score 4

Importance

Changes 0
Metric Value
eloc 17
c 0
b 0
f 0
dl 0
loc 23
ccs 18
cts 18
cp 1
rs 9.7
cc 4
nc 4
nop 1
crap 4
1
<?php declare(strict_types=1);
2
/**
3
 * This file is part of the daikon-cqrs/message-bus project.
4
 *
5
 * For the full copyright and license information, please view the LICENSE
6
 * file that was distributed with this source code.
7
 */
8
9
namespace Daikon\MessageBus\Channel;
10
11
use Closure;
12
use Daikon\MessageBus\EnvelopeInterface;
13
use Daikon\MessageBus\MessageBusInterface;
14
use Daikon\MessageBus\Channel\Subscription\SubscriptionInterface;
15
use Daikon\MessageBus\Channel\Subscription\SubscriptionMap;
16
use Daikon\MessageBus\Exception\EnvelopeNotAcceptable;
17
use Daikon\MessageBus\Exception\SubscriptionUnknown;
18
use Daikon\Metadata\MetadataInterface;
19
use Daikon\Metadata\MetadataEnricherInterface;
20
use Daikon\Metadata\MetadataEnricherList;
21
22
final class Channel implements ChannelInterface
23
{
24
    private string $key;
25
26
    private SubscriptionMap $subscriptions;
27
28
    private Closure $guard;
29
30
    private MetadataEnricherList $metadataEnrichers;
31
32 9
    public function __construct(
33
        string $key,
34
        SubscriptionMap $subscriptions,
35
        Closure $guard = null,
36
        MetadataEnricherList $metadataEnrichers = null
37
    ) {
38 9
        $this->key = $key;
39 9
        $this->subscriptions = $subscriptions;
40 9
        $this->guard = $guard ?? fn(): bool => true;
41 9
        $metadataEnrichers = $metadataEnrichers ?? new MetadataEnricherList;
42 9
        $this->metadataEnrichers = $metadataEnrichers->enrichWith(self::METADATA_KEY, $this->key);
43 9
    }
44
45 3
    public function publish(EnvelopeInterface $envelope, MessageBusInterface $messageBus): void
46
    {
47 3
        $envelope = $this->enrichMetadata($envelope);
48 3
        if ($this->accepts($envelope)) {
49 2
            foreach ($this->subscriptions as $subscription) {
50 2
                $subscription->publish($envelope, $messageBus);
51
            }
52
        }
53 3
    }
54
55 5
    public function receive(EnvelopeInterface $envelope): void
56
    {
57 5
        $this->verify($envelope);
58 2
        $subscriptionKey = (string)$envelope->getMetadata()->get(SubscriptionInterface::METADATA_KEY);
59 2
        if (!$this->subscriptions->has($subscriptionKey)) {
60 1
            throw new SubscriptionUnknown(
61 1
                "Channel '{$this->key}' has no subscription '$subscriptionKey' and thus ".
62 1
                "Envelope '{$envelope->getUuid()->toString()}' cannot be handled."
63
            );
64
        }
65
        /** @var SubscriptionInterface $subscription */
66 1
        $subscription = $this->subscriptions->get($subscriptionKey);
67 1
        $subscription->receive($envelope);
68 1
    }
69
70 1
    public function getKey(): string
71
    {
72 1
        return $this->key;
73
    }
74
75 3
    private function enrichMetadata(EnvelopeInterface $envelope): EnvelopeInterface
76
    {
77 3
        return $envelope->withMetadata(array_reduce(
78 3
            $this->metadataEnrichers->unwrap(),
79 3
            function (MetadataInterface $metadata, MetadataEnricherInterface $metadataEnricher): MetadataInterface {
80 3
                return $metadataEnricher->enrich($metadata);
81 3
            },
82 3
            $envelope->getMetadata()
83
        ));
84
    }
85
86 3
    private function accepts(EnvelopeInterface $envelope): bool
87
    {
88 3
        return (bool)($this->guard)($envelope);
89
    }
90
91 5
    private function verify(EnvelopeInterface $envelope): void
92
    {
93 5
        $metadata = $envelope->getMetadata();
94 5
        if (!$metadata->has(self::METADATA_KEY)) {
95 1
            throw new EnvelopeNotAcceptable(
96 1
                "Channel key '".self::METADATA_KEY."' missing in metadata of Envelope ".
97 1
                "'{$envelope->getUuid()->toString()}' received on channel '{$this->key}'.",
98 1
                EnvelopeNotAcceptable::CHANNEL_KEY_MISSING
99
            );
100
        }
101 4
        $channelKey = $metadata->get(self::METADATA_KEY);
102 4
        if ($channelKey !== $this->key) {
103 1
            throw new EnvelopeNotAcceptable(
104 1
                "Channel '{$this->key}' inadvertently received Envelope ".
105 1
                "'{$envelope->getUuid()->toString()}' for channel '$channelKey'.",
106 1
                EnvelopeNotAcceptable::CHANNEL_KEY_UNEXPECTED
107
            );
108
        }
109 3
        if (!$metadata->has(SubscriptionInterface::METADATA_KEY)) {
110 1
            throw new EnvelopeNotAcceptable(
111 1
                "Subscription key '".SubscriptionInterface::METADATA_KEY."' missing in metadata of ".
112 1
                "Envelope '{$envelope->getUuid()->toString()}' received on channel '{$this->key}'.",
113 1
                EnvelopeNotAcceptable::SUBSCRIPTION_KEY_MISSING
114
            );
115
        }
116 2
    }
117
}
118