387 lines
9 KiB
PHP
Executable file
387 lines
9 KiB
PHP
Executable file
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Entity;
|
|
|
|
use ApiPlatform\Doctrine\Orm\Filter\OrderFilter;
|
|
use ApiPlatform\Metadata\ApiFilter;
|
|
use ApiPlatform\Metadata\ApiProperty;
|
|
use App\Doctrine\Behavior\TimestampableEntity;
|
|
use App\Enum\Group\GroupMembership;
|
|
use App\Enum\Group\GroupType;
|
|
use App\Repository\GroupRepository;
|
|
use App\Validator as AppAssert;
|
|
use Doctrine\Common\Collections\ArrayCollection;
|
|
use Doctrine\Common\Collections\Collection;
|
|
use Doctrine\DBAL\Types\Types;
|
|
use Doctrine\ORM\Mapping as ORM;
|
|
use Gedmo\Mapping\Annotation as Gedmo;
|
|
use Symfony\Bridge\Doctrine\IdGenerator\UuidGenerator;
|
|
use Symfony\Component\Uid\Uuid;
|
|
use Symfony\Component\Validator\Constraints as Assert;
|
|
|
|
#[ORM\Entity(repositoryClass: GroupRepository::class)]
|
|
#[ORM\Table(name: '`group`')] // we need escaping here, as group is a reserved word
|
|
#[ORM\Index(columns: ['type'])]
|
|
#[ApiFilter(OrderFilter::class, properties: ['name'])]
|
|
#[AppAssert\Constraints\Group\GroupParentNotSelf]
|
|
class Group implements \Stringable
|
|
{
|
|
use TimestampableEntity;
|
|
|
|
/**
|
|
* Generates a V6 uuid.
|
|
*/
|
|
#[ORM\Id]
|
|
#[ORM\Column(type: 'uuid', unique: true)]
|
|
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
|
|
#[ORM\CustomIdGenerator(class: UuidGenerator::class)]
|
|
#[ApiProperty(identifier: true)]
|
|
private Uuid $id;
|
|
|
|
/**
|
|
* Optional parent for the group.
|
|
*/
|
|
#[ORM\ManyToOne(targetEntity: self::class, inversedBy: 'children')]
|
|
private ?self $parent = null;
|
|
|
|
/**
|
|
* Type of the group. Public group are accessible by anyone while a private group
|
|
* requires an invitation.
|
|
*/
|
|
#[ORM\Column(name: 'type', type: 'string', nullable: false, enumType: GroupType::class)]
|
|
#[Assert\NotBlank]
|
|
protected GroupType $type = GroupType::PUBLIC;
|
|
|
|
/**
|
|
* Short and main name of the group.
|
|
*/
|
|
#[ORM\Column(type: Types::STRING, length: 255, nullable: false)]
|
|
#[Assert\NotBlank]
|
|
#[Assert\Length(max: 255)]
|
|
private string $name;
|
|
|
|
/**
|
|
* SEO friendly group name for URLs.
|
|
*/
|
|
#[ORM\Column(length: 255, unique: true)]
|
|
#[Gedmo\Slug(fields: ['name'])]
|
|
private string $slug;
|
|
|
|
/**
|
|
* Longer description of the group.
|
|
*/
|
|
#[ORM\Column(type: Types::TEXT, nullable: true)]
|
|
#[Assert\Length(max: 2000)]
|
|
private ?string $description = null;
|
|
|
|
/**
|
|
* Optional external URL for the group.
|
|
*/
|
|
#[ORM\Column(length: 255, nullable: true)]
|
|
#[Assert\Length(max: 255)]
|
|
#[Assert\Url]
|
|
private ?string $url = null;
|
|
|
|
/**
|
|
* @var Collection<int, self> $children
|
|
*/
|
|
#[ORM\OneToMany(mappedBy: 'parent', targetEntity: self::class)]
|
|
private Collection $children;
|
|
|
|
/**
|
|
* membership of the group. It can be free or paying.
|
|
*/
|
|
#[ORM\Column(name: 'membership', type: 'string', nullable: false, enumType: GroupMembership::class)]
|
|
protected GroupMembership $membership = GroupMembership::FREE;
|
|
|
|
/**
|
|
* If true, administrators can send invitations.
|
|
*/
|
|
#[ORM\Column(type: 'boolean', nullable: false)]
|
|
private bool $invitationByAdmin = false;
|
|
|
|
/**
|
|
* @var Collection<int, UserGroup>
|
|
*/
|
|
#[ORM\OneToMany(mappedBy: 'group', targetEntity: UserGroup::class, orphanRemoval: true)]
|
|
private Collection $userGroups;
|
|
|
|
/**
|
|
* @var Collection<int, GroupOffer>
|
|
*/
|
|
#[ORM\OneToMany(mappedBy: 'group', targetEntity: GroupOffer::class, orphanRemoval: true)]
|
|
#[ORM\OrderBy(['price' => 'ASC'])]
|
|
private Collection $offers;
|
|
|
|
/**
|
|
* List of visible product in the group.
|
|
*
|
|
* @var Collection<int, Product>
|
|
*/
|
|
#[ORM\ManyToMany(targetEntity: Product::class, mappedBy: 'groups')]
|
|
private Collection $products;
|
|
|
|
public function __construct()
|
|
{
|
|
$this->children = new ArrayCollection();
|
|
$this->userGroups = new ArrayCollection();
|
|
$this->offers = new ArrayCollection();
|
|
$this->products = new ArrayCollection();
|
|
}
|
|
|
|
public function __toString(): string
|
|
{
|
|
return $this->name;
|
|
}
|
|
|
|
public function getId(): Uuid
|
|
{
|
|
return $this->id;
|
|
}
|
|
|
|
public function setId(Uuid $uuid): self
|
|
{
|
|
$this->id = $uuid;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function getParent(): ?self
|
|
{
|
|
return $this->parent;
|
|
}
|
|
|
|
public function setParent(?self $parent): self
|
|
{
|
|
$this->parent = $parent;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function getName(): string
|
|
{
|
|
return $this->name;
|
|
}
|
|
|
|
public function setName(string $name): self
|
|
{
|
|
$this->name = $name;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function setSlug(string $slug): self
|
|
{
|
|
$this->slug = $slug;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function getSlug(): string
|
|
{
|
|
return $this->slug;
|
|
}
|
|
|
|
public function getType(): GroupType
|
|
{
|
|
return $this->type;
|
|
}
|
|
|
|
public function setType(GroupType $type): Group
|
|
{
|
|
$this->type = $type;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function getDescription(): ?string
|
|
{
|
|
return $this->description;
|
|
}
|
|
|
|
public function setDescription(?string $description): self
|
|
{
|
|
$this->description = $description;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function getUrl(): ?string
|
|
{
|
|
return $this->url;
|
|
}
|
|
|
|
public function setUrl(?string $url): self
|
|
{
|
|
$this->url = $url;
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @return Collection<int, self>
|
|
*/
|
|
public function getChildren(): Collection
|
|
{
|
|
return $this->children;
|
|
}
|
|
|
|
public function addChild(self $group): self
|
|
{
|
|
if (!$this->children->contains($group)) {
|
|
$this->children->add($group);
|
|
$group->setParent($this);
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function removeChild(self $group): self
|
|
{
|
|
// set the owning side to null (unless already changed)
|
|
if ($this->children->removeElement($group) && $group->getParent() === $this) {
|
|
$group->setParent(null);
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function getMembership(): GroupMembership
|
|
{
|
|
return $this->membership;
|
|
}
|
|
|
|
public function setMembership(GroupMembership $membership): void
|
|
{
|
|
$this->membership = $membership;
|
|
}
|
|
|
|
public function isInvitationByAdmin(): bool
|
|
{
|
|
return $this->invitationByAdmin;
|
|
}
|
|
|
|
public function setInvitationByAdmin(bool $invitationByAdmin): self
|
|
{
|
|
$this->invitationByAdmin = $invitationByAdmin;
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @return Collection<int, UserGroup>
|
|
*/
|
|
public function getUserGroups(): Collection
|
|
{
|
|
return $this->userGroups;
|
|
}
|
|
|
|
public function addUserGroup(UserGroup $userGroup): self
|
|
{
|
|
if (!$this->userGroups->contains($userGroup)) {
|
|
$this->userGroups->add($userGroup);
|
|
$userGroup->setGroup($this);
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function removeUserGroup(UserGroup $userGroup): self
|
|
{
|
|
$this->userGroups->removeElement($userGroup);
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @return Collection<int, GroupOffer>
|
|
*/
|
|
public function getOffers(): Collection
|
|
{
|
|
return $this->offers;
|
|
}
|
|
|
|
/**
|
|
* @param Collection<int, GroupOffer> $offers
|
|
*/
|
|
public function setOffers(Collection $offers): Group
|
|
{
|
|
$this->offers = $offers;
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @return Collection<int, Product>
|
|
*/
|
|
public function getProducts(): Collection
|
|
{
|
|
return $this->products;
|
|
}
|
|
|
|
public function addProduct(Product $product): self
|
|
{
|
|
if (!$this->products->contains($product)) {
|
|
$this->products->add($product);
|
|
$product->addGroup($this);
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function removeProduct(Product $product): self
|
|
{
|
|
if ($this->products->removeElement($product)) {
|
|
$product->removeGroup($this);
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
// End of basic 'etters ----------------------------------------------------
|
|
|
|
/**
|
|
* @return array<string, string>
|
|
*/
|
|
public function getRoutingParameters(): array
|
|
{
|
|
return [
|
|
'id' => (string) $this->getId(),
|
|
'slug' => $this->getSlug(),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Test if a given user is main admin of the group.
|
|
*/
|
|
public function isMainAdmin(User $user): bool
|
|
{
|
|
$mainAdminUserGroups = $this->userGroups->filter(
|
|
static fn (UserGroup $userGroup) => $userGroup->getUser() === $user && $userGroup->isMainAdminAccount()
|
|
);
|
|
|
|
return !$mainAdminUserGroups->isEmpty();
|
|
}
|
|
|
|
/**
|
|
* Get active offers only.
|
|
*
|
|
* @return Collection<int, GroupOffer>
|
|
*/
|
|
public function getActiveOffers(): Collection
|
|
{
|
|
/** @var Collection<int, GroupOffer> $collection */
|
|
$collection = $this->offers->filter(
|
|
static fn (GroupOffer $groupOffer) => $groupOffer->isActive()
|
|
);
|
|
|
|
return $collection;
|
|
}
|
|
|
|
public function hasActiveOffers(): bool
|
|
{
|
|
return !$this->getActiveOffers()->isEmpty();
|
|
}
|
|
}
|