使用Symfony和API-Platform在存储到数据库之前修改POST数据

nhaq1z21  于 2022-11-16  发布在  其他
关注(0)|答案(1)|浏览(88)

我对Symfony的世界还很陌生,所以如果这个问题已经得到了回答,请耐心等待。
我已经为端点提供了api-platform以创建 RegistrationRequestRegistrationRequest 具有通过 ManyToOne 关系连接的用户,因此它存储在另一个表中。在API中,user或user_id是只读的,这就是无法在发布数据中设置用户的原因。如果通过API创建 RegistrationRequest,因为user_id显然是null
这就是为什么我希望在通过API发出注册请求后,但在将 RegistrationRequest 存储到数据库之前手动设置用户。
通过全局REMOTE_USER可以知道用户,我可以从全局REMOTE_USER派生相应的用户对象。
src/Entity/RegistrationRequest.php

<?php

namespace App\Entity;

use ApiPlatform\Core\Annotation\ApiResource;
use Symfony\Component\Serializer\Annotation\Groups;
use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity(repositoryClass=App\Repository\RegistrationRequestRepository::class)
 * @ApiResource(
 *   normalizationContext={"groups" = {"read"}},
 *   denormalizationContext={"groups" = {"write"}},
 *   paginationEnabled=false,
 * )
 */
class RegistrationRequest
{
  /**
   * @ORM\Id
   * @ORM\GeneratedValue
   * @ORM\Column(type="integer")
   * @Groups({"read"})
   */
  private $id;

  /**
   * @ORM\Column(type="string", length=64, nullable=true)
   * @Groups({"read", "write"})
   */
  private $opt_email;

  /**
   * @ORM\Column(type="string", length=255, nullable=true)
   * @Groups({"read", "write"})
   */
  private $title;

  /**
   * @Gedmo\Mapping\Annotation\Timestampable(on="create")
   * @ORM\Column(type="datetime")
   * @Groups({"read"})
   */
  private $created_at;

  /**
   * @Gedmo\Mapping\Annotation\Timestampable(on="update")
   * @ORM\Column(type="datetime")
   * @Groups({"read"})
   */
  private $updated_at;

  /**
   * @ORM\Column(type="text", nullable=true)
   * @Groups({"read", "write"})
   */
  private $notes;

  /**
   * @ORM\Column(type="string", length=16)
   * @Groups({"read", "write"})
   */
  private $language_code;

  /**
   * @ORM\Column(type="text")
   * @Groups({"read", "write"})
   */
  private $data;

  /**
   * @ORM\ManyToOne(targetEntity=User::class, inversedBy="registrationRequests")
   * @ORM\JoinColumn(nullable=false)
   */
  private $user;

  public function getId(): ?int
  {
    return $this->id;
  }

  public function getOptEmail(): ?string
  {
    return $this->opt_email;
  }

  public function setOptEmail(?string $opt_email): self
  {
    $this->opt_email = $opt_email;

    return $this;
  }

  public function getTitle(): ?string
  {
    return $this->title;
  }

  public function setTitle(?string $title): self
  {
    $this->title = $title;

    return $this;
  }

  public function getCreatedAt(): ?\DateTimeInterface
  {
    return $this->created_at;
  }

  public function setCreatedAt(\DateTimeInterface $created_at): self
  {
    $this->created_at = $created_at;

    return $this;
  }

  public function getUpdatedAt(): ?\DateTimeInterface
  {
    return $this->updated_at;
  }

  public function setUpdatedAt(\DateTimeInterface $updated_at): self
  {
    $this->updated_at = $updated_at;

    return $this;
  }

  public function getNotes(): ?string
  {
    return $this->notes;
  }

  public function setNotes(?string $notes): self
  {
    $this->notes = $notes;

    return $this;
  }

  public function getLanguageCode(): ?string
  {
    return $this->language_code;
  }

  public function setLanguageCode(string $language_code): self
  {
    $this->language_code = $language_code;

    return $this;
  }

  public function getData(): ?string
  {
    return $this->data;
  }

  public function setData(string $data): self
  {
    $this->data = $data;

    return $this;
  }

  public function getUser(): ?User
  {
      return $this->user;
  }

  public function setUser(?User $user): self
  {
      $this->user = $user;

      return $this;
  }

}

src/Controller/RegistrationRequestController.php

<?php

namespace App\Controller;

use App\Service\IGSNService;
use App\Entity\RegistrationRequest;
use App\Form\RegistrationRequestType;
use App\Repository\RegistrationRequestRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Contracts\Translation\TranslatorInterface;

/**
 * @Route("/registration_request")
 */
class RegistrationRequestController extends AbstractController
{
  
  /**
   * @Route("/")
   */
    public function indexNoLocale(): Response
    {
        return $this->redirectToRoute('app_registration_request_index', ['_locale' => 'de']);
    }

  /**
   * @Route("/{_locale<%app.supported_locales%>}/", name="app_registration_request_index", methods={"GET"})
   */
  public function index(RegistrationRequestRepository $registrationRequestRepository): Response
  {
    return $this->render('registration_request/index.html.twig', [
      'registration_requests' => $registrationRequestRepository->findAll(),
    ]);
  }

  /**
   * @Route("/{_locale<%app.supported_locales%>}/new", name="app_registration_request_new", methods={"GET", "POST"})
   */
  public function new(Request $request, RegistrationRequestRepository $registrationRequestRepository, IGSNService $igsnService, TranslatorInterface $translator): Response
  {
    $registrationRequest = new RegistrationRequest();
    $form = $this->createForm(RegistrationRequestType::class, $registrationRequest);
    $form->handleRequest($request);

    if ($form->isSubmitted() && $form->isValid()) {
      $json_data = json_decode($registrationRequest->getData());
      $err = $igsnService->validate_data($json_data);
      if ($json_data !== null && empty($err)) {
        $registrationRequestRepository->add($registrationRequest, true);

        $this->addFlash(
          'success',
          $translator->trans('Your changes were saved!')
        );

        return $this->redirectToRoute('app_registration_request_index', [], Response::HTTP_SEE_OTHER);
      } else {
        $this->addFlash(
          'schema_error',
          $err
        );
      }
    }

    return $this->renderForm('registration_request/new.html.twig', [
      'registration_request' => $registrationRequest,
      'form' => $form,
    ]);
  }

  /**
   * @Route("/{_locale<%app.supported_locales%>}/{id}", name="app_registration_request_show", methods={"GET"})
   */
  public function show(RegistrationRequest $registrationRequest): Response
  {
    return $this->render('registration_request/show.html.twig', [
      'registration_request' => $registrationRequest,
    ]);
  }

  /**
   * @Route("/{_locale<%app.supported_locales%>}/{id}/edit", name="app_registration_request_edit", methods={"GET", "POST"})
   */
  public function edit(Request $request, RegistrationRequest $registrationRequest, RegistrationRequestRepository $registrationRequestRepository, IGSNService $igsnService, TranslatorInterface $translator): Response
  {
    $form = $this->createForm(RegistrationRequestType::class, $registrationRequest);
    $form->handleRequest($request);

    if ($form->isSubmitted() && $form->isValid()) {
      $json_data = json_decode($registrationRequest->getData());
      $err = $igsnService->validate_data($json_data);
      if ($json_data !== null && empty($err)) {
        $registrationRequestRepository->add($registrationRequest, true);

        $this->addFlash(
          'success',
          $translator->trans('Your changes were saved!')
        );

        return $this->redirectToRoute('app_registration_request_index', [], Response::HTTP_SEE_OTHER);
      } else {
        $this->addFlash(
          'schema_error',
          $err
        );
      }
    }

    return $this->renderForm('registration_request/edit.html.twig', [
      'registration_request' => $registrationRequest,
      'form' => $form,
    ]);
  }

  /**
   * @Route("/{_locale<%app.supported_locales%>}/{id}", name="app_registration_request_delete", methods={"POST"})
   */
  public function delete(Request $request, RegistrationRequest $registrationRequest, RegistrationRequestRepository $registrationRequestRepository, TranslatorInterface $translator): Response
  {
    if ($this->isCsrfTokenValid('delete' . $registrationRequest->getId(), $request->request->get('_token'))) {
      $registrationRequestRepository->remove($registrationRequest, true);
      $this->addFlash(
        'success',
        $translator->trans('Request successfully deleted!')
      );
    }

    return $this->redirectToRoute('app_registration_request_index', [], Response::HTTP_SEE_OTHER);
  }
}

config/packages/api_platform.yaml

api_platform:
    mapping:
        paths: ['%kernel.project_dir%/src/Entity']
    patch_formats:
        json: ['application/merge-patch+json']
    swagger:
        versions: [3]
    # Fixes empty api endpoint list with error:
    # No operations defined in spec!
    # See https://github.com/api-platform/core/issues/4485
    metadata_backward_compatibility_layer: false
sg24os4d

sg24os4d1#

我现在已经用DataPersister解决了这个问题,就像Julien B.在评论中建议的那样。

namespace App\DataPersister;

use ApiPlatform\Core\DataPersister\DataPersisterInterface;
use App\Entity\RegistrationRequest;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Security\Core\Security;

final class RequestDataPersister implements DataPersisterInterface
{

  private $security;

  public function __construct(Security $security, EntityManagerInterface $entityManager)
  {
    $this->entityManager = $entityManager;
    $this->security = $security;
  }

  public function supports($data): bool
  {
    return $data instanceof RegistrationRequest;
  }

  public function persist($data)
  {

    $data->setUser($this->security->getUser());

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

    return $data;
  }

  public function remove($data): void
  {
    // no action needed
  }
}

相关问题