Symfony API Platform Subresource post/put Operations не работает, как ожидалосьPhp

Кемеровские программисты php общаются здесь
Ответить
Anonymous
 Symfony API Platform Subresource post/put Operations не работает, как ожидалось

Сообщение Anonymous »

Я не могу получить операции Subresource Write (, положить ) Работать на платформе API 4.1.
Я проведу вас по шагам по шагам. Однако, чтобы суммировать заранее, ниже приведены ожидаемые поведения, а также фактические результаты:
post
  • Ожидаемый: новые подрасунки могут быть созданы ad Infinitum . Дополнительные попытки просто перезаписать исходный Subresource.
put
  • Ожидаемый Однажды .
минимальный пример
Предположим, что у нас есть две сущности: пользователь и usermail в отношениях one-to-many, как так:
/>

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

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

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

#[ApiResource(
uriTemplate: '/users/{userUuid}/emails/{uuid}',
uriVariables: [
'userUuid' => new Link(fromClass: User::class, fromProperty: 'emails'),
'uuid' => new Link(fromClass: UserEmail::class),
],
operations: [
new Get(
normalizationContext: ['groups' => ['userEmail:read']],
security: "is_granted('ROLE_ADMIN') or (is_granted('ROLE_USER') and user.getUuid() == request.attributes.get('userUuid'))",
),
new Put(
normalizationContext: ['groups' => ['userEmail:read']],
security: "is_granted('ROLE_ADMIN') or (is_granted('ROLE_USER') and user.getUuid() == request.attributes.get('userUuid'))",
processor: UserEmailProcessor::class,
allowCreate: true,
),
new Delete(
security: "is_granted('ROLE_ADMIN') or (is_granted('ROLE_USER') and user.getUuid() == request.attributes.get('userUuid'))",
),
]
)]
#[ApiResource(
uriTemplate: '/users/{userUuid}/emails',
uriVariables: [
'userUuid' => new Link(fromClass: User::class, fromProperty: 'emails'),
],
extraProperties: [
'standard_put' => true,
],
operations: [
new GetCollection(
normalizationContext: ['groups' => ['userEmail:read']],
security: "is_granted('ROLE_ADMIN') or (is_granted('ROLE_USER') and user.getUuid() == request.attributes.get('userUuid'))",
),
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,
),
]
)]
// @formatter:on

#[ORM\Entity(repositoryClass: UserEmailRepository::class)]
#[ORM\Table(name: 'user_email')]
#[UniqueEntity(fields: ['emailNumber'], message: 'This email number 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\Email]
#[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
Во-первых, давайте обсудим post .

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

POST /users/00000000-0000-0000-0000-000000000001/emails
{
"email": "aaa@test.com"
}
< /code>
{
"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"
}
< /code>
UserEmail::$user
не устанавливается из URI, как и ожидалось. Мы должны прикрепить этот процессор состояния к операции post .

Вопрос № 1
Это то, что мы можем решить без . /> useremail.php

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

#[ApiResource(
operations: new Post(
processor: UserEmailProcessor::class,
// ...
)
// ...
)]
< /code>
[b]UserEmailProcessor.php[/b]
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;
}
}
< /code>
Now let's try the same request as before:
POST /users/00000000-0000-0000-0000-000000000001/emails
{
"email": "aaa@test.com"
}
< /code>
[b]201 Created[/b]
{
"uuid": "988a50a6-f77f-47aa-b5de-eaa5029fb1f2",
"email": "aaa@test.com",
"user": "/users/00000000-0000-0000-0000-000000000001"
}
< /code>
It worked! Let's test it one more time with a different email:
POST /users/00000000-0000-0000-0000-000000000001/emails
{
"email": "bbb@test.com"
}
< /code>
[b]201 Created[/b]
{
"uuid": "988a50a6-f77f-47aa-b5de-eaa5029fb1f2",
"email": "bbb@test.com",
"user": "/users/00000000-0000-0000-0000-000000000001"
}
< /code>
[b]WRONG[/b]. We received a 201 Created
код ответа и электронная почта верны. Тем не менее, Uuid то же самое. Предыдущий ресурс был обновлен или воссозданный . Обратите внимание, что если мы попробуем это с помощью другого пользователя Uuid, это также будет работать в первый раз, но последующие попытки покажут ту же проблему. /> plot
В прошлом операция Put Platform Platform была печально известна тем, что имело неправильное поведение, функционируя аналогично Patch . Однако с платформой API 4.0, эти проблемы якобы решаются.
Попробуем запрос put .

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

PUT /users/00000000-0000-0000-0000-000000000001/emails/cccccccc-cccc-cccc-cccc-cccccccccccc
{
"email": "ccc@test.com"
}
< /code>
{
"uuid": "b797c3fd-2d31-4452-8aaa-b87a0644cc28",
"email": "ccc@test.com",
"user": "/users/00000000-0000-0000-0000-000000000001"
}
< /code>
The email was created.  However, the UUID is incorrect (and by extension, so is the IRI).
Let's try it again.
PUT /users/00000000-0000-0000-0000-000000000001/emails/dddddddd-dddd-dddd-dddd-dddddddddddd
{
"email": "ddd@test.com"
}
< /code>
{
"uuid": "92bde1cf-d103-406c-895d-9e96393089f6",
"email": "ddd@test.com",
"user": "/users/00000000-0000-0000-0000-000000000001"
}
< /code>
The same issue occurred. However, the UUID is different! That means PUT
ведет себя как мы ожидали, что Post изначально. Поскольку у нас уже есть государственный процессор из ранее, давайте обновим его следующим образом:

Вопрос № 3
снова - это то, что мы можем решить без . /> useremail.php

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

#[ApiResource(
operations: new Put(
processor: UserEmailProcessor::class,
// ...
)
// ...
)]
< /code>
[b]UserEmailProcessor.php[/b]
// For PUT operations, ensure the UUID from the URI is used
if ($operation instanceof Put) {
$emailUuid = $uriVariables['uuid'] ?? null;
if ($emailUuid && $data->getUuid() !== $emailUuid) {
$data->setUuid($emailUuid);
}
}
< /code>
Here, we are manually setting the UUID in the state processor. I don't like having setters for my identifiers, but we'll ignore that for now. Let's try a request:
PUT /users/00000000-0000-0000-0000-000000000001/emails/eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee
{
"email": "eee@test.com"
}
< /code>
{
"uuid": "eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee",
"email": "eee@test.com",
"user": "/users/00000000-0000-0000-0000-000000000001"
}
< /code>
It worked! This is exactly what we expected to see. Now let's try replacing that same resource with a different email:
PUT /users/00000000-0000-0000-0000-000000000001/emails/eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee
{
"email": "eee.updated@test.com"
}
< /code>
{
"title": "An error occurred",
"detail": "An exception occurred while executing a query: SQLSTATE[23505]: Unique violation: 7 ERROR:  duplicate key value violates unique constraint \"uniq_a68d6c85d17f50a6\"\nDETAIL:  Key (uuid)=(eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee) already exists.",
"status": 500,
"type": "/errors/500"
}
< /code>
Yet another problem. PUT
не обновляет существующие строки базы данных, не удаляет и не заполняет их. Вместо этого он просто пытается создать новую строку с указанным UUID.

Вопрос № 4
еще раз - что вызывает это, и как мы решаем?>

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

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

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

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

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

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