<?php
declare(strict_types=1);
namespace App\Point\Doctrine\Entity;
use ApiPlatform\Core\Annotation\ApiProperty;
use ApiPlatform\Core\Annotation\ApiResource;
use App\Point\Doctrine\Repository\TransferRepository;
use App\Program\Doctrine\Entity\Profile;
use DateTimeImmutable;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping\Column;
use Doctrine\ORM\Mapping\Entity;
use Doctrine\ORM\Mapping\GeneratedValue;
use Doctrine\ORM\Mapping\Id;
use Doctrine\ORM\Mapping\JoinColumn;
use Doctrine\ORM\Mapping\JoinTable;
use Doctrine\ORM\Mapping\ManyToMany;
use Doctrine\ORM\Mapping\ManyToOne;
use Doctrine\ORM\Mapping\Table;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints\Callback;
use Symfony\Component\Validator\Constraints\GreaterThan;
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Validator\Constraints\NotEqualTo;
use Symfony\Component\Validator\Constraints\NotNull;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
#[ApiResource(
collectionOperations: ['get', 'post'],
itemOperations: ['get' => ['security' => 'is_granted("item", object)']],
normalizationContext: ['groups' => ['read']],
denormalizationContext: ['groups' => ['write']]
)]
#[Entity(repositoryClass: TransferRepository::class)]
#[Table(name: '`point_transfer`')]
class Transfer
{
#[Id]
#[Column(type: 'integer')]
#[GeneratedValue]
#[Groups('read')]
private ?int $id = null;
#[Column(type: 'datetime_immutable')]
#[Groups('read')]
private DateTimeImmutable $createdAt;
/**
* @var Collection<int, Transaction>
*/
#[ManyToMany(targetEntity: Transaction::class, cascade: ['persist'])]
#[JoinTable(name: '`point_transfer_transactions`')]
#[Groups('read')]
#[ApiProperty(readableLink: false)]
private Collection $transactions;
#[Column(type: 'integer')]
#[NotBlank]
#[GreaterThan(0)]
#[Groups(['read', 'write'])]
private int $points = 0;
#[ManyToOne(targetEntity: Account::class)]
#[JoinColumn(nullable: false, onDelete: 'CASCADE')]
#[NotNull]
#[Groups(['read', 'write'])]
#[ApiProperty(readableLink: false, writableLink: false)]
private Account $from;
#[ManyToOne(targetEntity: Account::class)]
#[JoinColumn(nullable: false, onDelete: 'CASCADE')]
#[NotNull]
#[NotEqualTo(propertyPath: 'from', message: 'Vous ne pouvez pas transférer de l\'argent à la même personne.')]
#[Groups(['read', 'write'])]
#[ApiProperty(readableLink: false, writableLink: false)]
private Account $to;
#[Column(nullable: true)]
#[Groups(['read', 'write'])]
private ?string $comment = null;
#[ManyToOne(targetEntity: TransferType::class)]
#[JoinColumn(nullable: true, onDelete: 'CASCADE')]
#[Groups(['read', 'write'])]
#[ApiProperty(readableLink: false, writableLink: false)]
private ?TransferType $type = null;
public function __construct()
{
$this->createdAt = new DateTimeImmutable();
$this->transactions = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getCreatedAt(): DateTimeImmutable
{
return $this->createdAt;
}
/**
* @return Collection<int, Transaction>
*/
public function getTransactions(): ArrayCollection|Collection
{
return $this->transactions;
}
public function getPoints(): int
{
return $this->points;
}
public function setPoints(int $points): void
{
$this->points = $points;
}
public function getFrom(): Account
{
return $this->from;
}
public function setFrom(Account $from): void
{
$this->from = $from;
}
public function getTo(): Account
{
return $this->to;
}
public function setTo(Account $to): void
{
$this->to = $to;
}
#[Callback]
public function validate(ExecutionContextInterface $context): void
{
if ($this->from->getBalance() < $this->points) {
$context->buildViolation('Le nombre de points est supérieur au solde de points de l\'émetteur.')
->atPath('points')
->addViolation();
}
/** @var Profile $fromProfile */
$fromProfile = $this->from->getProfile();
/** @var Profile $toProfile */
$toProfile = $this->to->getProfile();
if ($fromProfile->getProgram() !== $toProfile->getProgram()) {
$context->buildViolation('Le destinataire n\'appartient pas au même programme que l\'émetteur.')
->atPath('to')
->addViolation();
}
}
public function getComment(): ?string
{
return $this->comment;
}
public function setComment(?string $comment): void
{
$this->comment = $comment;
}
public function getType(): ?TransferType
{
return $this->type;
}
public function setType(?TransferType $type): void
{
$this->type = $type;
}
}