issues/27: sequence/default migration and #[OA\RequestBody(... Model(... groups: *:write))]

This commit is contained in:
Valery Petrov
2026-05-15 14:31:24 +03:00
committed by Valeriy Petrov
parent 656f79ff4e
commit da5f7bb242
14 changed files with 104 additions and 9 deletions
+25 -9
View File
@@ -52,30 +52,34 @@ final class CrudResponder
string $entityClass,
array $writeGroups,
array $readGroups,
bool $allowIdFromPayload = true,
bool $allowIdFromPayload = false,
): JsonResponse {
$payload = $this->decodePayload($request);
if ($payload === null) {
return $this->jsonError('Ожидается JSON-объект в теле запроса', Response::HTTP_BAD_REQUEST);
}
$deserializationPayload = $payload;
if (!$allowIdFromPayload) {
unset($deserializationPayload['id']);
}
try {
/** @var T $entity */
$entity = $this->serializer->deserialize(
$request->getContent(),
$this->encodePayload($deserializationPayload),
$entityClass,
'json',
[
AbstractNormalizer::GROUPS => $writeGroups,
],
);
} catch (SerializerExceptionInterface $e) {
} catch (JsonException|SerializerExceptionInterface $e) {
return $this->jsonError('Ошибка десериализации: ' . $e->getMessage(), Response::HTTP_BAD_REQUEST);
}
// Id в группе :write не присутствует (чтобы запретить инъекцию при update).
// На create поддерживаем явный id из payload, потому что у контент-сущностей
// нет GeneratedValue (id приходит из Bitrix-view).
// По умолчанию публичный CRUD не принимает id от клиента. Если системной
// интеграции понадобится внешний id, конкретный вызов должен явно передать true.
if ($allowIdFromPayload && isset($payload['id']) && method_exists($entity, 'setId')) {
$id = (int) $payload['id'];
if ($id > 0) {
@@ -103,13 +107,15 @@ final class CrudResponder
array $writeGroups,
array $readGroups,
): JsonResponse {
if ($this->decodePayload($request) === null) {
$payload = $this->decodePayload($request);
if ($payload === null) {
return $this->jsonError('Ожидается JSON-объект в теле запроса', Response::HTTP_BAD_REQUEST);
}
unset($payload['id']);
try {
$this->serializer->deserialize(
$request->getContent(),
$this->encodePayload($payload),
$entity::class,
'json',
[
@@ -117,7 +123,7 @@ final class CrudResponder
AbstractNormalizer::OBJECT_TO_POPULATE => $entity,
],
);
} catch (SerializerExceptionInterface $e) {
} catch (JsonException|SerializerExceptionInterface $e) {
return $this->jsonError('Ошибка десериализации: ' . $e->getMessage(), Response::HTTP_BAD_REQUEST);
}
@@ -150,6 +156,16 @@ final class CrudResponder
}
}
/**
* @param array<string, mixed> $payload
*
* @throws JsonException
*/
private function encodePayload(array $payload): string
{
return json_encode($payload, JSON_THROW_ON_ERROR);
}
private function validate(object $entity): ?JsonResponse
{
$errors = $this->validator->validate($entity);