Skip to content

Commit 027a465

Browse files
committedMay 4, 2025
ISSUE-345: subscriptions
1 parent 9bd58bc commit 027a465

File tree

3 files changed

+106
-59
lines changed

3 files changed

+106
-59
lines changed
 

‎src/Controller/SubscriptionController.php

Lines changed: 42 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,20 @@
55
namespace PhpList\RestBundle\Controller;
66

77
use OpenApi\Attributes as OA;
8+
use PhpList\Core\Domain\Filter\SubscriberFilter;
9+
use PhpList\Core\Domain\Model\Subscription\Subscriber;
810
use PhpList\Core\Domain\Model\Subscription\SubscriberList;
911
use PhpList\Core\Security\Authentication;
1012
use PhpList\RestBundle\Entity\Request\SubscriptionRequest;
1113
use PhpList\RestBundle\Serializer\SubscriberNormalizer;
1214
use PhpList\RestBundle\Serializer\SubscriptionNormalizer;
1315
use PhpList\RestBundle\Service\Manager\SubscriptionManager;
16+
use PhpList\RestBundle\Service\Provider\PaginatedDataProvider;
1417
use PhpList\RestBundle\Validator\RequestValidator;
1518
use Symfony\Bridge\Doctrine\Attribute\MapEntity;
1619
use Symfony\Component\HttpFoundation\JsonResponse;
1720
use Symfony\Component\HttpFoundation\Request;
1821
use Symfony\Component\HttpFoundation\Response;
19-
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
2022
use Symfony\Component\Routing\Attribute\Route;
2123

2224
/**
@@ -30,18 +32,21 @@ class SubscriptionController extends BaseController
3032
private SubscriptionManager $subscriptionManager;
3133
private SubscriberNormalizer $subscriberNormalizer;
3234
private SubscriptionNormalizer $subscriptionNormalizer;
35+
private PaginatedDataProvider $paginatedProvider;
3336

3437
public function __construct(
3538
Authentication $authentication,
3639
RequestValidator $validator,
3740
SubscriptionManager $subscriptionManager,
3841
SubscriberNormalizer $subscriberNormalizer,
3942
SubscriptionNormalizer $subscriptionNormalizer,
43+
PaginatedDataProvider $paginatedProvider,
4044
) {
4145
parent::__construct($authentication, $validator);
4246
$this->subscriptionManager = $subscriptionManager;
4347
$this->subscriberNormalizer = $subscriberNormalizer;
4448
$this->subscriptionNormalizer = $subscriptionNormalizer;
49+
$this->paginatedProvider = $paginatedProvider;
4550
}
4651

4752
#[Route('/{listId}/subscribers', name: 'get_subscriber_from_list', methods: ['GET'])]
@@ -64,15 +69,36 @@ public function __construct(
6469
in: 'path',
6570
required: true,
6671
schema: new OA\Schema(type: 'string')
72+
),
73+
new OA\Parameter(
74+
name: 'after_id',
75+
description: 'Last id (starting from 0)',
76+
in: 'query',
77+
required: false,
78+
schema: new OA\Schema(type: 'integer', default: 1, minimum: 1)
79+
),
80+
new OA\Parameter(
81+
name: 'limit',
82+
description: 'Number of results per page',
83+
in: 'query',
84+
required: false,
85+
schema: new OA\Schema(type: 'integer', default: 25, maximum: 100, minimum: 1)
6786
)
6887
],
6988
responses: [
7089
new OA\Response(
7190
response: 200,
7291
description: 'Success',
7392
content: new OA\JsonContent(
74-
type: 'array',
75-
items: new OA\Items(ref: '#/components/schemas/Subscriber')
93+
properties: [
94+
new OA\Property(
95+
property: 'items',
96+
type: 'array',
97+
items: new OA\Items(ref: '#/components/schemas/Subscriber')
98+
),
99+
new OA\Property(property: 'pagination', ref: '#/components/schemas/CursorPagination')
100+
],
101+
type: 'object'
76102
)
77103
),
78104
new OA\Response(
@@ -94,13 +120,18 @@ public function getListMembers(
94120
$this->requireAuthentication($request);
95121

96122
if (!$list) {
97-
throw new NotFoundHttpException('Subscriber list not found.');
123+
throw $this->createNotFoundException('Subscriber list not found.');
98124
}
99125

100-
$subscribers = $this->subscriptionManager->getSubscriberListMembers($list);
101-
$normalized = array_map(fn($subscriber) => $this->subscriberNormalizer->normalize($subscriber), $subscribers);
102-
103-
return new JsonResponse($normalized, Response::HTTP_OK);
126+
return new JsonResponse(
127+
$this->paginatedProvider->getPaginatedList(
128+
$request,
129+
$this->subscriberNormalizer,
130+
Subscriber::class,
131+
(new SubscriberFilter())->setListId($list->getId())
132+
),
133+
Response::HTTP_OK
134+
);
104135
}
105136

106137
#[Route('/{listId}/subscribers/count', name: 'get_subscribers_count_from_list', methods: ['GET'])]
@@ -154,7 +185,7 @@ public function getSubscribersCount(
154185
$this->requireAuthentication($request);
155186

156187
if (!$list) {
157-
throw new NotFoundHttpException('Subscriber list not found.');
188+
throw $this->createNotFoundException('Subscriber list not found.');
158189
}
159190

160191
return new JsonResponse(['subscribers_count' => count($list->getSubscribers())], Response::HTTP_OK);
@@ -240,7 +271,7 @@ public function createSubscription(
240271
$this->requireAuthentication($request);
241272

242273
if (!$list) {
243-
throw new NotFoundHttpException('Subscriber list not found.');
274+
throw $this->createNotFoundException('Subscriber list not found.');
244275
}
245276

246277
/** @var SubscriptionRequest $subscriptionRequest */
@@ -303,7 +334,7 @@ public function deleteSubscriptions(
303334
): JsonResponse {
304335
$this->requireAuthentication($request);
305336
if (!$list) {
306-
throw new NotFoundHttpException('Subscriber list not found.');
337+
throw $this->createNotFoundException('Subscriber list not found.');
307338
}
308339
$subscriptionRequest = new SubscriptionRequest();
309340
$subscriptionRequest->emails = $request->query->all('emails');

‎tests/Integration/Controller/CampaignControllerTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@ public function testGetCampaignsReturnsCampaignData(): void
5151
$response = $this->getDecodedJsonResponseContent();
5252

5353
self::assertIsArray($response);
54-
self::assertArrayHasKey('id', $response[0]);
55-
self::assertArrayHasKey('message_content', $response[0]);
54+
self::assertArrayHasKey('id', $response['items'][0]);
55+
self::assertArrayHasKey('message_content', $response['items'][0]);
5656
}
5757

5858
public function testGetSingleCampaignWithValidSessionReturnsData(): void

‎tests/Integration/Controller/ListControllerTest.php

Lines changed: 62 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,15 @@ public function testGetListMembersWithCurrentSessionKeyForExistingListWithoutSub
232232

233233
$this->authenticatedJsonRequest('get', '/api/v2/lists/1/subscribers');
234234

235-
$this->assertJsonResponseContentEquals([]);
235+
$this->assertJsonResponseContentEquals([
236+
'items' => [],
237+
'pagination' => [
238+
'total' => 0,
239+
'limit' => 25,
240+
'has_more' => false,
241+
'next_cursor' => null,
242+
]
243+
]);
236244
}
237245

238246
public function testGetListMembersWithCurrentSessionKeyForExistingListWithSubscribersReturnsSubscribers()
@@ -243,55 +251,63 @@ public function testGetListMembersWithCurrentSessionKeyForExistingListWithSubscr
243251

244252
$this->assertJsonResponseContentEquals(
245253
[
246-
[
247-
'id' => 1,
248-
'email' => 'oliver@example.com',
249-
'created_at' => '2016-07-22T15:01:17+00:00',
250-
'confirmed' => true,
251-
'blacklisted' => true,
252-
'bounce_count' => 17,
253-
'unique_id' => '95feb7fe7e06e6c11ca8d0c48cb46e89',
254-
'html_email' => true,
255-
'disabled' => true,
256-
'subscribed_lists' => [
257-
[
258-
'id' => 2,
259-
'name' => 'More news',
260-
'description' => '',
261-
'created_at' => '2016-06-22T15:01:17+00:00',
262-
'public' => true,
263-
'subscription_date' => '2016-07-22T15:01:17+00:00',
264-
],
265-
],
266-
], [
267-
'id' => 2,
268-
'email' => 'oliver1@example.com',
269-
'created_at' => '2016-07-22T15:01:17+00:00',
270-
'confirmed' => true,
271-
'blacklisted' => true,
272-
'bounce_count' => 17,
273-
'unique_id' => '95feb7fe7e06e6c11ca8d0c48cb46e87',
274-
'html_email' => true,
275-
'disabled' => true,
276-
'subscribed_lists' => [
277-
[
278-
'id' => 2,
279-
'name' => 'More news',
280-
'description' => '',
281-
'created_at' => '2016-06-22T15:01:17+00:00',
282-
'public' => true,
283-
'subscription_date' => '2016-08-22T15:01:17+00:00',
254+
'items' => [
255+
[
256+
'id' => 1,
257+
'email' => 'oliver@example.com',
258+
'created_at' => '2016-07-22T15:01:17+00:00',
259+
'confirmed' => true,
260+
'blacklisted' => true,
261+
'bounce_count' => 17,
262+
'unique_id' => '95feb7fe7e06e6c11ca8d0c48cb46e89',
263+
'html_email' => true,
264+
'disabled' => true,
265+
'subscribed_lists' => [
266+
[
267+
'id' => 2,
268+
'name' => 'More news',
269+
'description' => '',
270+
'created_at' => '2016-06-22T15:01:17+00:00',
271+
'public' => true,
272+
'subscription_date' => '2016-07-22T15:01:17+00:00',
273+
],
284274
],
285-
[
286-
'id' => 1,
287-
'name' => 'News',
288-
'description' => 'News (and some fun stuff)',
289-
'created_at' => '2016-06-22T15:01:17+00:00',
290-
'public' => true,
291-
'subscription_date' => '2016-09-22T15:01:17+00:00',
275+
], [
276+
'id' => 2,
277+
'email' => 'oliver1@example.com',
278+
'created_at' => '2016-07-22T15:01:17+00:00',
279+
'confirmed' => true,
280+
'blacklisted' => true,
281+
'bounce_count' => 17,
282+
'unique_id' => '95feb7fe7e06e6c11ca8d0c48cb46e87',
283+
'html_email' => true,
284+
'disabled' => true,
285+
'subscribed_lists' => [
286+
[
287+
'id' => 2,
288+
'name' => 'More news',
289+
'description' => '',
290+
'created_at' => '2016-06-22T15:01:17+00:00',
291+
'public' => true,
292+
'subscription_date' => '2016-08-22T15:01:17+00:00',
293+
],
294+
[
295+
'id' => 1,
296+
'name' => 'News',
297+
'description' => 'News (and some fun stuff)',
298+
'created_at' => '2016-06-22T15:01:17+00:00',
299+
'public' => true,
300+
'subscription_date' => '2016-09-22T15:01:17+00:00',
301+
],
292302
],
293303
],
294304
],
305+
'pagination' => [
306+
'total' => 3,
307+
'limit' => 25,
308+
'has_more' => false,
309+
'next_cursor' => 2,
310+
],
295311
]
296312
);
297313
}

0 commit comments

Comments
 (0)
Please sign in to comment.