Completed
Pull Request — master (#92)
by Samuel
06:09
created

RequestListener   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 163
Duplicated Lines 4.91 %

Coupling/Cohesion

Components 1
Dependencies 8

Test Coverage

Coverage 84.13%

Importance

Changes 5
Bugs 0 Features 0
Metric Value
wmc 14
c 5
b 0
f 0
lcom 1
cbo 8
dl 8
loc 163
ccs 53
cts 63
cp 0.8413
rs 10

5 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A onKernelRequest() 8 16 4
B handleIronMqNotifications() 0 28 2
A handleSnsNotifications() 0 54 2
B getIronMqQueueName() 0 17 5

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
3
/**
4
 * Copyright 2014 Underground Elephant
5
 *
6
 * Licensed under the Apache License, Version 2.0 (the "License");
7
 * you may not use this file except in compliance with the License.
8
 * You may obtain a copy of the License at
9
 *
10
 *     http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing, software
13
 * distributed under the License is distributed on an "AS IS" BASIS,
14
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
 * See the License for the specific language governing permissions and
16
 * limitations under the License.
17
 *
18
 * @package     qpush-bundle
19
 * @copyright   Underground Elephant 2014
20
 * @license     Apache License, Version 2.0
21
 */
22
23
namespace Uecode\Bundle\QPushBundle\EventListener;
24
25
use Psr\Log\LoggerInterface;
26
use Symfony\Component\HttpKernel\HttpKernel;
27
use Symfony\Component\HttpFoundation\Response;
28
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
29
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
30
use Uecode\Bundle\QPushBundle\Message\Notification;
31
use Uecode\Bundle\QPushBundle\Event\Events;
32
use Uecode\Bundle\QPushBundle\Event\NotificationEvent;
33
34
/**
35
 * @author Keith Kirk <[email protected]>
36
 */
37
class RequestListener
38
{
39
    /**
40
     * Symfony Event Dispatcher
41
     *
42
     * @var EventDispatcherInterface
43
     */
44
    private $dispatcher;
45
46
    /**
47
     * Constructor.
48
     *
49
     * @param EventDispatcherInterface $dispatcher A Symfony Event Dispatcher
50
     */
51 4
    public function __construct(EventDispatcherInterface $dispatcher)
52
    {
53 4
        $this->dispatcher = $dispatcher;
54 4
    }
55
56
    /**
57
     * Kernel Request Event Handler for QPush Notifications
58
     *
59
     * @param GetResponseEvent $event The Kernel Request's GetResponseEvent
60
     */
61 4
    public function onKernelRequest(GetResponseEvent $event)
62
    {
63 4
        if (HttpKernel::MASTER_REQUEST != $event->getRequestType()) {
64 1
            return;
65
        }
66
67 3 View Code Duplication
        if ($event->getRequest()->headers->has('x-amz-sns-message-type')) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
68 2
            $result = $this->handleSnsNotifications($event);
69 2
            $event->setResponse(new Response($result, 200));
70
        }
71
72 3 View Code Duplication
        if ($event->getRequest()->headers->has('iron-message-id')) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
73 1
            $result = $this->handleIronMqNotifications($event);
74
            $event->setResponse(new Response($result, 200));
75
        }
76 2
    }
77
78
    /**
79
     * Handles Messages sent from a IronMQ Push Queue
80
     *
81
     * @param GetResponseEvent $event The Kernel Request's GetResponseEvent
82
     * @return string|void
83
     */
84 1
    private function handleIronMqNotifications(GetResponseEvent $event)
85
    {
86 1
        $headers    = $event->getRequest()->headers;
87 1
        $messageId  = $headers->get('iron-message-id');
88
89 1
        if (null === ($message = json_decode($event->getRequest()->getContent(), true))) {
90
            throw new \InvalidArgumentException('Unable to decode JSON');
91
        }
92
93 1
        $queue = $this->getIronMqQueueName($event, $message);
94
        $metadata = [
95 1
            'iron-subscriber-message-id'  => $headers->get('iron-subscriber-message-id'),
96 1
            'iron-subscriber-message-url' => $headers->get('iron-subscriber-message-url')
97
        ];
98
99 1
        $notification = new Notification(
100
            $messageId,
0 ignored issues
show
Bug introduced by
It seems like $messageId defined by $headers->get('iron-message-id') on line 87 can also be of type array; however, Uecode\Bundle\QPushBundl...fication::__construct() does only seem to accept integer|string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
101
            $message,
102
            $metadata
103
        );
104
105 1
        $this->dispatcher->dispatch(
106 1
            Events::Notification($queue),
107 1
            new NotificationEvent($queue, NotificationEvent::TYPE_MESSAGE, $notification)
108
        );
109
110
        return "IronMQ Notification Received.";
111
    }
112
113
    /**
114
     * Handles Notifications sent from AWS SNS
115
     *
116
     * @param GetResponseEvent $event The Kernel Request's GetResponseEvent
117
     * @return string
118
     */
119 2
    private function handleSnsNotifications(GetResponseEvent $event)
120
    {
121 2
        $notification = json_decode((string)$event->getRequest()->getContent(), true);
122
123 2
        $type = $event->getRequest()->headers->get('x-amz-sns-message-type');
124
125
        $metadata = [
126 2
            'Type'      => $notification['Type'],
127 2
            'TopicArn'  => $notification['TopicArn'],
128 2
            'Timestamp' => $notification['Timestamp'],
129
        ];
130
131 2
        if ($type === 'Notification') {
132
133
            // We put the queue name in the Subject field
134 1
            $queue                  = $notification['Subject'];
135 1
            $metadata['Subject']    = $queue;
136
137 1
            $notification           = new Notification(
138 1
                $notification['MessageId'],
139 1
                $notification['Message'],
140
                $metadata
141
            );
142
143 1
            $this->dispatcher->dispatch(
144 1
                Events::Notification($queue),
145 1
                new NotificationEvent($queue, NotificationEvent::TYPE_MESSAGE, $notification)
146
            );
147
148 1
            return "SNS Message Notification Received.";
149
        }
150
151
        // For subscription notifications, we need to parse the Queue from
152
        // the Topic ARN
153 1
        $arnParts           = explode(':', $notification['TopicArn']);
154 1
        $last               = end($arnParts);
155 1
        $queue              = str_replace('qpush_', '', $last);
156
157
        // Get the token for the Subscription Confirmation
158 1
        $metadata['Token']  = $notification['Token'];
159
160 1
        $notification = new Notification(
161 1
            $notification['MessageId'],
162 1
            $notification['Message'],
163
            $metadata
164
        );
165
166 1
        $this->dispatcher->dispatch(
167 1
            Events::Notification($queue),
168 1
            new NotificationEvent($queue, NotificationEvent::TYPE_SUBSCRIPTION, $notification)
169
        );
170
171 1
        return "SNS Subscription Confirmation Received.";
172
    }
173
174
    /**
175
     * Get the name of the IronMq queue.
176
     *
177
     * @param GetResponseEvent $event
178
     * @param array $message
179
     *
180
     * @return string
181
     */
182 1
    private function getIronMqQueueName(GetResponseEvent $event, array &$message)
183
    {
184 1
        if (array_key_exists('_qpush_queue', $message)) {
185 1
            return $message['_qpush_queue'];
186
        } else if (null !== ($subscriberUrl = $event->getRequest()->headers->get('iron-subscriber-message-url'))) {
187
            if (preg_match('#/queues/([a-z0-9_-]+)/messages/#i', $subscriberUrl, $matches)) {
188
                $queue = $matches[1];
189
                if (substr($queue, 0, 6) == 'qpush_') {
190
                    $queue = substr($queue, 6);
191
                }
192
193
                return $queue;
194
            }
195
        }
196
197
        throw new \RuntimeException('Unable to get queue name');
198
    }
199
}
200