Почему мои операции POST с подресурсом обновляют одну и ту же запись, а не создают новые?Php

Кемеровские программисты php общаются здесь
Ответить
Anonymous
 Почему мои операции POST с подресурсом обновляют одну и ту же запись, а не создают новые?

Сообщение Anonymous »

Мне не удается заставить операции POST подресурса работать должным образом в платформе API 4.1 с подресурсами; ресурсы верхнего уровня работают нормально.
Ожидается: при необходимости можно создавать новые подресурсы. Фактическое: можно создать только один подресурс; дополнительные попытки просто перезаписывают исходный подресурс.
Минимальный пример
У меня есть сущности User и UserEmail в отношении один-ко-многим:
User.php:

Код: Выделить всё

#[Groups(['user:read'])]
#[ORM\OneToMany(targetEntity: UserEmail::class, mappedBy: 'user', cascade: ['persist', 'remove'])]
private Collection $emails;
UserEmail.php:

Код: Выделить всё

#[ApiResource(
uriTemplate: '/users/{userUuid}/emails',
uriVariables: [
'userUuid' => new Link(fromClass: User::class, fromProperty: 'emails'),
],
operations: [
new Post(
normalizationContext: ['groups' => ['userEmail:read']],
security: "is_granted('ROLE_ADMIN') or (is_granted('ROLE_USER') and user.getUuid() == request.attributes.get('userUuid'))",
processor: UserEmailProcessor::class,
),
]
)]

#[ORM\Entity(repositoryClass: UserEmailRepository::class)]
#[ORM\Table(name: 'user_email')]
#[UniqueEntity(fields: ['email'], message: 'This email is already in use.')]
final class UserEmail
{
#[ApiProperty(identifier: false)]
#[ORM\Id]
#[ORM\GeneratedValue(strategy: 'SEQUENCE')]
#[ORM\Column(type: 'integer')]
private int $id;

#[ApiProperty(identifier: true)]
#[Assert\Uuid(versions: [4], groups: ['userEmail:read', 'userEmail:write'])]
#[Groups(['userEmail:read', 'user:read'])]
#[ORM\Column(type: 'string', length: 36, unique: true)]
private string $uuid;

#[ApiProperty]
#[Assert\NotBlank]
#[Assert\Regex(pattern: '/^\d+$/')]
#[Groups(['userEmail:read', 'userEmail:write', 'user:read'])]
#[ORM\Column(type: 'string', length: 20, unique: true)]
private string $email;

#[ApiProperty]
#[Groups(['userEmail:read'])]
#[ORM\ManyToOne(targetEntity: User::class, inversedBy: 'emails')]
#[ORM\JoinColumn(nullable: false)]
private User $user;

public function __construct(?UuidInterface $uuid = null)
{
$this->uuid = $uuid?->toString() ?? Uuid::uuid4()->toString();
}

// ...
}
Проблема
Запрос:

Код: Выделить всё

POST /users/00000000-0000-0000-0000-000000000001/emails
{
"email": "aaa@test.com"
}

Код: Выделить всё

{
"title": "An error occurred",
"detail": "An exception occurred while executing a query: SQLSTATE[23502]: Not null violation: 7 ERROR:  null value in column \"user_id\" of relation \"user_email\" violates not-null constraint\nDETAIL:  Failing row contains (1, 6b63235a-8c25-468c-881f-b4ce80618c56, 2222222, null).",
"status": 500,
"type": "/errors/500"
}

Код: Выделить всё

UserEmail::$user
не устанавливается из URI, как ожидалось. Однако я могу использовать процессор состояний, чтобы установить поле UserEmail::$user вручную. Я должен подключить этот процессор состояния к операции POST.
UserEmail.php:

Код: Выделить всё

#[ApiResource(
operations: new Post(
processor: UserEmailProcessor::class,
// ...
)
// ...
)]
UserEmailProcessor.php:

Код: Выделить всё

final readonly class UserEmailProcessor implements ProcessorInterface
{
public function __construct(
private EntityManagerInterface $entityManager,
private UserRepository $userRepository,
private RequestStack $requestStack,
) {
}

public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): mixed
{
if (!$data instanceof UserEmail) {
return $data;
}

$userUuid = $uriVariables['userUuid'] ?? null;

$user = $this->userRepository->findOneBy(['uuid' => $userUuid]);
if (!$user) {
throw new NotFoundHttpException();
}

$data->setUser($user);

$this->entityManager->persist($data);
$this->entityManager->flush();

return $data;
}
}
Теперь попробуйте тот же запрос:

Код: Выделить всё

POST /users/00000000-0000-0000-0000-000000000001/emails
{
"email": "aaa@test.com"
}

Код: Выделить всё

201 Created

Код: Выделить всё

{
"uuid": "988a50a6-f77f-47aa-b5de-eaa5029fb1f2",
"email": "aaa@test.com",
"user": "/users/00000000-0000-0000-0000-000000000001"
}
Это сработало! Еще раз с другим адресом электронной почты:

Код: Выделить всё

POST /users/00000000-0000-0000-0000-000000000001/emails
{
"email": "bbb@test.com"
}

Код: Выделить всё

201 Created

Код: Выделить всё

{
"uuid": "988a50a6-f77f-47aa-b5de-eaa5029fb1f2",
"email": "bbb@test.com",
"user": "/users/00000000-0000-0000-0000-000000000001"
}
Неверно. Я получил код ответа 201 Created, адрес электронной почты правильный. Однако UUID тот же самый. Предыдущий ресурс был обновлен или создан заново. Если я попробую это сделать с UUID другого пользователя, это сработает с первого раза, но последующие попытки покажут ту же проблему.


Подробнее здесь: https://stackoverflow.com/questions/797 ... ad-of-crea
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Php»