Skip to content

Commit f03fe55

Browse files
committed
Add support for subscribe page data management and validation
1 parent 112abce commit f03fe55

6 files changed

Lines changed: 181 additions & 276 deletions

File tree

src/Subscription/Controller/SubscribePageController.php

Lines changed: 36 additions & 168 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
use PhpList\RestBundle\Common\Controller\BaseController;
1515
use PhpList\RestBundle\Common\Service\Provider\PaginatedDataProvider;
1616
use PhpList\RestBundle\Common\Validator\RequestValidator;
17-
use PhpList\RestBundle\Subscription\Request\SubscribePageDataRequest;
1817
use PhpList\RestBundle\Subscription\Request\SubscribePageRequest;
1918
use PhpList\RestBundle\Subscription\Serializer\SubscribePageNormalizer;
2019
use Symfony\Bridge\Doctrine\Attribute\MapEntity;
@@ -152,16 +151,12 @@ className: SubscribePage::class,
152151
),
153152
]
154153
)]
155-
public function getPage(
156-
Request $request,
157-
#[MapEntity(mapping: ['id' => 'id'])] ?SubscribePage $page = null
158-
): JsonResponse {
159-
$admin = $this->requireAuthentication($request);
160-
if (!$admin->getPrivileges()->has(PrivilegeFlag::Subscribers)) {
161-
throw $this->createAccessDeniedException('You are not allowed to view subscribe pages.');
162-
}
154+
public function getPage(Request $request): JsonResponse
155+
{
156+
$admin = $this->authentication->authenticateByApiKey($request);
157+
$page = $this->subscribePageManager->findPage(id: (int) $request->get('id'));
163158

164-
if (!$page) {
159+
if (!$page || ($page->isActive() === false && $admin === null)) {
165160
throw $this->createNotFoundException('Subscribe page not found');
166161
}
167162

@@ -179,6 +174,18 @@ public function getPage(
179174
properties: [
180175
new OA\Property(property: 'title', type: 'string'),
181176
new OA\Property(property: 'active', type: 'boolean', nullable: true),
177+
new OA\Property(
178+
property: 'data',
179+
type: 'array',
180+
items: new OA\Items(
181+
properties: [
182+
new OA\Property(property: 'key', type: 'string'),
183+
new OA\Property(property: 'value', type: 'string'),
184+
],
185+
type: 'object'
186+
),
187+
nullable: true
188+
),
182189
]
183190
)
184191
),
@@ -221,6 +228,10 @@ public function createPage(Request $request): JsonResponse
221228
$createRequest = $this->validator->validate($request, SubscribePageRequest::class);
222229

223230
$page = $this->subscribePageManager->createPage($createRequest->title, $createRequest->active, $admin);
231+
if ($createRequest->hasData()) {
232+
$this->entityManager->flush();
233+
$this->subscribePageManager->syncPageData($createRequest->getDataMap(), $page);
234+
}
224235
$this->entityManager->flush();
225236

226237
return $this->json($this->normalizer->normalize($page), Response::HTTP_CREATED);
@@ -237,6 +248,18 @@ public function createPage(Request $request): JsonResponse
237248
properties: [
238249
new OA\Property(property: 'title', type: 'string', nullable: true),
239250
new OA\Property(property: 'active', type: 'boolean', nullable: true),
251+
new OA\Property(
252+
property: 'data',
253+
type: 'array',
254+
items: new OA\Items(
255+
properties: [
256+
new OA\Property(property: 'key', type: 'string'),
257+
new OA\Property(property: 'value', type: 'string'),
258+
],
259+
type: 'object'
260+
),
261+
nullable: true
262+
),
240263
]
241264
)
242265
),
@@ -297,6 +320,9 @@ public function updatePage(
297320
active: $updateRequest->active,
298321
owner: $admin,
299322
);
323+
if ($updateRequest->hasData()) {
324+
$this->subscribePageManager->syncPageData(data: $updateRequest->getDataMap(), page: $page);
325+
}
300326
$this->entityManager->flush();
301327

302328
return $this->json($this->normalizer->normalize($updated), Response::HTTP_OK);
@@ -356,162 +382,4 @@ public function deletePage(
356382

357383
return $this->json(null, Response::HTTP_NO_CONTENT);
358384
}
359-
360-
#[Route('/{id}/data', name: 'get_data', requirements: ['id' => '\\d+'], methods: ['GET'])]
361-
#[OA\Get(
362-
path: '/api/v2/subscribe-pages/{id}/data',
363-
description: '🚧 **Status: Beta** – This method is under development. Avoid using in production.',
364-
summary: 'Get subscribe page data',
365-
tags: ['subscriptions'],
366-
parameters: [
367-
new OA\Parameter(
368-
name: 'php-auth-pw',
369-
description: 'Session key obtained from login',
370-
in: 'header',
371-
required: true,
372-
schema: new OA\Schema(type: 'string')
373-
),
374-
new OA\Parameter(
375-
name: 'id',
376-
description: 'Subscribe page ID',
377-
in: 'path',
378-
required: true,
379-
schema: new OA\Schema(type: 'integer')
380-
)
381-
],
382-
responses: [
383-
new OA\Response(
384-
response: 200,
385-
description: 'Success',
386-
content: new OA\JsonContent(
387-
type: 'array',
388-
items: new OA\Items(
389-
properties: [
390-
new OA\Property(property: 'id', type: 'integer'),
391-
new OA\Property(property: 'name', type: 'string'),
392-
new OA\Property(property: 'data', type: 'string', nullable: true),
393-
],
394-
type: 'object'
395-
)
396-
)
397-
),
398-
new OA\Response(
399-
response: 403,
400-
description: 'Failure',
401-
content: new OA\JsonContent(ref: '#/components/schemas/UnauthorizedResponse')
402-
),
403-
new OA\Response(
404-
response: 404,
405-
description: 'Not Found',
406-
content: new OA\JsonContent(ref: '#/components/schemas/NotFoundErrorResponse')
407-
)
408-
]
409-
)]
410-
public function getPageData(
411-
Request $request,
412-
#[MapEntity(mapping: ['id' => 'id'])] ?SubscribePage $page = null
413-
): JsonResponse {
414-
$admin = $this->requireAuthentication($request);
415-
if (!$admin->getPrivileges()->has(PrivilegeFlag::Subscribers)) {
416-
throw $this->createAccessDeniedException('You are not allowed to view subscribe page data.');
417-
}
418-
419-
if (!$page) {
420-
throw $this->createNotFoundException('Subscribe page not found');
421-
}
422-
423-
$data = $this->subscribePageManager->getPageData($page);
424-
425-
$json = array_map(static function ($item) {
426-
return [
427-
'id' => $item->getId(),
428-
'name' => $item->getName(),
429-
'data' => $item->getData(),
430-
];
431-
}, $data);
432-
433-
return $this->json($json, Response::HTTP_OK);
434-
}
435-
436-
#[Route('/{id}/data', name: 'set_data', requirements: ['id' => '\\d+'], methods: ['PUT'])]
437-
#[OA\Put(
438-
path: '/api/v2/subscribe-pages/{id}/data',
439-
description: '🚧 **Status: Beta** – This method is under development. Avoid using in production.',
440-
summary: 'Set subscribe page data item',
441-
requestBody: new OA\RequestBody(
442-
required: true,
443-
content: new OA\JsonContent(
444-
properties: [
445-
new OA\Property(property: 'name', type: 'string'),
446-
new OA\Property(property: 'value', type: 'string', nullable: true),
447-
]
448-
)
449-
),
450-
tags: ['subscriptions'],
451-
parameters: [
452-
new OA\Parameter(
453-
name: 'php-auth-pw',
454-
description: 'Session key obtained from login',
455-
in: 'header',
456-
required: true,
457-
schema: new OA\Schema(type: 'string')
458-
),
459-
new OA\Parameter(
460-
name: 'id',
461-
description: 'Subscribe page ID',
462-
in: 'path',
463-
required: true,
464-
schema: new OA\Schema(type: 'integer')
465-
)
466-
],
467-
responses: [
468-
new OA\Response(
469-
response: 200,
470-
description: 'Success',
471-
content: new OA\JsonContent(
472-
properties: [
473-
new OA\Property(property: 'id', type: 'integer'),
474-
new OA\Property(property: 'name', type: 'string'),
475-
new OA\Property(property: 'data', type: 'string', nullable: true),
476-
],
477-
type: 'object'
478-
)
479-
),
480-
new OA\Response(
481-
response: 403,
482-
description: 'Failure',
483-
content: new OA\JsonContent(ref: '#/components/schemas/UnauthorizedResponse')
484-
),
485-
new OA\Response(
486-
response: 404,
487-
description: 'Not Found',
488-
content: new OA\JsonContent(ref: '#/components/schemas/NotFoundErrorResponse')
489-
)
490-
]
491-
)]
492-
public function setPageData(
493-
Request $request,
494-
#[MapEntity(mapping: ['id' => 'id'])] ?SubscribePage $page = null
495-
): JsonResponse {
496-
$admin = $this->requireAuthentication($request);
497-
if (!$admin->getPrivileges()->has(PrivilegeFlag::Subscribers)) {
498-
throw $this->createAccessDeniedException('You are not allowed to update subscribe page data.');
499-
}
500-
501-
if (!$page) {
502-
throw $this->createNotFoundException('Subscribe page not found');
503-
}
504-
505-
/** @var SubscribePageDataRequest $createRequest */
506-
$createRequest = $this->validator->validate($request, SubscribePageDataRequest::class);
507-
508-
$item = $this->subscribePageManager->setPageData($page, $createRequest->name, $createRequest->value);
509-
$this->entityManager->flush();
510-
511-
return $this->json([
512-
'id' => $item->getId(),
513-
'name' => $item->getName(),
514-
'data' => $item->getData(),
515-
], Response::HTTP_OK);
516-
}
517385
}

src/Subscription/Request/SubscribePageRequest.php

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,61 @@ class SubscribePageRequest implements RequestInterface
1616
#[Assert\Type(type: 'bool')]
1717
public bool $active = false;
1818

19+
/**
20+
* @var array<int, array{key: string, value: ?string}>|null
21+
*/
22+
#[Assert\Type(type: 'array')]
23+
#[Assert\All(constraints: [
24+
new Assert\Collection(
25+
fields: [
26+
'key' => new Assert\Required([
27+
new Assert\NotBlank(),
28+
new Assert\Type(type: 'string'),
29+
]),
30+
'value' => new Assert\Required([
31+
new Assert\Type(type: 'string'),
32+
]),
33+
],
34+
allowExtraFields: false,
35+
allowMissingFields: false
36+
),
37+
])]
38+
private ?array $data = null;
39+
40+
private bool $dataProvided = false;
41+
42+
public function setData(?array $data): void
43+
{
44+
$this->data = $data;
45+
$this->dataProvided = true;
46+
}
47+
48+
public function hasData(): bool
49+
{
50+
return $this->dataProvided;
51+
}
52+
53+
/** @return array<int, array{key: string, value: ?string}>|null */
54+
public function getData(): ?array
55+
{
56+
return $this->data;
57+
}
58+
59+
/** @return array<string, ?string> */
60+
public function getDataMap(): array
61+
{
62+
if ($this->data === null) {
63+
return [];
64+
}
65+
66+
$result = [];
67+
foreach ($this->data as $item) {
68+
$result[$item['key']] = $item['value'];
69+
}
70+
71+
return $result;
72+
}
73+
1974
public function getDto(): SubscribePageRequest
2075
{
2176
return $this;
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpList\RestBundle\Subscription\Serializer;
6+
7+
use OpenApi\Attributes as OA;
8+
use PhpList\Core\Domain\Subscription\Model\SubscribePageData;
9+
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
10+
11+
#[OA\Schema(
12+
schema: 'SubscribePageData',
13+
properties: [
14+
new OA\Property(property: 'key', type: 'string', example: 'button'),
15+
new OA\Property(property: 'value', type: 'string', example: 'Subscribe to the selected newsletters'),
16+
],
17+
)]
18+
class SubscribePageDataNormalizer implements NormalizerInterface
19+
{
20+
/**
21+
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
22+
*/
23+
public function normalize($object, string $format = null, array $context = []): array
24+
{
25+
if (!$object instanceof SubscribePageData) {
26+
return [];
27+
}
28+
29+
return [
30+
'key' => $object->getName(),
31+
'value' => $object->getData(),
32+
];
33+
}
34+
35+
/**
36+
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
37+
*/
38+
public function supportsNormalization($data, string $format = null): bool
39+
{
40+
return $data instanceof SubscribePageData;
41+
}
42+
}

src/Subscription/Serializer/SubscribePageNormalizer.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,18 @@
1616
new OA\Property(property: 'title', type: 'string', example: 'Subscribe to our newsletter'),
1717
new OA\Property(property: 'active', type: 'boolean', example: true),
1818
new OA\Property(property: 'owner', ref: '#/components/schemas/Administrator'),
19+
new OA\Property(
20+
property: 'data',
21+
type: 'array',
22+
items: new OA\Items(ref: '#/components/schemas/SubscribePageData')
23+
),
1924
],
2025
)]
2126
class SubscribePageNormalizer implements NormalizerInterface
2227
{
2328
public function __construct(
2429
private readonly AdministratorNormalizer $adminNormalizer,
30+
private readonly SubscribePageDataNormalizer $dataNormalizer,
2531
) {
2632
}
2733

@@ -39,6 +45,9 @@ public function normalize($object, string $format = null, array $context = []):
3945
'title' => $object->getTitle(),
4046
'active' => $object->isActive(),
4147
'owner' => $this->adminNormalizer->normalize($object->getOwner()),
48+
'data' => array_map(function ($data) {
49+
return $this->dataNormalizer->normalize($data);
50+
}, $object->getData())
4251
];
4352
}
4453

0 commit comments

Comments
 (0)