Skip to content

Commit 5e58320

Browse files
committed
ISSUE-345: update subscriber
1 parent b5f1db2 commit 5e58320

File tree

5 files changed

+186
-12
lines changed

5 files changed

+186
-12
lines changed

src/Controller/SubscriberController.php

+95-8
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,11 @@
1010
use PhpList\Core\Security\Authentication;
1111
use PhpList\RestBundle\Controller\Traits\AuthenticationTrait;
1212
use PhpList\RestBundle\Entity\CreateSubscriberRequest;
13+
use PhpList\RestBundle\Entity\UpdateSubscriberRequest;
1314
use PhpList\RestBundle\Serializer\SubscriberNormalizer;
1415
use PhpList\RestBundle\Service\Manager\SubscriberManager;
1516
use PhpList\RestBundle\Validator\RequestValidator;
17+
use Symfony\Bridge\Doctrine\Attribute\MapEntity;
1618
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
1719
use Symfony\Component\HttpFoundation\JsonResponse;
1820
use Symfony\Component\HttpFoundation\Request;
@@ -24,7 +26,9 @@
2426
* This controller provides REST API access to subscribers.
2527
*
2628
* @author Oliver Klee <[email protected]>
29+
* @author Tatevik Grigoryan <[email protected]>
2730
*/
31+
#[Route('/subscribers')]
2832
class SubscriberController extends AbstractController
2933
{
3034
use AuthenticationTrait;
@@ -42,7 +46,7 @@ public function __construct(
4246
$this->subscriberManager = $subscriberManager;
4347
}
4448

45-
#[Route('/subscribers', name: 'create_subscriber', methods: ['POST'])]
49+
#[Route('', name: 'create_subscriber', methods: ['POST'])]
4650
#[OA\Post(
4751
path: '/subscribers',
4852
description: 'Creates a new subscriber (if there is no subscriber with the given email address yet).',
@@ -112,7 +116,7 @@ public function __construct(
112116
)
113117
]
114118
)]
115-
public function postAction(
119+
public function createSubscriber(
116120
Request $request,
117121
SerializerInterface $serializer,
118122
RequestValidator $validator
@@ -131,10 +135,96 @@ public function postAction(
131135
);
132136
}
133137

134-
#[Route('/subscribers/{subscriberId}', name: 'get_subscriber_by_id', methods: ['GET'])]
138+
#[Route('/{subscriberId}', name: 'update_subscriber', requirements: ['subscriberId' => '\d+'], methods: ['PUT'])]
135139
#[OA\Get(
136140
path: '/subscribers/{subscriberId}',
137-
description: 'Get subscriber date by id.',
141+
description: 'Update subscriber data by id.',
142+
summary: 'Update subscriber',
143+
requestBody: new OA\RequestBody(
144+
description: 'Pass session credentials',
145+
required: true,
146+
content: new OA\JsonContent(
147+
required: ['email'],
148+
properties: [
149+
new OA\Property(property: 'email', type: 'string', format: 'string', example: '[email protected]'),
150+
new OA\Property(property: 'html_email', type: 'boolean', example: false),
151+
new OA\Property(property: 'confirmed', type: 'boolean', example: false),
152+
new OA\Property(property: 'blacklisted', type: 'boolean', example: false),
153+
new OA\Property(property: 'html_email', type: 'boolean', example: false),
154+
new OA\Property(property: 'disabled', type: 'boolean', example: false),
155+
new OA\Property(property: 'additional_data', type: 'string', example: 'asdf'),
156+
]
157+
)
158+
),
159+
tags: ['subscribers'],
160+
parameters: [
161+
new OA\Parameter(
162+
name: 'session',
163+
description: 'Session ID obtained from authentication',
164+
in: 'header',
165+
required: true,
166+
schema: new OA\Schema(type: 'string')
167+
),
168+
new OA\Parameter(
169+
name: 'subscriberId',
170+
description: 'Subscriber ID',
171+
in: 'path',
172+
required: true,
173+
schema: new OA\Schema(type: 'string')
174+
)
175+
],
176+
responses: [
177+
new OA\Response(
178+
response: 200,
179+
description: 'Success',
180+
content: new OA\JsonContent(ref: '#/components/schemas/Subscriber'),
181+
),
182+
new OA\Response(
183+
response: 403,
184+
description: 'Failure',
185+
content: new OA\JsonContent(
186+
properties: [
187+
new OA\Property(
188+
property: 'message',
189+
type: 'string',
190+
example: 'No valid session key was provided as basic auth password.'
191+
)
192+
]
193+
)
194+
),
195+
new OA\Response(
196+
response: 404,
197+
description: 'Not Found',
198+
)
199+
]
200+
)]
201+
public function update(
202+
Request $request,
203+
#[MapEntity(mapping: ['subscriberId' => 'id'])] Subscriber $subscriber,
204+
SerializerInterface $serializer,
205+
RequestValidator $validator,
206+
SubscriberNormalizer $subscriberNormalizer,
207+
): JsonResponse {
208+
$this->requireAuthentication($request);
209+
210+
/** @var UpdateSubscriberRequest $dto */
211+
$dto = $serializer->deserialize($request->getContent(), UpdateSubscriberRequest::class, 'json');
212+
$dto->subscriberId = $subscriber->getId();
213+
$validator->validateDto($dto);
214+
$subscriber = $this->subscriberManager->updateSubscriber($dto);
215+
216+
return new JsonResponse(
217+
$subscriberNormalizer->normalize($subscriber, 'json'),
218+
Response::HTTP_OK,
219+
[],
220+
false
221+
);
222+
}
223+
224+
#[Route('/{subscriberId}', name: 'get_subscriber_by_id', methods: ['GET'])]
225+
#[OA\Get(
226+
path: '/subscribers/{subscriberId}',
227+
description: 'Get subscriber data by id.',
138228
summary: 'Get a subscriber',
139229
tags: ['subscribers'],
140230
parameters: [
@@ -182,10 +272,7 @@ public function getSubscriber(Request $request, int $subscriberId, SubscriberNor
182272
{
183273
$this->requireAuthentication($request);
184274

185-
$subscriber = $this->subscriberRepository->findSubscriberWithSubscriptions($subscriberId);
186-
if (!$subscriber) {
187-
return new JsonResponse(['error' => 'Subscriber not found'], Response::HTTP_NOT_FOUND);
188-
}
275+
$subscriber = $this->subscriberManager->getSubscriber($subscriberId);
189276

190277
return new JsonResponse(
191278
$serializer->normalize($subscriber, 'json'),
+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpList\RestBundle\Entity;
6+
7+
use PhpList\RestBundle\Validator as CustomAssert;
8+
use Symfony\Component\Validator\Constraints as Assert;
9+
10+
class UpdateSubscriberRequest implements RequestInterface
11+
{
12+
public int $subscriberId;
13+
14+
#[Assert\NotBlank]
15+
#[Assert\Email]
16+
#[CustomAssert\UniqueEmail]
17+
public string $email;
18+
19+
#[Assert\Type(type: 'bool')]
20+
public bool $confirmed;
21+
22+
#[Assert\Type(type: 'bool')]
23+
public bool $blacklisted;
24+
25+
#[Assert\Type(type: 'bool')]
26+
public bool $htmlEmail;
27+
28+
#[Assert\Type(type: 'number')]
29+
public ?int $rssFrequency = null; // todo check what is this
30+
31+
#[Assert\Type(type: 'bool')]
32+
public bool $disabled;
33+
34+
#[Assert\Type(type: 'string')]
35+
public string $additionalData;
36+
37+
#[Assert\Type(type: 'string')]
38+
public ?string $woonplaats = null; // todo check what is this
39+
40+
#[Assert\Type(type: 'string')]
41+
public ?string $foreignKey = null; // todo check what is this
42+
43+
#[Assert\Type(type: 'string')]
44+
public ?string $country = null; // todo check what is this
45+
}

src/Service/Manager/SubscriberManager.php

+34-1
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,22 @@
44

55
namespace PhpList\RestBundle\Service\Manager;
66

7+
use Doctrine\ORM\EntityManagerInterface;
78
use PhpList\Core\Domain\Model\Subscription\Subscriber;
89
use PhpList\Core\Domain\Repository\Subscription\SubscriberRepository;
910
use PhpList\RestBundle\Entity\CreateSubscriberRequest;
11+
use PhpList\RestBundle\Entity\UpdateSubscriberRequest;
12+
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
1013

1114
class SubscriberManager
1215
{
1316
private SubscriberRepository $subscriberRepository;
17+
private EntityManagerInterface $entityManager;
1418

15-
public function __construct(SubscriberRepository $subscriberRepository)
19+
public function __construct(SubscriberRepository $subscriberRepository, EntityManagerInterface $entityManager)
1620
{
1721
$this->subscriberRepository = $subscriberRepository;
22+
$this->entityManager = $entityManager;
1823
}
1924

2025
public function createSubscriber(CreateSubscriberRequest $subscriberRequest): Subscriber
@@ -31,4 +36,32 @@ public function createSubscriber(CreateSubscriberRequest $subscriberRequest): Su
3136

3237
return $subscriber;
3338
}
39+
40+
public function getSubscriber(int $subscriberId): Subscriber
41+
{
42+
$subscriber = $this->subscriberRepository->findSubscriberWithSubscriptions($subscriberId);
43+
44+
if (!$subscriber) {
45+
throw new NotFoundHttpException('Subscriber not found');
46+
}
47+
48+
return $subscriber;
49+
}
50+
51+
public function updateSubscriber(UpdateSubscriberRequest $subscriberRequest): Subscriber
52+
{
53+
/** @var Subscriber $subscriber */
54+
$subscriber = $this->subscriberRepository->find($subscriberRequest->subscriberId);
55+
56+
$subscriber->setEmail($subscriberRequest->email);
57+
$subscriber->setConfirmed($subscriberRequest->confirmed);
58+
$subscriber->setBlacklisted($subscriberRequest->blacklisted);
59+
$subscriber->setHtmlEmail($subscriberRequest->htmlEmail);
60+
$subscriber->setDisabled($subscriberRequest->disabled);
61+
$subscriber->setExtraData($subscriberRequest->additionalData);
62+
63+
$this->entityManager->flush();
64+
65+
return $subscriber;
66+
}
3467
}

src/Validator/RequestValidator.php

+8-2
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,13 @@ public function validate(Request $request, string $dtoClass): RequestInterface
3030
} catch (Throwable $e) {
3131
throw new UnprocessableEntityHttpException('Invalid JSON: ' . $e->getMessage());
3232
}
33-
$errors = $this->validator->validate($dto);
33+
34+
return $this->validateDto($dto);
35+
}
36+
37+
public function validateDto(RequestInterface $request): RequestInterface
38+
{
39+
$errors = $this->validator->validate($request);
3440

3541
if (count($errors) > 0) {
3642
$lines = [];
@@ -47,6 +53,6 @@ public function validate(Request $request, string $dtoClass): RequestInterface
4753
throw new UnprocessableEntityHttpException($message);
4854
}
4955

50-
return $dto;
56+
return $request;
5157
}
5258
}

src/Validator/UniqueEmailValidator.php

+4-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,10 @@ public function validate($value, Constraint $constraint): void
3636

3737
$existingUser = $this->subscriberRepository->findOneBy(['email' => $value]);
3838

39-
if ($existingUser) {
39+
$dto = $this->context->getObject();
40+
$updatingId = $dto->subscriberId ?? null;
41+
42+
if ($existingUser && $existingUser->getId() !== $updatingId) {
4043
throw new ConflictHttpException('Email already exists.');
4144
}
4245
}

0 commit comments

Comments
 (0)