Tree.php 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. <?php
  2. namespace common\traits;
  3. use common\helpers\ArrayHelper;
  4. use common\helpers\TreeHelper;
  5. use common\models\member\Member;
  6. /**
  7. * Trait Tree
  8. *
  9. * 注意:必须带有
  10. *
  11. * id、pid、level、tree 字段
  12. *
  13. * 选择使用
  14. *
  15. * '''php
  16. * public function getParent()
  17. * {
  18. * return $this->hasOne(self::class, ['id' => 'pid']);
  19. * }
  20. * '''
  21. *
  22. * @package common\traits
  23. */
  24. trait Tree
  25. {
  26. /**
  27. * 关联父级
  28. *
  29. * @return \yii\db\ActiveQuery
  30. */
  31. public function getParent()
  32. {
  33. return $this->hasOne(self::class, ['id' => 'pid']);
  34. }
  35. /**
  36. * @param bool $insert
  37. * @return bool
  38. */
  39. public function beforeSave($insert)
  40. {
  41. // 处理上下级关系
  42. $this->autoUpdateTree();
  43. return parent::beforeSave($insert);
  44. }
  45. /**
  46. * @return bool
  47. */
  48. public function beforeDelete()
  49. {
  50. // 自动删除所有下级
  51. $this->autoDeleteTree();
  52. return parent::beforeDelete();
  53. }
  54. /**
  55. * 自动删除所有下级
  56. */
  57. protected function autoDeleteTree()
  58. {
  59. self::deleteAll(['like', 'tree', $this->tree . TreeHelper::prefixTreeKey($this->id) . '%', false]);
  60. }
  61. /**
  62. * 自动更新树
  63. *
  64. * @param bool $insert
  65. * @return bool
  66. */
  67. protected function autoUpdateTree()
  68. {
  69. if ($this->isNewRecord) {
  70. if ($this->pid == 0) {
  71. $this->tree = TreeHelper::defaultTreeKey();
  72. } else {
  73. list($level, $tree) = $this->getParentData();
  74. $this->level = $level;
  75. $this->tree = $tree;
  76. }
  77. } else {
  78. // 修改父类
  79. if (isset($this->oldAttributes['pid']) && $this->oldAttributes['pid'] != $this->pid) {
  80. list($level, $tree) = $this->getParentData();
  81. // 查找所有子级
  82. $list = self::find()
  83. ->where(['like', 'tree', $this->tree . TreeHelper::prefixTreeKey($this->id) . '%', false])
  84. ->select(['id', 'level', 'tree', 'pid'])
  85. ->asArray()
  86. ->all();
  87. $distanceLevel = $level - $this->level;
  88. // 递归修改
  89. $data = ArrayHelper::itemsMerge($list, $this->id);
  90. $this->recursionUpdate($data, $distanceLevel, $tree);
  91. $this->level = $level;
  92. $this->tree = $tree;
  93. }
  94. }
  95. }
  96. /**
  97. * 递归更新数据
  98. *
  99. * @param $data
  100. * @param $distanceLevel
  101. * @param $tree
  102. */
  103. protected function recursionUpdate($data, $distanceLevel, $tree)
  104. {
  105. $updateIds = [];
  106. $itemLevel = '';
  107. $itemTree = '';
  108. foreach ($data as $item) {
  109. $updateIds[] = $item['id'];
  110. empty($itemLevel) && $itemLevel = $item['level'] + $distanceLevel;
  111. empty($itemTree) && $itemTree = str_replace($this->tree, $tree, $item['tree']);
  112. !empty($item['-']) && $this->recursionUpdate($item['-'], $distanceLevel, $tree);
  113. unset($item);
  114. }
  115. !empty($updateIds) && self::updateAll(['level' => $itemLevel, 'tree' => $itemTree], ['in', 'id', $updateIds]);
  116. }
  117. /**
  118. * @return array
  119. */
  120. protected function getParentData()
  121. {
  122. if (!$parent = $this->parent) {
  123. return [1, TreeHelper::defaultTreeKey()];
  124. }
  125. $level = $parent->level + 1;
  126. $tree = $parent->tree . TreeHelper::prefixTreeKey($parent->id ?? 0);
  127. return [$level, $tree];
  128. }
  129. }