公司要求做一个用户关系链图表,其中用到了无限极树形结构的数据,在这里分享一下实体的创建,顺便分享一波公司里大佬写实体时候的一些习惯和写法,文章结尾在分享一下递归获取关系数据的方法。
用户实体:
<?php
namespace App\Entity;
use App\Validator\Constraints as AppAssert;
use App\Exception\BalanceInsufficientException;
use App\Exception\CategoryParentConflictException;
use App\Exception\CategoryDescendantConflictException;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/**
* @ORM\Entity(repositoryClass="App\Repository\ClientUserRepository")
*
* @UniqueEntity(fields={"phoneNumber"})
*/
class ClientUser implements ResourceInterface, UserInterface, TimestampableInterface
{
use ResourceTrait, TimestampableTrait;
/**
* @ORM\Column(type="string", length=28, unique=true, options={"fixed": true}, name="open_id", nullable=true)
*
* @Groups({""})
*/
private $openID;
/**
* @ORM\Column(type="string", length=32, nullable=true)
*
* @Assert\NotBlank()
* @Assert\Length(max=32)
*
* @Groups({"client_user", "tree"})
*/
private $name;
/**
* @ORM\Column(type="string", length=11, unique=true, nullable=true)
*
* @Assert\NotBlank()
* @AppAssert\PhoneNumber()
*
* @Groups({"client_user", "tree"})
*/
private $phoneNumber;
/**
* @ORM\ManyToOne(targetEntity="Region")
* @ORM\JoinColumn(referencedColumnName="id")
*
* @Assert\NotBlank()
*
* @Groups({"client_user"})
*/
private $province;
/**
* @ORM\ManyToOne(targetEntity="Region")
* @ORM\JoinColumn(referencedColumnName="id")
*
* @Assert\NotBlank()
*
* @Groups({"client_user"})
*/
private $city;
/**
* @ORM\ManyToOne(targetEntity="Region")
* @ORM\JoinColumn(referencedColumnName="id")
*
* @Assert\NotBlank()
*
* @Groups({"client_user"})
*/
private $district;
/**
* 头像.
*
* @ORM\Column(type="string", length=150, nullable=true)
*
* @Groups({"client_user"})
*/
private $avatar;
/**
* @ORM\OneToMany(targetEntity="ClientDevice", mappedBy="owner", cascade={"all"}, orphanRemoval=true)
*
* @Groups({"client_user"})
*/
private $devices;
/**
* 邀请码.
*
* @ORM\Column(type="string", length=6, unique=true, options={"fixed": true}, nullable=true)
*
* @Groups({"client_user"})
*/
private $invitationCode;
/**
* 父级.
*
* @ORM\ManyToOne(targetEntity="ClientUser", inversedBy="children")
* @ORM\JoinColumn(name="parent_id", nullable=true)
*
* @Groups({"", "tree"})
*/
private $parent;
/**
* 子级.
*
* @ORM\OneToMany(targetEntity="ClientUser", mappedBy="parent", cascade={"all"}, orphanRemoval=true)
*/
private $children;
/**深度
* @ORM\Column(type="smallint")
*
* @Assert\GreaterThanOrEqual(-32768)
* @Assert\LessThanOrEqual(32767)
*/
private $depth;
/**
* @ORM\Column(type="text", nullable=true)
* @Groups("client_user")
*/
private $remark;
/**
* @ORM\OneToMany(targetEntity="ClientAchievement", mappedBy="clientUser", cascade={"all"}, orphanRemoval=true)
* @ORM\OrderBy({"id": "DESC"})
*/
private $achievement;
public function __construct()
{
$this->achievement = new ArrayCollection();
$this->children = new ArrayCollection();
}
public function getOpenID()
{
return $this->openID;
}
public function setOpenID(string $openID)
{
$this->openID = $openID;
return $this;
}
public function getName()
{
return $this->name;
}
public function setName(?string $name)
{
$this->name = $name;
return $this;
}
public function getPhoneNumber()
{
return $this->phoneNumber;
}
public function setPhoneNumber(?string $phoneNumber)
{
$this->phoneNumber = $phoneNumber;
return $this;
}
public function getProvince()
{
return $this->province;
}
public function setProvince(Region $province)
{
$this->province = $province;
return $this;
}
public function getCity()
{
return $this->city;
}
public function setCity(Region $city)
{
$this->city = $city;
return $this;
}
public function getDistrict()
{
return $this->district;
}
public function setDistrict(Region $district)
{
$this->district = $district;
return $this;
}
public function getDevices()
{
return $this->devices;
}
public function getRoles()
{
return ['ROLE_CLIENT'];
}
public function getPassword()
{
return;
}
public function getSalt()
{
return;
}
public function getUsername()
{
return $this->openID;
}
public function eraseCredentials()
{
$this->plainPassword = null;
}
public function getAvatar()
{
return $this->avatar;
}
public function setAvatar(string $avatar)
{
$this->avatar = $avatar;
return $this;
}
public function getInvitationCode()
{
return $this->invitationCode;
}
public function setInvitationCode(string $invitationCode)
{
return $this->invitationCode = $invitationCode;
}
public function getParent(): ?self
{
return $this->parent;
}
public function setParent(?self $parent): self
{
//设置的父级如果是他自己则抛出异常
if ($parent && $parent->isEqual($this) && !$parent->isNew()) {
throw new CategoryParentConflictException($this, $parent);
}
//设置的父级是自己的子级中的一个,则抛出异常
if ($parent && \in_array($parent, $this->getDescendants(), true)) {
throw new CategoryDescendantConflictException($this, $parent);
}
return $this->parent = $parent;
}
public function getRemark()
{
return $this->remark;
}
public function setRemark(?string $remark)
{
$this->remark = $remark;
return $this;
}
public function getAchievementTotal()
{
$achievements = [];
foreach ($this->achievement as $achievement) {
$achievements[] = $achievement->getAmount();
}
return round(array_sum($achievements), 2);
}
public function getAchievement()
{
return $this->achievement;
}
public function addAchievement(ClientAchievement $achievement)
{
$consumeAmount = $achievement->getAmount();
$currentAmount = $this->getAchievementTotal();
if ($consumeAmount < 0 && abs($consumeAmount) > $currentAmount) {
throw new BalanceInsufficientException($consumeAmount, $currentAmount);
}
$achievement->setClientUser($this);
$this->achievement[] = $achievement;
return $this;
}
public function removeAchievement(ClientAchievement $achievement)
{
$this->achievement->removeElement($achievement);
}
public function getChildren(): Collection
{
return $this->children;
}
/*
设置子节点集合
*/
public function setChildren(Collection $children): self
{
$this->children = $children;
return $this;
}
/**
* 添加子节点.
*
*/
public function addChild(self $child): self
{
if (!$this->children->contains($child)) {
$this->children[] = $child;
$child->setParent($this);
}
return $this;
}
public function removeChild(self $child): self
{
if ($this->children->contains($child)) {
$this->children->removeElement($child);
if ($child->getParent() === $this) {
$child->setParent(null);
}
}
return $this;
}
/**
* 获取祖先节点集合.(所有上级)
*
*/
public function getAncestors(bool $includeSelf = false): array
{
$parents = $includeSelf ? [$this] : [];
$node = $this;
while ($parent = $node->getParent()) {
array_unshift($parents, $parent);
$node = $parent;
}
return $parents;
}
/**
* 获取相邻节点集合.(同级,当前用户的父级下的所有子级)
*
*/
public function getSiblings(bool $includeSelf = false): array
{
if ($this->isRoot()) {
return [];
}
$siblings = [];
foreach ($this->getParent()->getChildren() as $child) {
if ($includeSelf || !$this->isEqual($child)) {
$siblings[] = $child;
}
}
return $siblings;
}
/**
* 获取后代节点集合.(所有子级)
*/
public function getDescendants(bool $includeSelf = false): array
{
$descendants = $includeSelf ? [$this] : [];
foreach ($this->children as $child) {
$descendants[] = $child;
if (!$child->isLeaf()) {
$descendants = array_merge($descendants, $child->getDescendants());
}
}
return $descendants;
}
/**
* 向上追溯到至根节点.
*
* @return NodeInterface 根节点
*/
public function getRoot(): self
{
$node = $this;
while ($parent = $node->getParent()) {
$node = $parent;
}
return $node;
}
/**
* 检测是否为根节点.
*
* @return bool 是否为根节点
*/
public function isRoot(): bool
{
return null === $this->getParent();
}
/**
* 检测是否为叶子节点.
*
* @return bool 是否为叶子节点
*/
public function isLeaf(): bool
{
return 0 === \count($this->children);
}
/**
* 获取节点深度.
*/
public function getDepth(): int
{
if (null === $this->depth) {
$this->recalculateDepth();
}
return $this->depth;
}
public function setDepth(int $depth): self
{
$this->depth = $depth;
return $this;
}
public function recalculateDepth(): ?int
{
if ($this->isRoot()) {
return $this->depth = 0;
}
return $this->depth = $this->getParent()->getDepth() + 1;
}
/**
* @ORM\PrePersist
* @ORM\PreUpdate
*/
public function lifecycleCallbacks()
{
$this->depth = $this->recalculateDepth();
}
}
0 条评论