From 2be1d804b22ca79a4c1e07c13710320ee7384387 Mon Sep 17 00:00:00 2001 From: "Robert (Jamie) Munro" Date: Wed, 14 Aug 2013 18:07:49 +0100 Subject: [PATCH 1/4] Apple: Move calculating $APNUrl to where it's needed --- Service/OS/AppleNotification.php | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Service/OS/AppleNotification.php b/Service/OS/AppleNotification.php index b3cad0b..1e84bc7 100644 --- a/Service/OS/AppleNotification.php +++ b/Service/OS/AppleNotification.php @@ -101,14 +101,9 @@ public function send(MessageInterface $message) throw new InvalidMessageTypeException(sprintf("Message type '%s' not supported by APN", get_class($message))); } - $apnURL = "ssl://gateway.push.apple.com:2195"; - if ($this->useSandbox) { - $apnURL = "ssl://gateway.sandbox.push.apple.com:2195"; - } - $messageId = ++$this->lastMessageId; $this->messages[$messageId] = $this->createPayload($messageId, $message->getDeviceIdentifier(), $message->getMessageBody()); - $errors = $this->sendMessages($messageId, $apnURL); + $errors = $this->sendMessages($messageId); return !$errors; } @@ -122,9 +117,15 @@ public function send(MessageInterface $message) * @throws \RMS\PushNotificationsBundle\Exception\InvalidMessageTypeException * @return int */ - protected function sendMessages($firstMessageId, $apnURL) + protected function sendMessages($firstMessageId) { $errors = array(); + + $apnURL = "ssl://gateway.push.apple.com:2195"; + if ($this->useSandbox) { + $apnURL = "ssl://gateway.sandbox.push.apple.com:2195"; + } + // Loop through all messages starting from the given ID for ($currentMessageId = $firstMessageId; $currentMessageId < count($this->messages); $currentMessageId++) { From 75173608cfe7074122d762da70f048a4aedbe6a7 Mon Sep 17 00:00:00 2001 From: "Robert (Jamie) Munro" Date: Wed, 14 Aug 2013 18:25:22 +0100 Subject: [PATCH 2/4] Apple: Add new method queue() to enable bulk sending queue() queues messages without calling sendMessages(), so you can then call sendMessages manually. Refactored send to call queue() then sendMessages(). Tidied code a little to conform to PSR-2 --- Service/OS/AppleNotification.php | 55 +++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 18 deletions(-) diff --git a/Service/OS/AppleNotification.php b/Service/OS/AppleNotification.php index 1e84bc7..dc17d16 100644 --- a/Service/OS/AppleNotification.php +++ b/Service/OS/AppleNotification.php @@ -51,6 +51,13 @@ class AppleNotification implements OSNotificationServiceInterface */ protected $lastMessageId; + /** + * Log of errors thrown to us from Apple + * + * @var type array + */ + protected $errors = array(); + /** * JSON_UNESCAPED_UNICODE * @@ -88,14 +95,14 @@ public function setJsonUnescapedUnicode($jsonUnescapedUnicode) } /** - * Send a notification message + * Queue a notification message for later sending * - * @param \RMS\PushNotificationsBundle\Message\MessageInterface|\RMS\PushNotificationsBundle\Service\OS\MessageInterface $message + * @param AppleMessage $message * @throws \RuntimeException - * @throws \RMS\PushNotificationsBundle\Exception\InvalidMessageTypeException - * @return bool + * @throws InvalidMessageTypeException + * @return int Id of the message */ - public function send(MessageInterface $message) + public function queue(MessageInterface $message) { if (!$message instanceof AppleMessage) { throw new InvalidMessageTypeException(sprintf("Message type '%s' not supported by APN", get_class($message))); @@ -103,6 +110,21 @@ public function send(MessageInterface $message) $messageId = ++$this->lastMessageId; $this->messages[$messageId] = $this->createPayload($messageId, $message->getDeviceIdentifier(), $message->getMessageBody()); + + return $messageId; + } + + /** + * Send a single notification message + * + * @param AppleMessage $message + * @throws \RuntimeException + * @throws InvalidMessageTypeException + * @return bool True if messages sent successfully + */ + public function send(MessageInterface $message) + { + $messageId = $this->queue($message); $errors = $this->sendMessages($messageId); return !$errors; @@ -111,37 +133,34 @@ public function send(MessageInterface $message) /** * Send all notification messages starting from the given ID * - * @param int $firstMessageId - * @param string $apnURL + * @param int $firstMessageId + * @param string $apnURL * @throws \RuntimeException - * @throws \RMS\PushNotificationsBundle\Exception\InvalidMessageTypeException - * @return int + * @throws InvalidMessageTypeException + * @return array Array of errors returned */ - protected function sendMessages($firstMessageId) + protected function sendMessages($firstMessageId = 0) { - $errors = array(); - $apnURL = "ssl://gateway.push.apple.com:2195"; if ($this->useSandbox) { $apnURL = "ssl://gateway.sandbox.push.apple.com:2195"; } // Loop through all messages starting from the given ID - for ($currentMessageId = $firstMessageId; $currentMessageId < count($this->messages); $currentMessageId++) - { + for ($currentMessageId = $firstMessageId; $currentMessageId < count($this->messages); $currentMessageId++) { // Send the message $result = $this->writeApnStream($apnURL, $this->messages[$currentMessageId]); - $errors = array(); - // Check if there is an error result if (is_array($result)) { + // Save the error + $this->errors[] = $result; // Resend all messages that were sent after the failed message $this->sendMessages($result['identifier']+1, $apnURL); - $errors[] = $result; } } - return $errors; + + return $this->$errors; } /** From 4ffa2dec840b623c3fa1c086a3424041d5bff875 Mon Sep 17 00:00:00 2001 From: "Robert (Jamie) Munro" Date: Thu, 15 Aug 2013 09:47:50 +0100 Subject: [PATCH 3/4] Rename sendMessages() to flush() --- Service/OS/AppleNotification.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Service/OS/AppleNotification.php b/Service/OS/AppleNotification.php index dc17d16..d0bf628 100644 --- a/Service/OS/AppleNotification.php +++ b/Service/OS/AppleNotification.php @@ -125,7 +125,7 @@ public function queue(MessageInterface $message) public function send(MessageInterface $message) { $messageId = $this->queue($message); - $errors = $this->sendMessages($messageId); + $errors = $this->flush($messageId); return !$errors; } @@ -139,7 +139,7 @@ public function send(MessageInterface $message) * @throws InvalidMessageTypeException * @return array Array of errors returned */ - protected function sendMessages($firstMessageId = 0) + protected function flush($firstMessageId = 0) { $apnURL = "ssl://gateway.push.apple.com:2195"; if ($this->useSandbox) { @@ -156,7 +156,7 @@ protected function sendMessages($firstMessageId = 0) // Save the error $this->errors[] = $result; // Resend all messages that were sent after the failed message - $this->sendMessages($result['identifier']+1, $apnURL); + $this->flush($result['identifier']+1, $apnURL); } } From b919a08501addcda810325f564c63f13f4aeb0fd Mon Sep 17 00:00:00 2001 From: "Robert (Jamie) Munro" Date: Thu, 15 Aug 2013 10:13:04 +0100 Subject: [PATCH 4/4] Add bulk notification methods to parent object --- Service/Notifications.php | 48 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/Service/Notifications.php b/Service/Notifications.php index ff6c47e..a31cebc 100644 --- a/Service/Notifications.php +++ b/Service/Notifications.php @@ -21,7 +21,31 @@ public function __construct() } /** - * Sends a message to a device, identified by + * Queues a message for sending to a device, identified by + * the OS and the supplied device token + * + * @param \RMS\PushNotificationsBundle\Message\MessageInterface $message + * @throws \RuntimeException + * @return bool + */ + public function queue(MessageInterface $message) + { + if (!isset($this->handlers[$message->getTargetOS()])) { + throw new \RuntimeException("OS type {$message->getTargetOS()} not supported"); + } + + $handler = $this->handlers[$message->getTargetOS()]; + + if (method_exists($handler, "queue")) { + return $handler->queue($message); + } else { + // Fall back to sending now if bulk messaging not supported + return $handler->send($message); + } + } + + /** + * Sends a message to a device instantly, identified by * the OS and the supplied device token * * @param \RMS\PushNotificationsBundle\Message\MessageInterface $message @@ -37,13 +61,33 @@ public function send(MessageInterface $message) return $this->handlers[$message->getTargetOS()]->send($message); } + /** + * Flush - send queued messages in all handlers + * + * @return array An array of errors returned by each handler, keyed by the OS. + */ + public function flush() + { + $errors = array(); + foreach ($this->handlers as $osType => $handler) { + if (method_exists($handler, "flush")) { + // This is a no-op for platforms that don't support bulk sending + $osErrors = $handler->flush(); + if (count($osErrors)) { + $errors[$osType] = $osErrors; + } + } + } + return $errors; + } + /** * Adds a handler * * @param $osType * @param $service */ - public function addHandler($osType, $service) + public function addHandler($osType, OS\OSNotificationServiceInterface $service) { if (!isset($this->handlers[$osType])) { $this->handlers[$osType] = $service;