Skip to content

Commit a263873

Browse files
committed
feat: add liveactivity message
Signed-off-by: Sean Molenaar <[email protected]>
1 parent 0c1e7fc commit a263873

File tree

6 files changed

+691
-0
lines changed

6 files changed

+691
-0
lines changed

ApnsPHP/Message/LiveActivity.php

Lines changed: 259 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,259 @@
1+
<?php
2+
3+
/**
4+
* This file contains the LiveActivity class.
5+
*
6+
* SPDX-FileCopyrightText: Copyright 2024 Move Agency Group B.V., Zwolle, The Netherlands
7+
* SPDX-License-Identifier: BSD-2-Clause
8+
*/
9+
10+
namespace ApnsPHP\Message;
11+
12+
use ApnsPHP\Message;
13+
use AssertionError;
14+
use UnexpectedValueException;
15+
16+
/**
17+
* Live activity style message.
18+
*/
19+
class LiveActivity extends Message
20+
{
21+
/**
22+
* Content state information
23+
* @var array|object
24+
*/
25+
private array|object $state;
26+
27+
/**
28+
* Attributes at the start of an activity
29+
* @var array|object
30+
*/
31+
private array|object $attributes;
32+
33+
/**
34+
* Type of attributes
35+
* @var string
36+
*/
37+
private string $attributes_type;
38+
39+
/**
40+
* Event for the activity
41+
* @var LiveActivityEvent
42+
*/
43+
private LiveActivityEvent $event;
44+
45+
/**
46+
* Time when the activity will become stale
47+
* @var int
48+
*/
49+
private int $stale_time;
50+
51+
/**
52+
* Time when the activity will dismiss itself
53+
* @var int
54+
*/
55+
private int $dismiss_time;
56+
57+
/**
58+
* Constructor.
59+
*
60+
* @param string|null $deviceToken Recipients device token (optional).
61+
*/
62+
public function __construct(?string $deviceToken = null)
63+
{
64+
parent::__construct($deviceToken);
65+
parent::setPushType(PushType::LiveActivity);
66+
}
67+
68+
/**
69+
* Get the payload dictionary.
70+
*
71+
* @return array<string,mixed> The payload dictionary.
72+
*/
73+
public function getPayloadDictionary(): array
74+
{
75+
$payload = parent::getPayloadDictionary();
76+
77+
$payload[self::APPLE_RESERVED_NAMESPACE]['event'] = $this->event->value;
78+
$payload[self::APPLE_RESERVED_NAMESPACE]['timestamp'] = time();
79+
if (isset($this->state)) {
80+
$payload[self::APPLE_RESERVED_NAMESPACE]['content-state'] = $this->state;
81+
}
82+
if (isset($this->stale_time)) {
83+
$payload[self::APPLE_RESERVED_NAMESPACE]['stale-date'] = $this->stale_time;
84+
}
85+
if (isset($this->dismiss_time)) {
86+
$payload[self::APPLE_RESERVED_NAMESPACE]['dismissal-date'] = $this->dismiss_time;
87+
}
88+
89+
if ($this->event !== LiveActivityEvent::Start) {
90+
return $payload;
91+
}
92+
93+
if (isset($this->attributes) && isset($this->attributes_type)) {
94+
$payload[self::APPLE_RESERVED_NAMESPACE]['attributes-type'] = $this->attributes_type;
95+
$payload[self::APPLE_RESERVED_NAMESPACE]['attributes'] = $this->attributes;
96+
}
97+
98+
return $payload;
99+
}
100+
101+
/**
102+
* Set a topic
103+
*
104+
* @throws UnexpectedValueException if the topic is invalid for a live activity.
105+
*
106+
* @param string $topic
107+
*
108+
* @return void
109+
*/
110+
public function setTopic(string $topic): void
111+
{
112+
if (!str_contains($topic, '.push-type.liveactivity')) {
113+
throw new UnexpectedValueException("Topic '$topic' does not include '.push-type.liveactivity'!");
114+
}
115+
116+
parent::setTopic($topic);
117+
}
118+
119+
/**
120+
* Set a push type
121+
*
122+
* @throws AssertionError Since the push type is tied to the class
123+
*
124+
* @param PushType $pushType
125+
*
126+
* @return void
127+
*/
128+
public function setPushType(PushType $pushType): void
129+
{
130+
throw new AssertionError('Push type is enforced by the class!');
131+
}
132+
133+
/**
134+
* Set the event for the activity
135+
*
136+
* @param LiveActivityEvent $event The activity event
137+
*/
138+
public function setEvent(LiveActivityEvent $event): void
139+
{
140+
$this->event = $event;
141+
}
142+
143+
/**
144+
* Get the event for the activity
145+
* @return LiveActivityEvent
146+
*/
147+
public function getEvent(): LiveActivityEvent
148+
{
149+
return $this->event;
150+
}
151+
152+
/**
153+
* Set the attributes for the start of the activity
154+
*
155+
* @param array|object $attributes The attributes to set
156+
*/
157+
public function setAttributes(array|object $attributes): void
158+
{
159+
$this->attributes = $attributes;
160+
}
161+
162+
/**
163+
* Get the attributes for the start activity
164+
*
165+
* @return object|array
166+
*/
167+
public function getAttributes(): object|array
168+
{
169+
return $this->attributes;
170+
}
171+
172+
/**
173+
* Set the attribute type for the start of the activity.
174+
*
175+
* @param string $type The attribute type
176+
*
177+
* @return void
178+
*/
179+
public function setAttributesType(string $type): void
180+
{
181+
$this->attributes_type = $type;
182+
}
183+
184+
/**
185+
* Get the attribute type for the start of the activity.
186+
*
187+
* @return string The attribute type
188+
*/
189+
public function getAttributesType(): string
190+
{
191+
return $this->attributes_type;
192+
}
193+
194+
/**
195+
* Set the time when the information goes stale
196+
*
197+
* @param int $stale_time The timestamp at which the information goes stale
198+
*
199+
* @return void
200+
*/
201+
public function setStaleTime(int $stale_time): void
202+
{
203+
$this->stale_time = $stale_time;
204+
}
205+
206+
/**
207+
* Get the time when the information goes stale
208+
*
209+
* @return int The timestamp at which the information goes stale
210+
*/
211+
public function getStaleTime(): int
212+
{
213+
return $this->stale_time;
214+
}
215+
216+
/**
217+
* Set the time when the activity dismisses itself
218+
*
219+
* @param int $dismiss_time The timestamp at which the activity dismisses
220+
*
221+
* @return void
222+
*/
223+
public function setDismissTime(int $dismiss_time): void
224+
{
225+
$this->dismiss_time = $dismiss_time;
226+
}
227+
228+
/**
229+
* Get the time when the activity dismisses itself
230+
*
231+
* @return int The timestamp at which the activity dismisses
232+
*/
233+
public function getDismissTime(): int
234+
{
235+
return $this->dismiss_time;
236+
}
237+
238+
/**
239+
* Set the content state
240+
*
241+
* @param array|object $state The content state to relay to the app
242+
*
243+
* @return void
244+
*/
245+
public function setContentState(array|object $state): void
246+
{
247+
$this->state = $state;
248+
}
249+
250+
/**
251+
* Get the content state
252+
*
253+
* @return array|object The content state that should be relayed to the app
254+
*/
255+
public function getContentState(): object|array
256+
{
257+
return $this->state;
258+
}
259+
}

ApnsPHP/Message/LiveActivityEvent.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
/**
4+
* This file contains the LiveActivityEvent enum.
5+
*
6+
* SPDX-FileCopyrightText: Copyright 2024 Move Agency Group B.V., Zwolle, The Netherlands
7+
* SPDX-License-Identifier: BSD-2-Clause
8+
*/
9+
10+
namespace ApnsPHP\Message;
11+
12+
/**
13+
* Live activity events.
14+
*/
15+
enum LiveActivityEvent: string
16+
{
17+
/**
18+
* Indicates this message starts the live activity
19+
*/
20+
case Start = 'start';
21+
22+
/**
23+
* Indicates this message updates the live activity
24+
*/
25+
case Update = 'update';
26+
27+
/**
28+
* Indicates this message ends the live activity
29+
*/
30+
case End = 'end';
31+
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
<?php
2+
3+
/**
4+
* This file contains the LiveActivityGetPayloadDictionaryTest class.
5+
*
6+
* SPDX-FileCopyrightText: Copyright 2024 Move Agency Group B.V., Zwolle, The Netherlands
7+
* SPDX-License-Identifier: BSD-2-Clause
8+
*/
9+
10+
namespace ApnsPHP\Message\Tests;
11+
12+
use ApnsPHP\Message\LiveActivityEvent;
13+
14+
/**
15+
* This class contains tests for the getPayloadDictionary function
16+
*
17+
* @covers \ApnsPHP\Message
18+
*/
19+
class LiveActivityGetPayloadDictionaryTest extends LiveActivityTestBase
20+
{
21+
/**
22+
* Test that getPayloadDictionary returns complete payload
23+
*
24+
* @covers \ApnsPHP\Message::getPayloadDictionary
25+
*/
26+
public function testGetPayloadDictionaryReturnsCompletePayload(): void
27+
{
28+
$this->mock_function('time', fn() => 1731944572);
29+
30+
$this->class->setTitle('Were no strangers to love');
31+
$this->class->setText('You know the rules, and so do I');
32+
$this->class->setCategory('something');
33+
$this->class->setThreadId('thisIsAThreadId');
34+
$this->class->setCustomProperty('property', 'property');
35+
$this->class->setCustomProperty('name', 'value');
36+
$this->class->setTopic('name.push-type.liveactivity');
37+
$this->class->setEvent(LiveActivityEvent::Start);
38+
$this->class->setContentState([]);
39+
$this->class->setAttributes([]);
40+
$this->class->setAttributesType('Type');
41+
$this->class->setStaleTime(1);
42+
$this->class->setDismissTime(2);
43+
44+
$payload = [
45+
'aps' => [
46+
'alert' => [
47+
'title' => 'Were no strangers to love',
48+
'body' => 'You know the rules, and so do I'
49+
],
50+
'category' => 'something',
51+
'thread-id' => 'thisIsAThreadId',
52+
'event' => 'start',
53+
'timestamp' => 1731944572,
54+
'content-state' => [],
55+
'stale-date' => 1,
56+
'dismissal-date' => 2,
57+
'attributes-type' => 'Type',
58+
'attributes' => [],
59+
],
60+
'property' => 'property',
61+
'name' => 'value'
62+
];
63+
64+
$result = $this->get_reflection_method('getPayloadDictionary')
65+
->invoke($this->class);
66+
67+
$this->assertEquals($payload, $result);
68+
$this->unmock_function('time');
69+
}
70+
71+
/**
72+
* Test that getPayloadDictionary returns an empty payload if nothing is set
73+
*
74+
* @covers \ApnsPHP\Message::getPayloadDictionary
75+
*/
76+
public function testGetPayloadDictionaryReturnsEmptyPayload(): void
77+
{
78+
$this->mock_function('time', fn() => 1731944572);
79+
80+
$this->class->setEvent(LiveActivityEvent::Start);
81+
82+
$payload = [
83+
'aps' => [
84+
'event' => 'start',
85+
'timestamp' => 1731944572
86+
]
87+
];
88+
89+
$result = $this->get_reflection_method('getPayloadDictionary')
90+
->invoke($this->class);
91+
92+
$this->assertEquals($payload, $result);
93+
$this->unmock_function('time');
94+
}
95+
}

0 commit comments

Comments
 (0)