隔着屏幕轻易产生感情的你,肯定很孤独吧。

公司要求做一个用户关系链图表,其中用到了无限极树形结构的数据,在这里分享一下实体的创建,顺便分享一波公司里大佬写实体时候的一些习惯和写法,文章结尾在分享一下递归获取关系数据的方法。
用户实体:

<?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 条评论

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据