Tree.php 3.5 KB

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