首页 > 解决方案 > DataPersister 未在“PUT”操作时累加数量

问题描述

我是 API 平台的新手。目前,我正面临来自 API 平台的“PUT”操作问题。

我有两个实体。一个是用户实体,另一个是信用实体。他们的关系是一对多的关系。我有一个 DataPersister,我参考并遵循本文档(https://api-platform.com/docs/core/data-persisters/)。所以,坚持,我想做一些业务逻辑。所以现在的问题是当我更新信用时。它应该添加当前值+请求的信用额度,而不是直接添加请求的信用额度。例如,假设我在贷方表中有 100 美元的金额。当我尝试再添加 50 美元时,它应该是 150,但相反,它只存储为 50 美元。

下面是我的用户实体

<?php

namespace App\Entity;

use ApiPlatform\Core\Annotation\ApiResource;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Serializer\Annotation\SerializedName;
use Gedmo\Mapping\Annotation as Gedmo;


/**
 * @ApiResource(
 *     collectionOperations={
 *       "get" ,
 *       "post",
 *        "app_login"={
 *              "route_name"="app_login",
 *              "method"="POST",
 *               "swagger_context" = {
 *                  "parameters" = {
 *                      {
 *                          "name" = "User Login",
 *                          "in" = "body",
 *                          "type" = "object",
 *                          "schema"= {
 *                                   "email" = {"type": "string"},
 *                                   "password" = {"type" : "string"},
 *                                    "example" ={
 *                                              "email" = "string",
 *                                              "password" ="string"
 *                                              }
 *                          }
 *                      }
 *                  },
 *                  "responses" = {
 *                      "200" = {
 *                          "description" = "You will get User IRI and PHPSESSID",
 *                          "schema" =  {
 *                              "type" = "object",
 *                              "required" = {
 *                                  "email",
 *                                  "password"
 *                              },
 *                              "properties" = {
 *                                   "user" = {
 *                                      "type" = "string"
 *                                   },
 *                                   "PHPSESSID" = {
 *                                      "type" = "string"
 *                                   },
 *
 *                              }
 *                          }
 *                      },
 *                      "400" = {
 *                          "description" = "Bad Requests"
 *                      }
 *                  },
 *                  "summary" = "User Login",
 *                  "description" = "Set User session to api platform by email and password",
 *                  "consumes" = {
 *                      "application/json",
 *                      "text/html",
 *                   },
 *                  "produces" = {
 *                      "application/json",
 *                      "application/ld+json"
 *                   }
 *              }
 *          }
 *     },
 *     itemOperations={
 *              "get" ={
 *                    "normalization_context"={"groups"={"user:item:get"}}
 *                      },
 *              "put" = {
 *                      "swagger_context" ={
 *                          "summary" = "Update username details and credit items"
 *                      }
 *
 *        }
 *     },
 *     normalizationContext={"groups"={"user:read"}},
 *     denormalizationContext={"groups"={"user:write"}},
 *     shortName="User"
 *
 * )
 * @UniqueEntity(fields={"email"})
 * @UniqueEntity(fields={"contact"})
 * @ORM\Entity(repositoryClass="App\Repository\UserRepository")
 */
class User implements UserInterface
{

    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @Groups({"user:read", "user:write"})
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=180, unique=true)
     * @Groups({"user:read", "user:write", "user:item:get", "credit:item:get"})
     * @Assert\Email()
     * @Assert\NotBlank()
     */
    private $email;

    /**
     * @ORM\Column(type="json")
     */
    private $roles = [];

    /**
     * @var string The hashed password
     * @ORM\Column(type="string")
     */
    private $password;

    /**
     * @Groups("user:write")
     * @SerializedName("password")
     * @Assert\NotBlank(groups={"create"})
     */
    private $plainPassword;

    /**
     * @ORM\Column(type="string", length=255)
     * @Groups({"user:read", "user:write"})
     * @Assert\NotBlank()
     */
    private $firstName;

    /**
     * @ORM\Column(type="string", length=255)
     * @Groups({"user:read", "user:write"})
     * @Assert\NotBlank()
     */
    private $lastName;

    /**
     * @var string provide in YYYY-MM-DD (neglect Time)
     * @ORM\Column(type="date")
     * @Groups({"user:read", "user:write"})
     * @Assert\NotBlank()
     */
    private $dob;

    /**
     * @ORM\Column(type="text")
     * @Groups({"user:read", "user:write"})
     * @Assert\NotBlank()
     */
    private $address;

    /**
     * @ORM\Column(type="string", length=255)
     * @Groups({"user:read", "user:write"})
     * @Assert\NotBlank()
     * @Assert\Length(
     *     min=8,
     *     max=8,
     *     maxMessage="contact number must have 8 character",
     *     minMessage="contact number must have 8 character"
     * )
     */
    private $contact;

    /**
     * @ORM\OneToMany(targetEntity="App\Entity\Credit", mappedBy="user", cascade={"persist"}, orphanRemoval=true)
     * @Groups({"user:read", "user:write"})
     * @Assert\Valid()
     */
    private $credits;


    /**
     * @var \DateTime $created
     *
     * @Gedmo\Timestampable(on="create")
     * @ORM\Column(type="datetime")
     */
    private $created_at;

    /**
     * @var \DateTime $updated
     *
     * @Gedmo\Timestampable(on="update")
     * @ORM\Column(type="datetime")
     */
    private $updated_at;


    public function __construct()
    {
        $this->credits = new ArrayCollection();
    }

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

    public function getEmail(): ?string
    {
        return $this->email;
    }

    public function setEmail(string $email): self
    {
        $this->email = $email;

        return $this;
    }

    /**
     * A visual identifier that represents this user.
     *
     * @see UserInterface
     */
    public function getUsername(): string
    {
        return (string) $this->email;
    }

    /**
     * @see UserInterface
     */
    public function getRoles(): array
    {
        $roles = $this->roles;
        // guarantee every user at least has ROLE_USER
        $roles[] = 'ROLE_USER';

        return array_unique($roles);
    }

    public function setRoles(array $roles): self
    {
        $this->roles = $roles;

        return $this;
    }

    /**
     * @see UserInterface
     */
    public function getPassword(): string
    {
        return (string) $this->password;
    }

    public function setPassword(string $password): self
    {
        $this->password = $password;
        return $this;
    }

    /**
     * @see UserInterface
     */
    public function getSalt()
    {
        // not needed when using the "bcrypt" algorithm in security.yaml
    }

    /**
     * @see UserInterface
     */
    public function eraseCredentials()
    {
        // If you store any temporary, sensitive data on the user, clear it here
        // $this->plainPassword = null;
    }

    public function getFirstName(): ?string
    {
        return $this->firstName;
    }

    public function setFirstName(string $firstName): self
    {
        $this->firstName = $firstName;

        return $this;
    }

    public function getLastName(): ?string
    {
        return $this->lastName;
    }

    public function setLastName(string $lastName): self
    {
        $this->lastName = $lastName;

        return $this;
    }

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

    public function setDob(\DateTimeInterface $dob): self
    {
        $this->dob = $dob;

        return $this;
    }

    public function getAddress(): ?string
    {
        return $this->address;
    }

    public function setAddress(string $address): self
    {
        $this->address = $address;

        return $this;
    }

    public function getContact(): ?string
    {
        return $this->contact;
    }

    public function setContact(string $contact): self
    {
        $this->contact = $contact;

        return $this;
    }

    /**
     * @return Collection|Credit[]
     */
    public function getCredits(): Collection
    {
        return $this->credits;
    }

    public function addCredit(Credit $credit): self
    {
        if (!$this->credits->contains($credit)) {
            $this->credits[] = $credit;
            $credit->setUser($this);
        }

        return $this;
    }

    public function removeCredit(Credit $credit): self
    {
        if ($this->credits->contains($credit)) {
            $this->credits->removeElement($credit);
            // set the owning side to null (unless already changed)
            if ($credit->getUser() === $this) {
                $credit->setUser(null);
            }
        }

        return $this;
    }

    public function getPlainPassword(): ?string
    {
        return $this->plainPassword;
    }

    public function setPlainPassword(string $plainPassword): self
    {
        $this->plainPassword = $plainPassword;

        return $this;
    }


    public function getCreated()
    {
        return $this->created_at;
    }

    public function getUpdated()
    {
        return $this->updated_at;
    }
}

这是我的信用实体

<?php

namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiResource;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * @ApiResource(
 *     collectionOperations={
 *          "get" ={
 *              "normalization_context"={"groups"={"credit:read", "credit:item:get"}},
 *          }
 *          },
 *     itemOperations={
 *          "get"
 *     },
 *      shortName="credits",
 *     normalizationContext={"groups"={"credit:read"}, "swagger_definition_name"="Read"},
 *     denormalizationContext={"groups"={"credit:write"}, "swagger_definition_name"="Write"},
 * )
 * @ORM\Entity(repositoryClass="App\Repository\CreditRepository")
 */
class Credit
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\ManyToOne(targetEntity="App\Entity\User", inversedBy="credits")
     * @ORM\JoinColumn(nullable=false)
     * @Groups({"credit:read", "credit:write"})
     * @Assert\Valid()
     */
    private $user;


    /**
     * @ORM\Column(type="string", length=255)
     * @Groups({ "user:read", "user:write", "credit:read", "credit:write"})
     */
    private $amount;


    /**
     * @var \DateTime $created
     *
     * @Gedmo\Timestampable(on="create")
     * @ORM\Column(type="datetime")
     */
    private $created_at;

    /**
     * @var \DateTime $updated
     *
     * @Gedmo\Timestampable(on="update")
     * @ORM\Column(type="datetime")
     */
    private $updated_at;


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

    public function getAmount(): ?string
    {
        return $this->amount;
    }

    public function setAmount(string $amount): self
    {
        $this->amount = $amount;

        return $this;
    }

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

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

        return $this;
    }

    public function getCreated()
    {
        return $this->created_at;
    }

    public function getUpdated()
    {
        return $this->updated_at;
    }

}

这是我的 UserDataPersister

<?php

    namespace App\DataPersister;

    use ApiPlatform\Core\DataPersister\DataPersisterInterface;
    use App\Entity\Credit;
    use App\Entity\User;
    use App\Managers\EmailManager;
    use Doctrine\ORM\EntityManagerInterface;
    use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;

    class UserDataPersister implements DataPersisterInterface
    {
        private $entityManager;
        private $userPasswordEncoder;
        private $emailManager;

        public function __construct(EntityManagerInterface $entityManager, UserPasswordEncoderInterface $userPasswordEncoder, EmailManager $emailManager  )
        {
            $this->entityManager        = $entityManager;
            $this->userPasswordEncoder  = $userPasswordEncoder;
            $this->emailManager         = $emailManager;
        }

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

        /**
         * @param User $data
         */
        public function persist($data)
        {

            //encrypt password
            if ($data->getPlainPassword()) {
                $data->setPassword(
                    $this->userPasswordEncoder->encodePassword($data, $data->getPlainPassword())
                );
                $data->eraseCredentials();
            }

            $creditArray = $data->getCredits();

            $creditAmt = 0;
            foreach ( $creditArray  as $credit ) {
                $creditAmt  = $credit->getAmount();
            }


            //credit top up detection
            if($creditAmt !==0){

                $creditRepo       =  $this->entityManager->getRepository(Credit::class);
                $currentCredit    =  $creditRepo->findAmountByUserId($data->getId());
                $currentCreditAmt =  $currentCredit->getAmount();
                $topupAmt         =  $currentCreditAmt + $creditAmt;
                $currentCredit    -> setAmount($topupAmt);

                //update entity
                $this->entityManager->persist($currentCredit);

                //send email
                //$this->emailManager->sendCreditTopupNotification($data);
            }else{
                //set credit to zero
                $creditEntity = new Credit();
                $creditEntity ->setAmount(0);
                $data->addCredit($creditEntity);

                //send registration email
                //$this->emailManager->sendRegisterNotification($data);
            }

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

        public function remove($data)
        {
            $this->entityManager->remove($data);
            $this->entityManager->flush();
        }
    }

我相信问题来自 UserDataPersister 的这个会话

        //credit top up detection
            if($creditAmt !==0){

                $creditRepo       =  $this->entityManager->getRepository(Credit::class);
                $currentCredit    =  $creditRepo->findAmountByUserId($data->getId());
                $currentCreditAmt =  $currentCredit->getAmount();
                $topupAmt         =  $currentCreditAmt + $creditAmt;
                $currentCredit    -> setAmount($topupAmt);

                //update entity
                $this->entityManager->persist($currentCredit);

                //send email
                //$this->emailManager->sendCreditTopupNotification($data);
            }else{
                //set credit to zero
                $creditEntity = new Credit();
                $creditEntity ->setAmount(0);
                $data->addCredit($creditEntity);

                //send registration email
                //$this->emailManager->sendRegisterNotification($data);
            }

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

当 API 被称为“PUT”操作时,我该如何实现,其中包含积分的金额(已实现)并添加当前金额 + API 请求的金额?提前致谢。

标签: phpsymfonyswaggersymfony4api-platform.com

解决方案


我很确定您正在尝试对数组中的所有学分求和,但您只是在$creditAmt这里使用最后一个元素的值:

$creditAmt = 0;
foreach ( $creditArray  as $credit ) {
    $creditAmt = $credit->getAmount();
}

这应该是:

$creditAmt = 0;
foreach ( $creditArray  as $credit ) {
    $creditAmt = $creditAmt + $credit->getAmount();
}

此外,如果您$creditArray是空的,您将有$creditAmt = 0;这解释为什么您没有看到任何添加的信用。确保$data->getCredits()确实拥有您要总结的“功劳”!


推荐阅读