youstra
youstra

Reputation: 113

Persist releted resource fields using api-platform

I'm using API-Platform for a projetc. And in this project, I have two resources (Donateur and Don) releted by a ManyToOne relation. One Don is releted to One Donateur and One Donateur can be releted to more Dons. I have a data persister which persists resources in database.

Donateur.php

<?php

namespace App\Entity;

use ApiPlatform\Core\Annotation\ApiResource;
use App\Repository\DonateurRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups;

/**
 * @ApiResource(
 *      normalizationContext={
 *          "groups"={
 *              "read:Donateur:collection"
 *          }
 *      },
 *      denormalizationContext={
 *          "groups"={
 *              "write:Donateur"
 *          }
 *      },
 *      collectionOperations={
 *          "get", "post"
 *      },
 *      itemOperations={
 *          "get", "patch", "delete"
 *      }
 * )
 * @ORM\Entity(repositoryClass=DonateurRepository::class)
 */
class Donateur
{
    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     * @Groups("read:Donateur:collection")
     */
    private $id;

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

    /**
     * @ORM\Column(type="float")
     * @Groups({"read:Donateur:collection", "write:Don"})
     */
    private $solde;

    /**
     * @ORM\OneToMany(targetEntity=Don::class, mappedBy="donateur")
     */
    private $dons;

Don.php

<?php

namespace App\Entity;

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

/**
 * @ApiResource(
 *      normalizationContext={
 *          "groups"={
 *              "read:Don:item",
 *              "read:Don:collection"
 *          }
 *      },
 *      denormalizationContext={
 *          "groups"={
 *              "write:Don"
 *          }
 *      },
 *      collectionOperations={
 *          "get", "post"
 *      },
 *      itemOperations={
 *          "get"={
 *              "normalization_context"={
 *                  "groups"={
 *                      "read:Don:item",
 *                      "read:Don:collection"
 *                  }
 *              }
 *          }, 
 *          "patch", "delete"
 *      }
 * )
 * @ORM\Entity(repositoryClass=DonRepository::class)
 */
class Don
{
    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\ManyToOne(targetEntity=Donateur::class, inversedBy="dons")
     * @ORM\JoinColumn(nullable=false)
     * @Groups({"read:Don:collection", "write:Don"})
     */
    private $donateur;

    /**
     * @ORM\Column(type="date", nullable=true)
     * @Groups({"read:Don:collection", "write:Don"})
     */
    private $date;

    /**
     * @ORM\Column(type="float")
     * @Groups({"read:Don:collection", "write:Don"})
     */
    private $montant;

The property $solde in Donateur must increase when we save a new Don. And the value which must be added is value of $montant of Don resource.

When I try this code

<?php

namespace App\EventListener;

use ApiPlatform\Core\EventListener\EventPriorities;
use App\Entity\Don;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\ViewEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Security\Core\Security;

class UpdateSoldeDonateurSubscriber implements EventSubscriberInterface
{
    private $security;

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


    public static function getSubscribedEvents()
    {
        return [
            KernelEvents::VIEW => ["updateSoldeDonateur", EventPriorities::POST_WRITE]
        ];
    }


    public function updateSoldeDonateur(ViewEvent $event)
    {
        $data   = $event->getControllerResult();
        $method = $event->getRequest()->getMethod();
        $user   = $this->security->getUser();

        //On va mettre à jour le solde du donateur. On récupère d'abord l'ancien solde puis on y ajoute le nouveau
        if($data instanceof Don){
            $ancienSolde  = $data->getDonateur()->getSolde();
            $nouveauSolde = $ancienSolde + $data->getMontant();
            if($method === 'POST'){
                $data->getDonateur()->setSolde($nouveauSolde);
            }
            elseif($method === 'PATCH'){
            }
            // dd($data->getDonateur(), $ancienSolde, $nouveauSolde);
        }
    }
}

solde didn't change. I think that it is caused by the data persister but I don't know how can I fix it.

These are my datapersisters

<?php

namespace App\DataPersister;

use ApiPlatform\Core\DataPersister\ContextAwareDataPersisterInterface;
use App\Entity\Donateur;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Security\Core\Security;

class DonateurDataPersister implements ContextAwareDataPersisterInterface
{
    private $manager;
    private $security;
    
    public function __construct(EntityManagerInterface $manager, Security $security)
    {
        $this->manager = $manager;
        $this->security = $security;
    }


    public function supports($data, array $context = []): bool
    {
        return $data instanceof Donateur;
    }

    public function persist($data, array $context = [])
    {
        $this->manager->persist($data);
        $this->manager->flush();

        return $data;
    }

    public function remove($data, array $context = [])
    {
        $data->setIsDeleted(true);
        $data->setDeletedBy($this->security->getUser());
        $data->setDeletedAt(new \DateTime());
        $this->manager->flush();
    }
}
<?php

namespace App\DataPersister;

use ApiPlatform\Core\DataPersister\ContextAwareDataPersisterInterface;
use App\Entity\Don;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Security\Core\Security;

class DonDataPersister implements ContextAwareDataPersisterInterface
{
    private $manager;
    private $security;
    
    public function __construct(EntityManagerInterface $manager, Security $security)
    {
        $this->manager  = $manager;
        $this->security = $security;
    }


    public function supports($data, array $context = []): bool
    {
        return $data instanceof Don;
    }

    public function persist($data, array $context = [])
    {
        $this->manager->persist($data);
        $this->manager->flush();

        return $data;
    }

    public function remove($data, array $context = [])
    {
        $data->setIsDeleted(true);
        $data->setDeletedBy($this->security->getUser());
        $data->setDeletedAt(new \DateTime());
        $this->manager->flush();
    }
}

Some ideas to help me please

Upvotes: 0

Views: 570

Answers (1)

Evgeny Ruban
Evgeny Ruban

Reputation: 1443

Your subscriber have been called after writing to the database and you should to flush after making changes in it or use another event that called before writing (PRE_WRITE, in example), as I mentioned in the comment.

Upvotes: 1

Related Questions