RequestListener   A
last analyzed

Complexity

Total Complexity 14

Size/Duplication

Total Lines 159
Duplicated Lines 5.03 %

Coupling/Cohesion

Components 1
Dependencies 8

Test Coverage

Coverage 88.41%

Importance

Changes 0
Metric Value
wmc 14
lcom 1
cbo 8
dl 8
loc 159
ccs 61
cts 69
cp 0.8841
rs 10
c 0
b 0
f 0

5 Methods

Rating   Name   Duplication   Size   Complexity  
A onKernelRequest() 8 15 4
B getIronMqQueueName() 0 16 5
B handleIronMqNotifications() 0 29 2
A __construct() 0 3 1
A handleSnsNotifications() 0 53 2

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 Symfony\Component\EventDispatcher\EventDispatcherInterface;
26
use Symfony\Component\HttpFoundation\Response;
27
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
28
use Symfony\Component\HttpKernel\HttpKernel;
29
use Uecode\Bundle\QPushBundle\Event\Events;
30
use Uecode\Bundle\QPushBundle\Event\NotificationEvent;
31
use Uecode\Bundle\QPushBundle\Message\Notification;
32
33
/**
34
 * @author Keith Kirk <[email protected]>
35
 */
36
37
class RequestListener {
38
	/**
39
	 * Symfony Event Dispatcher
40
	 *
41
	 * @var EventDispatcherInterface
42
	 */
43
	private $dispatcher;
44
45
	/**
46
	 * Constructor.
47
	 *
48
	 * @param EventDispatcherInterface $dispatcher A Symfony Event Dispatcher
49
	 */
50 4
	public function __construct(EventDispatcherInterface $dispatcher) {
51 4
		$this->dispatcher = $dispatcher;
52 4
	}
53
54
	/**
55
	 * Kernel Request Event Handler for QPush Notifications
56
	 *
57
	 * @param GetResponseEvent $event The Kernel Request's GetResponseEvent
58
	 */
59 4
	public function onKernelRequest(GetResponseEvent $event) {
60 4
		if (HttpKernel::MASTER_REQUEST != $event->getRequestType()) {
61 1
			return;
62
		}
63
64 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...
65 2
			$result = $this->handleSnsNotifications($event);
66 2
			$event->setResponse(new Response($result, 200));
67
		}
68
69 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...
70 1
			$result = $this->handleIronMqNotifications($event);
71 1
			$event->setResponse(new Response($result, 200));
72
		}
73 3
	}
74
75
	/**
76
	 * Handles Messages sent from a IronMQ Push Queue
77
	 *
78
	 * @param GetResponseEvent $event The Kernel Request's GetResponseEvent
79
	 * @return string|void
80
	 */
81 1
	private function handleIronMqNotifications(GetResponseEvent $event) {
82 1
		$headers   = $event->getRequest()->headers;
83 1
		$messageId = $headers->get('iron-message-id');
84
85 1
		if (null === ($message = json_decode($event->getRequest()->getContent(), true))) {
86
			throw new \InvalidArgumentException('Unable to decode JSON');
87
		}
88
89 1
		$queue    = $this->getIronMqQueueName($event, $message);
90
		$metadata = [
91 1
			'iron-subscriber-message-id'  => $headers->get('iron-subscriber-message-id'),
92 1
			'iron-subscriber-message-url' => $headers->get('iron-subscriber-message-url')
93
		];
94
95 1
		unset($message['_qpush_queue']);
96
97 1
		$notification = new Notification(
98 1
			$messageId,
0 ignored issues
show
Bug introduced by
It seems like $messageId defined by $headers->get('iron-message-id') on line 83 can also be of type array<integer,string>; 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...
99 1
			$message,
100 1
			$metadata
101
		);
102
103 1
		$this->dispatcher->dispatch(
104 1
			Events::Notification($queue),
105 1
			new NotificationEvent($queue, NotificationEvent::TYPE_MESSAGE, $notification)
106
		);
107
108 1
		return "IronMQ Notification Received.";
109
	}
110
111
	/**
112
	 * Handles Notifications sent from AWS SNS
113
	 *
114
	 * @param GetResponseEvent $event The Kernel Request's GetResponseEvent
115
	 * @return string
116
	 */
117 2
	private function handleSnsNotifications(GetResponseEvent $event) {
118 2
		$notification = json_decode((string) $event->getRequest()->getContent(), true);
119
120 2
		$type = $event->getRequest()->headers->get('x-amz-sns-message-type');
121
122
		$metadata = [
123 2
			'Type'      => $notification['Type'],
124 2
			'TopicArn'  => $notification['TopicArn'],
125 2
			'Timestamp' => $notification['Timestamp'],
126
		];
127
128 2
		if ($type === 'Notification') {
129
130
			// We put the queue name in the Subject field
131 1
			$queue               = $notification['Subject'];
132 1
			$metadata['Subject'] = $queue;
133
134 1
			$notification = new Notification(
135 1
				$notification['MessageId'],
136 1
				$notification['Message'],
137 1
				$metadata
138
			);
139
140 1
			$this->dispatcher->dispatch(
141 1
				Events::Notification($queue),
142 1
				new NotificationEvent($queue, NotificationEvent::TYPE_MESSAGE, $notification)
143
			);
144
145 1
			return "SNS Message Notification Received.";
146
		}
147
148
		// For subscription notifications, we need to parse the Queue from
149
		// the Topic ARN
150 1
		$arnParts = explode(':', $notification['TopicArn']);
151 1
		$last     = end($arnParts);
152 1
		$queue    = str_replace('qpush_', '', $last);
153
154
		// Get the token for the Subscription Confirmation
155 1
		$metadata['Token'] = $notification['Token'];
156
157 1
		$notification = new Notification(
158 1
			$notification['MessageId'],
159 1
			$notification['Message'],
160 1
			$metadata
161
		);
162
163 1
		$this->dispatcher->dispatch(
164 1
			Events::Notification($queue),
165 1
			new NotificationEvent($queue, NotificationEvent::TYPE_SUBSCRIPTION, $notification)
166
		);
167
168 1
		return "SNS Subscription Confirmation Received.";
169
	}
170
171
	/**
172
	 * Get the name of the IronMq queue.
173
	 *
174
	 * @param GetResponseEvent $event
175
	 * @param array $message
176
	 *
177
	 * @return string
178
	 */
179 1
	private function getIronMqQueueName(GetResponseEvent $event, array&$message) {
180 1
		if (array_key_exists('_qpush_queue', $message)) {
181 1
			return $message['_qpush_queue'];
182
		} else if (null !== ($subscriberUrl = $event->getRequest()->headers->get('iron-subscriber-message-url'))) {
183
			if (preg_match('#/queues/([a-z0-9_-]+)/messages/#i', $subscriberUrl, $matches)) {
184
				$queue = $matches[1];
185
				if (substr($queue, 0, 6) == 'qpush_') {
186
					$queue = substr($queue, 6);
187
				}
188
189
				return $queue;
190
			}
191
		}
192
193
		throw new \RuntimeException('Unable to get queue name');
194
	}
195
}
196