From ede4d86e7dca6892a448101229249cbf375d5de3 Mon Sep 17 00:00:00 2001 From: Brian Stoop Date: Wed, 4 Dec 2024 16:06:55 +0100 Subject: [PATCH 1/2] General: Add method to check if payload is a broadcast --- src/Lunr/Vortex/APNS/APNSPayload.php | 13 ++++++- .../Vortex/APNS/Tests/APNSPayloadBaseTest.php | 32 +++++++++++++++++ src/Lunr/Vortex/Email/EmailPayload.php | 14 +++++++- .../Email/Tests/EmailPayloadBaseTest.php | 10 ++++++ src/Lunr/Vortex/FCM/FCMPayload.php | 13 ++++++- .../Vortex/FCM/Tests/FCMPayloadBaseTest.php | 34 +++++++++++++++++++ src/Lunr/Vortex/JPush/JPushPayload.php | 14 +++++++- .../JPush/Tests/JPushPayloadBaseTest.php | 10 ++++++ .../PushNotificationPayloadInterface.php | 27 +++++++++++++++ .../Vortex/WNS/Tests/WNSPayloadBaseTest.php | 10 ++++++ src/Lunr/Vortex/WNS/WNSPayload.php | 14 +++++++- 11 files changed, 186 insertions(+), 5 deletions(-) create mode 100644 src/Lunr/Vortex/APNS/Tests/APNSPayloadBaseTest.php create mode 100644 src/Lunr/Vortex/PushNotificationPayloadInterface.php diff --git a/src/Lunr/Vortex/APNS/APNSPayload.php b/src/Lunr/Vortex/APNS/APNSPayload.php index e373002..8887a60 100644 --- a/src/Lunr/Vortex/APNS/APNSPayload.php +++ b/src/Lunr/Vortex/APNS/APNSPayload.php @@ -10,12 +10,13 @@ namespace Lunr\Vortex\APNS; +use Lunr\Vortex\PushNotificationPayloadInterface; use ReflectionClass; /** * Apple Push Notification Service Payload Generator. */ -class APNSPayload +class APNSPayload implements PushNotificationPayloadInterface { /** @@ -42,6 +43,16 @@ public function __destruct() unset($this->elements); } + /** + * Check if the payload is for a broadcast notification. + * + * @return bool If payload for notification is a broadcast + */ + public function is_broadcast(): bool + { + return FALSE; + } + /** * Construct the payload for the push notification. * diff --git a/src/Lunr/Vortex/APNS/Tests/APNSPayloadBaseTest.php b/src/Lunr/Vortex/APNS/Tests/APNSPayloadBaseTest.php new file mode 100644 index 0000000..44afbe6 --- /dev/null +++ b/src/Lunr/Vortex/APNS/Tests/APNSPayloadBaseTest.php @@ -0,0 +1,32 @@ +assertFalse($this->class->is_broadcast()); + } + +} + +?> diff --git a/src/Lunr/Vortex/Email/EmailPayload.php b/src/Lunr/Vortex/Email/EmailPayload.php index ae084b7..e0a0b14 100644 --- a/src/Lunr/Vortex/Email/EmailPayload.php +++ b/src/Lunr/Vortex/Email/EmailPayload.php @@ -10,6 +10,8 @@ namespace Lunr\Vortex\Email; +use Lunr\Vortex\PushNotificationPayloadInterface; + /** * Email Notification Payload Generator. * @@ -21,7 +23,7 @@ * body_as_html: bool * } */ -class EmailPayload +class EmailPayload implements PushNotificationPayloadInterface { /** @@ -52,6 +54,16 @@ public function __destruct() unset($this->elements); } + /** + * Check if the payload is for a broadcast notification. + * + * @return bool If payload for notification is a broadcast + */ + public function is_broadcast(): bool + { + return FALSE; + } + /** * Construct the payload for the email notification. * diff --git a/src/Lunr/Vortex/Email/Tests/EmailPayloadBaseTest.php b/src/Lunr/Vortex/Email/Tests/EmailPayloadBaseTest.php index 6bda2b7..3c27948 100644 --- a/src/Lunr/Vortex/Email/Tests/EmailPayloadBaseTest.php +++ b/src/Lunr/Vortex/Email/Tests/EmailPayloadBaseTest.php @@ -34,6 +34,16 @@ public function testElementsIsInitializedAsEmptyArray(): void $this->assertEquals($expected, $this->get_reflection_property_value('elements')); } + /** + * Test is_broadcast returns false. + * + * @covers Lunr\Vortex\Email\EmailPayload::is_broadcast + */ + public function testIsBroadCastReturnFalse(): void + { + $this->assertFalse($this->class->is_broadcast()); + } + } ?> diff --git a/src/Lunr/Vortex/FCM/FCMPayload.php b/src/Lunr/Vortex/FCM/FCMPayload.php index f6326b2..9cde5ef 100644 --- a/src/Lunr/Vortex/FCM/FCMPayload.php +++ b/src/Lunr/Vortex/FCM/FCMPayload.php @@ -11,6 +11,7 @@ namespace Lunr\Vortex\FCM; use InvalidArgumentException; +use Lunr\Vortex\PushNotificationPayloadInterface; /** * Firebase Cloud Messaging Push Notification Payload Generator. @@ -38,7 +39,7 @@ * } * @phpstan-type FcmOptionKeys "analytics_label" */ -class FCMPayload +class FCMPayload implements PushNotificationPayloadInterface { /** @@ -79,6 +80,16 @@ public function __destruct() unset($this->apns_payload); } + /** + * Check if the payload is for a broadcast notification. + * + * @return bool If payload for notification is a broadcast + */ + public function is_broadcast(): bool + { + return $this->has_topic() || $this->has_condition(); + } + /** * Construct the payload for the push notification. * diff --git a/src/Lunr/Vortex/FCM/Tests/FCMPayloadBaseTest.php b/src/Lunr/Vortex/FCM/Tests/FCMPayloadBaseTest.php index eb0b117..45c4fd7 100644 --- a/src/Lunr/Vortex/FCM/Tests/FCMPayloadBaseTest.php +++ b/src/Lunr/Vortex/FCM/Tests/FCMPayloadBaseTest.php @@ -42,6 +42,40 @@ public function testApnsPayloadIsInitializedWithNULL(): void $this->assertPropertySame('apns_payload', NULL); } + /** + * Test is_broadcast() returns FALSE when no condition or topic is set. + * + * @covers Lunr\Vortex\FCM\FCMPayload::is_broadcast + */ + public function testIsBroadcastReturnFalse(): void + { + $this->assertFalse($this->class->is_broadcast()); + } + + /** + * Test if is_broadcast() returns TRUE when condition is set. + * + * @covers Lunr\Vortex\FCM\FCMPayload::is_broadcast + */ + public function testIsBroadcastConditionIsSet(): void + { + $this->class->set_condition("'TopicA' in topics && 'TopicB' in topics"); + + $this->assertTrue($this->class->is_broadcast()); + } + + /** + * Test if is_broadcast() returns TRUE when topic is set. + * + * @covers Lunr\Vortex\FCM\FCMPayload::is_broadcast + */ + public function testIsBroadcastTopicIsSet(): void + { + $this->class->set_topic('news'); + + $this->assertTrue($this->class->is_broadcast()); + } + } ?> diff --git a/src/Lunr/Vortex/JPush/JPushPayload.php b/src/Lunr/Vortex/JPush/JPushPayload.php index 169f184..aa524e7 100644 --- a/src/Lunr/Vortex/JPush/JPushPayload.php +++ b/src/Lunr/Vortex/JPush/JPushPayload.php @@ -10,10 +10,12 @@ namespace Lunr\Vortex\JPush; +use Lunr\Vortex\PushNotificationPayloadInterface; + /** * JPush Payload Generator. */ -abstract class JPushPayload +abstract class JPushPayload implements PushNotificationPayloadInterface { /** @@ -50,6 +52,16 @@ public function __destruct() unset($this->elements); } + /** + * Check if the payload is for a broadcast notification. + * + * @return bool If payload for notification is a broadcast + */ + public function is_broadcast(): bool + { + return FALSE; + } + /** * Construct the payload for the push notification. * diff --git a/src/Lunr/Vortex/JPush/Tests/JPushPayloadBaseTest.php b/src/Lunr/Vortex/JPush/Tests/JPushPayloadBaseTest.php index 7cbe63e..90095e5 100644 --- a/src/Lunr/Vortex/JPush/Tests/JPushPayloadBaseTest.php +++ b/src/Lunr/Vortex/JPush/Tests/JPushPayloadBaseTest.php @@ -34,6 +34,16 @@ public function testElementsIsInitialized(): void ]); } + /** + * Test is_broadcast returns false. + * + * @covers \Lunr\Vortex\JPush\JPushPayload::is_broadcast + */ + public function testIsBroadCastReturnFalse(): void + { + $this->assertFalse($this->class->is_broadcast()); + } + } ?> diff --git a/src/Lunr/Vortex/PushNotificationPayloadInterface.php b/src/Lunr/Vortex/PushNotificationPayloadInterface.php new file mode 100644 index 0000000..cf75d2c --- /dev/null +++ b/src/Lunr/Vortex/PushNotificationPayloadInterface.php @@ -0,0 +1,27 @@ + diff --git a/src/Lunr/Vortex/WNS/Tests/WNSPayloadBaseTest.php b/src/Lunr/Vortex/WNS/Tests/WNSPayloadBaseTest.php index 0ddffe0..3b083b9 100644 --- a/src/Lunr/Vortex/WNS/Tests/WNSPayloadBaseTest.php +++ b/src/Lunr/Vortex/WNS/Tests/WNSPayloadBaseTest.php @@ -35,6 +35,16 @@ public function testEscapeString($string, $expected): void $this->assertEquals($expected, $method->invokeArgs($this->class, [ $string ])); } + /** + * Test is_broadcast returns false. + * + * @covers Lunr\Vortex\WNS\WNSBadgePayload::is_broadcast + */ + public function testIsBroadCastReturnFalse(): void + { + $this->assertFalse($this->class->is_broadcast()); + } + } ?> diff --git a/src/Lunr/Vortex/WNS/WNSPayload.php b/src/Lunr/Vortex/WNS/WNSPayload.php index b99cf6b..b114256 100644 --- a/src/Lunr/Vortex/WNS/WNSPayload.php +++ b/src/Lunr/Vortex/WNS/WNSPayload.php @@ -10,10 +10,12 @@ namespace Lunr\Vortex\WNS; +use Lunr\Vortex\PushNotificationPayloadInterface; + /** * Windows Push Notification Payload Generator. */ -abstract class WNSPayload +abstract class WNSPayload implements PushNotificationPayloadInterface { /** @@ -47,6 +49,16 @@ protected function escape_string(string $string): string return str_replace($search, $replace, $string); } + /** + * Check if the payload is for a broadcast notification. + * + * @return bool If payload for notification is a broadcast + */ + public function is_broadcast(): bool + { + return FALSE; + } + /** * Construct the payload for the push notification. * From e7ea585ba1c3d6628598da05b6d937c24a6b90e3 Mon Sep 17 00:00:00 2001 From: Brian Stoop Date: Thu, 5 Dec 2024 11:18:19 +0100 Subject: [PATCH 2/2] General: Allow broadcast to be sent with empty endpoints --- .../Vortex/PushNotificationDispatcher.php | 10 +++-- ...PushNotificationDispatcherDispatchTest.php | 37 +++++++++++++++++++ 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/src/Lunr/Vortex/PushNotificationDispatcher.php b/src/Lunr/Vortex/PushNotificationDispatcher.php index 671f6af..b4e389d 100644 --- a/src/Lunr/Vortex/PushNotificationDispatcher.php +++ b/src/Lunr/Vortex/PushNotificationDispatcher.php @@ -87,7 +87,7 @@ public function dispatch(array $endpoints, array $payloads): void foreach ($payloads as $platform => $platform_payloads) { - if (!isset($grouped_endpoints[$platform])) + if (!isset($grouped_endpoints[$platform]) && array_filter($platform_payloads, fn($payload) => $payload->is_broadcast()) === []) { continue; } @@ -104,18 +104,20 @@ public function dispatch(array $endpoints, array $payloads): void foreach ($platform_payloads as $payload_type => $payload) { - if (!isset($grouped_endpoints[$platform][$payload_type])) + if (!isset($grouped_endpoints[$platform][$payload_type]) && $payload->is_broadcast() === FALSE) { continue; } + $endpoints = $grouped_endpoints[$platform][$payload_type] ?? []; + if ($this->dispatchers[$platform] instanceof PushNotificationMultiDispatcherInterface) { - $this->dispatch_multiple($platform, $grouped_endpoints[$platform][$payload_type], $payload); + $this->dispatch_multiple($platform, $endpoints, $payload); } else { - $this->dispatch_single($platform, $grouped_endpoints[$platform][$payload_type], $payload); + $this->dispatch_single($platform, $endpoints, $payload); } } } diff --git a/src/Lunr/Vortex/Tests/PushNotificationDispatcherDispatchTest.php b/src/Lunr/Vortex/Tests/PushNotificationDispatcherDispatchTest.php index 87b9005..7df91b3 100644 --- a/src/Lunr/Vortex/Tests/PushNotificationDispatcherDispatchTest.php +++ b/src/Lunr/Vortex/Tests/PushNotificationDispatcherDispatchTest.php @@ -928,6 +928,43 @@ public function testDispatchMultiCastWithDeferredResponse(): void $this->assertPropertySame('statuses', $expected_statuses); } + /** + * Test dispatch send correct broadcast payload. + * + * @covers Lunr\Vortex\PushNotificationDispatcher::dispatch + */ + public function testDispatchSendsCorrectBroadcastPayload(): void + { + $dispatchers = [ + 'apns' => $this->apns, + 'fcm' => $this->fcm, + 'email' => $this->email, + ]; + $this->set_reflection_property_value('dispatchers', $dispatchers); + + $data_payload = $this->getMockBuilder(FCMPayload::class) + ->disableOriginalConstructor() + ->getMock(); + + $payloads = [ + 'fcm' => [ 'data' => $data_payload ], + ]; + + $data_payload->expects($this->exactly(2)) + ->method('is_broadcast') + ->willReturn(TRUE); + + $this->fcm->expects($this->once()) + ->method('push') + ->with($data_payload, []) + ->willReturn($this->fcm_response); + + $this->fcm_response->expects($this->never()) + ->method('get_status'); + + $this->class->dispatch([], $payloads); + } + } ?>