Ожидается: при необходимости можно создавать новые подресурсы. Фактическое: можно создать только один подресурс; дополнительные попытки просто перезаписывают исходный подресурс.
Минимальный пример
У меня есть сущности User и UserEmail в отношении один-ко-многим:
User.php:
Код: Выделить всё
#[Groups(['user:read'])]
#[ORM\OneToMany(targetEntity: UserEmail::class, mappedBy: 'user', cascade: ['persist', 'remove'])]
private Collection $emails;
Код: Выделить всё
#[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::$userUserEmail.php:
Код: Выделить всё
#[ApiResource(
operations: new Post(
processor: UserEmailProcessor::class,
// ...
)
// ...
)]
Код: Выделить всё
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"
}
Подробнее здесь: https://stackoverflow.com/questions/797 ... ad-of-crea
Мобильная версия