DefaultSender   A
last analyzed

Complexity

Total Complexity 18

Size/Duplication

Total Lines 208
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 10

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 18
lcom 1
cbo 10
dl 0
loc 208
ccs 81
cts 81
cp 1
rs 10
c 0
b 0
f 0

4 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 2
A addChannel() 0 10 1
A addMessage() 0 21 3
C send() 0 118 12
1
<?php
2
3
namespace Yokai\MessengerBundle\Sender;
4
5
use Psr\Log\LoggerInterface;
6
use Psr\Log\NullLogger;
7
use SplPriorityQueue;
8
use Symfony\Component\OptionsResolver\Exception\ExceptionInterface as OptionsResolverException;
9
use Symfony\Component\OptionsResolver\OptionsResolver;
10
use Yokai\MessengerBundle\Channel\ChannelInterface;
11
use Yokai\MessengerBundle\Delivery;
12
use Yokai\MessengerBundle\Exception\BadConfigurationException;
13
use Yokai\MessengerBundle\Exception\BadMethodCallException;
14
use Yokai\MessengerBundle\Exception\ChannelHandleException;
15
use Yokai\MessengerBundle\Exception\ExceptionInterface;
16
use Yokai\MessengerBundle\Helper\ContentBuilder;
17
use Yokai\MessengerBundle\Message;
18
19
/**
20
 * @author Yann Eugoné <[email protected]>
21
 */
22
class DefaultSender implements SenderInterface
23
{
24
    /**
25
     * @var ContentBuilder
26
     */
27
    private $contentBuilder;
28
29
    /**
30
     * @var bool
31
     */
32
    private $debug;
33
34
    /**
35
     * @var LoggerInterface
36
     */
37
    private $logger;
38
39
    /**
40
     * @var array
41
     */
42
    private $channels;
43
44
    /**
45
     * @var array
46
     */
47
    private $channelNames;
48
49
    /**
50
     * @var array
51
     */
52
    private $messages;
53
54
    /**
55
     * @param ContentBuilder  $contentBuilder
56
     * @param bool            $debug
57
     * @param LoggerInterface $logger
58
     */
59 14
    public function __construct(ContentBuilder $contentBuilder, $debug, LoggerInterface $logger = null)
60
    {
61 14
        $this->contentBuilder = $contentBuilder;
62 14
        $this->debug = $debug;
63 14
        $this->logger = $logger ?: new NullLogger();
64 14
    }
65
66
    /**
67
     * @param ChannelInterface $channel
68
     * @param string           $name
69
     * @param int              $priority
70
     */
71 14
    public function addChannel(ChannelInterface $channel, $name, $priority)
72
    {
73 14
        $oid = spl_object_hash($channel);
74
75 14
        $this->channels[$name] = [
76 14
            'object' => $channel,
77 14
            'priority' => $priority,
78
        ];
79 14
        $this->channelNames[$oid] = $name;
80 14
    }
81
82
    /**
83
     * @param Message $message
84
     * @param string  $channel
85
     */
86 14
    public function addMessage(Message $message, $channel)
87
    {
88
        //Check the channel was previously registered
89 14
        if (!isset($this->channels[$channel])) {
90 1
            throw BadMethodCallException::createMissingChannel($channel);
91
        }
92
93 13
        if (!isset($this->messages[$message->getId()])) {
94
            //Initialize the message by ID hash
95 13
            $this->messages[$message->getId()] = [
96 13
                'object' => $message,
97 13
                'channels' => new SplPriorityQueue(),
98
            ];
99
        }
100
101
        //Insert the channel in the prioritized queue
102 13
        $this->messages[$message->getId()]['channels']->insert(
103 13
            $this->channels[$channel]['object'],
104 13
            $this->channels[$channel]['priority']
105
        );
106 13
    }
107
108
    /**
109
     * @inheritdoc
110
     */
111 13
    public function send($message, $recipient, array $parameters = [], array $attachments = [])
112
    {
113
        //Check that the message is registered
114 13
        if (!isset($this->messages[$message])) {
115 1
            throw BadMethodCallException::createMissingMessage($message);
116
        }
117
118
        //Retrieve sorted channels for this message
119 12
        $channels = iterator_to_array(clone $this->messages[$message]['channels']);
120
        /* @var $channels ChannelInterface[] */
121
122
        //Retrieve message object
123 12
        $message = $this->messages[$message]['object'];
124
        /* @var $message Message */
125
126
        try {
127
128
            //Iterate over message channels and trigger process
129 12
            foreach ($channels as $channel) {
130 12
                $oid = spl_object_hash($channel);
131
132 12
                if (!$channel->supports($recipient)) {
133 2
                    if ($this->debug) {
134 1
                        throw ChannelHandleException::unsupportedRecipient($channel, $message, $recipient);
135
                    }
136
137 1
                    $this->logger->error(
138 1
                        'The recipient is not supported by channel.',
139
                        [
140 1
                            'channel' => $this->channelNames[$oid],
141 1
                            'message' => $message->getId(),
142 1
                            'parameters' => $parameters,
143
                        ]
144
                    );
145
146 1
                    continue;
147
                }
148
149
                //Fetch options of the message for the channel
150 10
                $options = $message->getOptions(
151 10
                    $this->channelNames[$oid]
152
                );
153
154
                try {
155
                    //Configure the content builder with message options for this channel
156 10
                    $this->contentBuilder->configure($options);
157 2
                } catch (OptionsResolverException $exception) {
158 2
                    throw BadConfigurationException::create($exception);
159
                }
160
161 8
                $resolver = new OptionsResolver();
162 8
                $channel->configure($resolver);
163
164
                try {
165
                    //Resolve options of the message for this channel
166 6
                    $options = $resolver->resolve(
167 6
                        array_intersect_key(
168 6
                            $options,
169 6
                            array_flip($resolver->getDefinedOptions())
170
                        )
171
                    );
172 2
                } catch (OptionsResolverException $exception) {
173 2
                    throw BadConfigurationException::create($exception);
174
                }
175
176
                //Create a delivery object that contains all information about the message to send
177 4
                $delivery = new Delivery(
178 4
                    $message->getId(), //Message identifier
179 4
                    $recipient, //Message recipient
180 4
                    $options, //Options for this channel
181 4
                    $this->contentBuilder->getSubject($parameters), //Message subject
182 4
                    $this->contentBuilder->getBody($parameters), //Message body
183 4
                    $parameters, //Provided parameters
184 4
                    $attachments //Provided attachments
185
                );
186
187
                try {
188
                    //Handle message delivery for this channel
189 4
                    $channel->handle($delivery);
190 2
                } catch (\Exception $exception) {
191 5
                    throw ChannelHandleException::createOnException($channel, $delivery, $exception);
192
                }
193
            }
194
195 9
        } catch (ExceptionInterface $exception) {
196
197 7
            $this->logger->error(
198 7
                $exception->getMessage(),
199
                [
200 7
                    'message' => $message->getId(),
201 7
                    'parameters' => $parameters,
202
                ]
203
            );
204
205 7
            if ($this->debug) {
206 7
                throw $exception;
207
            }
208
209 2
        } catch (\Exception $exception) {
210
211 2
            $this->logger->critical(
212 2
                sprintf(
213 2
                    'An error has occurred during the notification process. Exception : %s - %s',
214 2
                    get_class($exception),
215 2
                    $exception->getMessage()
216
                ),
217
                [
218 2
                    'message' => $message->getId(),
219 2
                    'parameters' => $parameters,
220
                ]
221
            );
222
223 2
            if ($this->debug) {
224 1
                throw $exception;
225
            }
226
227
        }
228 7
    }
229
}
230