feat: soft-delete for teamer accounts

addresses #869dv9br3
This commit is contained in:
Björn Fromme
2026-08-11 12:26:13 +02:00
parent 388ecf9603
commit d654ce77fb
45 changed files with 1151 additions and 7 deletions
+1 -1
View File
@@ -6,5 +6,5 @@ interface SoftDeletableEntityInterface
{
public function getDeletedAt(): ?\DateTimeImmutable;
public function setDeletedAt(\DateTimeImmutable $createdAt): static;
public function setDeletedAt(?\DateTimeImmutable $deletedAt): static;
}
+3 -1
View File
@@ -6,6 +6,7 @@ use App\BusProNet\Model\ProfileResponse;
use App\Entity\Embeddable\Address;
use App\Entity\Embeddable\BankAccount;
use App\Entity\Embeddable\Communication;
use App\Entity\Traits\SoftDeletableEntity;
use App\Entity\Traits\TimestampableEntity;
use App\Repository\TeamerRepository;
use Doctrine\Common\Collections\ArrayCollection;
@@ -16,9 +17,10 @@ use Symfony\Component\Uid\Uuid;
use Symfony\Component\Validator\Constraints as Assert;
#[ORM\Entity(repositoryClass: TeamerRepository::class)]
class Teamer implements TimestampableEntityInterface
class Teamer implements TimestampableEntityInterface, SoftDeletableEntityInterface
{
use TimestampableEntity;
use SoftDeletableEntity;
public const STATUS_NEW = 'new';
public const STATUS_EXISTING = 'existing';
+8 -1
View File
@@ -14,7 +14,7 @@ trait SoftDeletableEntity
return $this->deletedAt;
}
public function setDeletedAt(\DateTimeImmutable $deletedAt): static
public function setDeletedAt(?\DateTimeImmutable $deletedAt): static
{
$this->deletedAt = $deletedAt;
@@ -28,6 +28,13 @@ trait SoftDeletableEntity
return $this;
}
public function setRestored(): static
{
$this->setDeletedAt(null);
return $this;
}
public function isDeleted(): bool
{
return null !== $this->getDeletedAt();
+19 -1
View File
@@ -2,6 +2,7 @@
namespace App\Entity;
use App\Entity\Traits\SoftDeletableEntity;
use App\Entity\Traits\TimestampableEntity;
use App\Repository\UserRepository;
use Doctrine\DBAL\Types\Types;
@@ -12,9 +13,10 @@ use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
#[ORM\Entity(repositoryClass: UserRepository::class)]
class User implements UserInterface, TimestampableEntityInterface
class User implements UserInterface, TimestampableEntityInterface, SoftDeletableEntityInterface
{
use TimestampableEntity;
use SoftDeletableEntity;
/**
* Assignable roles and their labels.
@@ -315,6 +317,11 @@ class User implements UserInterface, TimestampableEntityInterface
public function setTeamer(?Teamer $teamer): static
{
// keep the inverse side in sync: it is only ever hydrated from the database, so
// without this a teamer attached during the request has no user to point back to
$this->teamer?->setUser(null);
$teamer?->setUser($this);
$this->teamer = $teamer;
return $this;
@@ -408,6 +415,17 @@ class User implements UserInterface, TimestampableEntityInterface
return $this->setDisabledAt(new \DateTimeImmutable());
}
/**
* Whether the account is barred from logging in, for either reason. A block and a
* deletion are independent states: a disciplinary block must survive a deletion and
* the restore that follows it, so the two are only ever combined for decisions,
* never merged into one another.
*/
public function isBlocked(): bool
{
return $this->isDeleted() || $this->isDisabled();
}
public function getDisabledReason(): ?string
{
return $this->disabledReason;