Skip to content

Commit 45daf8d

Browse files
committed
Configure request object normalizer
1 parent 9a574dc commit 45daf8d

4 files changed

Lines changed: 88 additions & 7 deletions

File tree

config/services/normalizers.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,11 @@ services:
1515
$classMetadataFactory: '@?serializer.mapping.class_metadata_factory'
1616
$nameConverter: '@Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter'
1717

18+
phplist.request_serializer:
19+
class: Symfony\Component\Serializer\Serializer
20+
arguments:
21+
$normalizers:
22+
- '@Symfony\Component\Serializer\Normalizer\ObjectNormalizer'
23+
1824
PhpList\RestBundle\:
1925
resource: '../../src/*/Serializer/*'

config/services/validators.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
services:
22
PhpList\RestBundle\Common\Validator\RequestValidator:
33
arguments:
4-
$serializer: '@Symfony\Component\Serializer\Normalizer\ObjectNormalizer'
4+
$serializer: '@phplist.request_serializer'
55
$validator: '@validator'
66

77
PhpList\RestBundle\Identity\Validator\Constraint\UniqueEmailValidator:
@@ -50,4 +50,3 @@ services:
5050
autowire: true
5151
autoconfigure: true
5252
tags: [ 'validator.constraint_validator' ]
53-

src/Common/EventListener/ExceptionListener.php

Lines changed: 80 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
1717
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
1818
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
19+
use Symfony\Component\Validator\ConstraintViolationInterface;
20+
use Symfony\Component\Validator\Exception\ValidationFailedException;
1921
use Symfony\Component\Validator\Exception\ValidatorException;
2022

2123
class ExceptionListener
@@ -36,33 +38,107 @@ public function onKernelException(ExceptionEvent $event): void
3638
{
3739
$exception = $event->getThrowable();
3840

41+
if ($exception instanceof ValidationFailedException) {
42+
$event->setResponse(
43+
new JsonResponse([
44+
'message' => 'Validation failed',
45+
'errors' => $this->parseFlatValidationMessage($exception->getMessage()),
46+
], 422)
47+
);
48+
49+
return;
50+
}
51+
3952
foreach (self::EXCEPTION_STATUS_MAP as $class => $statusCode) {
4053
if ($exception instanceof $class) {
41-
$status = $statusCode ?? $exception->getStatusCode();
54+
$status = $statusCode ?? (
55+
method_exists($exception, 'getStatusCode')
56+
? $exception->getStatusCode()
57+
: 400
58+
);
59+
4260
$event->setResponse(
4361
new JsonResponse([
44-
'message' => $exception->getMessage()
62+
'message' => $exception->getMessage(),
63+
'errors' => $this->parseFlatValidationMessage($exception->getMessage()),
4564
], $status)
4665
);
66+
4767
return;
4868
}
4969
}
5070

5171
if ($exception instanceof HttpExceptionInterface) {
5272
$event->setResponse(
5373
new JsonResponse([
54-
'message' => $exception->getMessage()
74+
'message' => $exception->getMessage(),
75+
'errors' => $this->parseFlatValidationMessage($exception->getMessage()),
5576
], $exception->getStatusCode())
5677
);
78+
5779
return;
5880
}
5981

6082
if ($exception instanceof Exception) {
6183
$event->setResponse(
6284
new JsonResponse([
63-
'message' => $exception->getMessage()
85+
'message' => $exception->getMessage(),
86+
'errors' => $this->parseFlatValidationMessage($exception->getMessage()),
6487
], 500)
6588
);
6689
}
6790
}
91+
92+
/**
93+
* @return array<string, array<int, string>>
94+
*/
95+
private function formatViolations(ValidationFailedException $exception): array
96+
{
97+
$errors = [];
98+
99+
foreach ($exception->getViolations() as $violation) {
100+
/** @var ConstraintViolationInterface $violation */
101+
$field = $violation->getPropertyPath();
102+
$message = $violation->getMessage();
103+
104+
if ($field === '') {
105+
$field = '_global';
106+
}
107+
108+
$errors[$field][] = $message;
109+
}
110+
111+
return $errors;
112+
}
113+
114+
/**
115+
* @return array<string, array<int, string>>
116+
*/
117+
private function parseFlatValidationMessage(string $message): array
118+
{
119+
$errors = [];
120+
$lines = preg_split('/\r\n|\r|\n/', $message) ?: [];
121+
122+
foreach ($lines as $line) {
123+
$line = trim($line);
124+
125+
if ($line === '') {
126+
continue;
127+
}
128+
129+
$parts = explode(':', $line, 2);
130+
131+
if (count($parts) !== 2) {
132+
$errors['_global'][] = $line;
133+
continue;
134+
}
135+
136+
$field = trim($parts[0]);
137+
$errorMessage = trim($parts[1]);
138+
139+
$errors[$field][] = $errorMessage;
140+
}
141+
142+
return $errors;
143+
}
68144
}

src/Messaging/Request/CreateMessageRequest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ class CreateMessageRequest implements RequestInterface
3838
public MessageOptionsRequest $options;
3939

4040
#[TemplateExists]
41-
public ?int $templateId;
41+
public ?int $templateId = null;
4242

4343
public function getDto(): MessageDtoInterface
4444
{

0 commit comments

Comments
 (0)