树 tree

Testing Is Documentation

tests/Tree/TreeTest.php树 tree - 图1

树组件 tree 提供了一些实用方法,用于整理数据为一棵树,并提供一些方法来获取树相关节点的信息。

Uses

  1. <?php
  2. use Leevel\Tree\Tree;

Tree 基本使用

将子父节点整理为树结构。

  1. public function testBaseUse(): void
  2. {
  3. $tree = new Tree([
  4. [1, 0, 'hello'],
  5. [2, 1, 'world'],
  6. ]);
  7. $nodes = <<<'eot'
  8. [
  9. {
  10. "value": 1,
  11. "data": "hello",
  12. "children": [
  13. {
  14. "value": 2,
  15. "data": "world"
  16. }
  17. ]
  18. }
  19. ]
  20. eot;
  21. $this->assertSame(
  22. $nodes,
  23. $this->varJson(
  24. $tree->toArray()
  25. )
  26. );
  27. }

Tree.toJson 树结构输出为 JSON 格式字符串

  1. public function testToJson(): void
  2. {
  3. $tree = new Tree([
  4. [1, 0, 'hello'],
  5. [2, 1, 'world'],
  6. ]);
  7. $nodes = <<<'eot'
  8. [{"value":1,"data":"hello","children":[{"value":2,"data":"world"}]}]
  9. eot;
  10. $this->assertSame(
  11. $nodes,
  12. $tree->toJson(),
  13. );
  14. }

Tree.setNode 设置节点

  1. public function testSetNode(): void
  2. {
  3. $tree = new Tree([
  4. [1, 0, 'hello'],
  5. [2, 1, 'world'],
  6. ]);
  7. // 尾部插入节点
  8. $tree->setNode(5, 1, 'foo');
  9. $nodes = <<<'eot'
  10. [
  11. {
  12. "value": 1,
  13. "data": "hello",
  14. "children": [
  15. {
  16. "value": 2,
  17. "data": "world"
  18. },
  19. {
  20. "value": 5,
  21. "data": "foo"
  22. }
  23. ]
  24. }
  25. ]
  26. eot;
  27. $this->assertSame(
  28. $nodes,
  29. $this->varJson(
  30. $tree->toArray()
  31. )
  32. );
  33. }

Tree.setNode 在头部设置节点

  1. public function testSetNodeAtHeader(): void
  2. {
  3. $tree = new Tree([
  4. [1, 0, 'hello'],
  5. [2, 1, 'world'],
  6. ]);
  7. // 头部插入节点
  8. $tree->setNode(6, 1, 'bar', true);
  9. $nodes = <<<'eot'
  10. [
  11. {
  12. "value": 1,
  13. "data": "hello",
  14. "children": [
  15. {
  16. "value": 6,
  17. "data": "bar"
  18. },
  19. {
  20. "value": 2,
  21. "data": "world"
  22. }
  23. ]
  24. }
  25. ]
  26. eot;
  27. $this->assertSame(
  28. $nodes,
  29. $this->varJson(
  30. $tree->toArray()
  31. )
  32. );
  33. }

Tree.setNode 设置子节点

  1. public function testSetNodeAsChildren(): void
  2. {
  3. $tree = new Tree([
  4. [1, 0, 'hello'],
  5. [2, 1, 'world'],
  6. ]);
  7. // 子节点测试
  8. $tree->setNode(8, 2, 'subbar');
  9. $nodes = <<<'eot'
  10. [
  11. {
  12. "value": 1,
  13. "data": "hello",
  14. "children": [
  15. {
  16. "value": 2,
  17. "data": "world",
  18. "children": [
  19. {
  20. "value": 8,
  21. "data": "subbar"
  22. }
  23. ]
  24. }
  25. ]
  26. }
  27. ]
  28. eot;
  29. $this->assertSame(
  30. $nodes,
  31. $this->varJson(
  32. $tree->toArray()
  33. )
  34. );
  35. $json = <<<'eot'
  36. [{"value":1,"data":"hello","children":[{"value":2,"data":"world","children":[{"value":8,"data":"subbar"}]}]}]
  37. eot;
  38. $this->assertSame(
  39. $json,
  40. $tree->toJson()
  41. );
  42. }

Tree.getChildrenTree 获取节点子树

测试树数据

  1. # Tests\Tree\TreeTest::providerTree
  2. protected function providerTree(): Tree
  3. {
  4. return new Tree([
  5. [1, 0, 'hello'],
  6. [2, 1, 'world'],
  7. [3, 1, 'foo'],
  8. [4, 1, 'bar'],
  9. [5, 3, 'subfoo'],
  10. [6, 5, 'subsubfoo'],
  11. ]);
  12. }

WARNING

后面的测试,也会用到这个测试树数据。

  1. public function testGetChildrenTree(): void
  2. {
  3. $tree = $this->providerTree();
  4. $nodes = <<<'eot'
  5. [
  6. {
  7. "value": 1,
  8. "data": "hello",
  9. "children": [
  10. {
  11. "value": 2,
  12. "data": "world"
  13. },
  14. {
  15. "value": 3,
  16. "data": "foo",
  17. "children": [
  18. {
  19. "value": 5,
  20. "data": "subfoo",
  21. "children": [
  22. {
  23. "value": 6,
  24. "data": "subsubfoo"
  25. }
  26. ]
  27. }
  28. ]
  29. },
  30. {
  31. "value": 4,
  32. "data": "bar"
  33. }
  34. ]
  35. }
  36. ]
  37. eot;
  38. $this->assertSame(
  39. $nodes,
  40. $this->varJson(
  41. $tree->toArray()
  42. )
  43. );
  44. $nodes = <<<'eot'
  45. [
  46. {
  47. "value": 5,
  48. "data": "subfoo",
  49. "children": [
  50. {
  51. "value": 6,
  52. "data": "subsubfoo"
  53. }
  54. ]
  55. }
  56. ]
  57. eot;
  58. $this->assertSame(
  59. $nodes,
  60. $this->varJson(
  61. $tree->getChildrenTree(3)
  62. )
  63. );
  64. }

Tree.getChild 获取一级子节点 ID

  1. public function testGetChild(): void
  2. {
  3. $tree = $this->providerTree();
  4. $nodes = <<<'eot'
  5. {
  6. "1": 1
  7. }
  8. eot;
  9. $this->assertSame(
  10. $nodes,
  11. $this->varJson(
  12. $tree->getChild(0)
  13. )
  14. );
  15. }

Tree.getChildren 获取所有子节点 ID

  1. public function testGetChildren(): void
  2. {
  3. $tree = $this->providerTree();
  4. $nodes = <<<'eot'
  5. [
  6. 5,
  7. 6
  8. ]
  9. eot;
  10. $this->assertSame(
  11. $nodes,
  12. $this->varJson(
  13. $tree->getChildren(3)
  14. )
  15. );
  16. }

Tree.hasChild 是否存在一级子节点 ID

  1. public function testHasChild(): void
  2. {
  3. $tree = $this->providerTree();
  4. $this->assertTrue(
  5. $tree->hasChild(3)
  6. );
  7. $this->assertFalse(
  8. $tree->hasChild(6)
  9. );
  10. }

Tree.hasChildren 是否存在子节点 ID

  1. public function testHasChildren(): void
  2. {
  3. $tree = $this->providerTree();
  4. // hasChildren 存在严格和不严格校验
  5. $this->assertFalse(
  6. $tree->hasChildren(3, [5, 100000])
  7. );
  8. $this->assertTrue(
  9. $tree->hasChildren(3, [5, 100000], false)
  10. );
  11. // 第二个元素为空
  12. $this->assertFalse(
  13. $tree->hasChildren(3, [], false)
  14. );
  15. $this->assertFalse(
  16. $tree->hasChildren(1, [], true)
  17. );
  18. // 非严格模式不存在
  19. $this->assertFalse(
  20. $tree->hasChildren(100000, [2, 3], false)
  21. );
  22. }

Tree.getParent 获取一级父节点 ID

  1. public function testGetParent(): void
  2. {
  3. $tree = $this->providerTree();
  4. $nodes = <<<'eot'
  5. [
  6. 1
  7. ]
  8. eot;
  9. $this->assertSame(
  10. $nodes,
  11. $this->varJson(
  12. $tree->getParent(3)
  13. )
  14. );
  15. $nodes = <<<'eot'
  16. [
  17. 3
  18. ]
  19. eot;
  20. $this->assertSame(
  21. $nodes,
  22. $this->varJson(
  23. $tree->getParent(5)
  24. )
  25. );
  26. $nodes = <<<'eot'
  27. [
  28. 3,
  29. 5
  30. ]
  31. eot;
  32. $this->assertSame(
  33. $nodes,
  34. $this->varJson(
  35. $tree->getParent(5, true)
  36. )
  37. );
  38. }

Tree.getParent 不存在的节点父级 ID 为空数组

  1. public function testGetParentButNodeNotFound(): void
  2. {
  3. $tree = $this->providerTree();
  4. // 不存对应的节点查询父节点
  5. $this->assertSame(
  6. [],
  7. $tree->getParent(400000000)
  8. );
  9. }

Tree.getParents 获取所有父节点 ID

  1. public function testGetParents(): void
  2. {
  3. $tree = $this->providerTree();
  4. $nodes = <<<'eot'
  5. [
  6. 1,
  7. 3
  8. ]
  9. eot;
  10. $this->assertSame(
  11. $nodes,
  12. $this->varJson(
  13. $tree->getParents(5)
  14. )
  15. );
  16. $nodes = <<<'eot'
  17. [
  18. 1,
  19. 3,
  20. 5
  21. ]
  22. eot;
  23. $this->assertSame(
  24. $nodes,
  25. $this->varJson(
  26. $tree->getParents(5, true)
  27. )
  28. );
  29. }

Tree.getLevel 获取节点所在的层级

  1. public function testGetLevel(): void
  2. {
  3. $tree = $this->providerTree();
  4. $this->assertSame(
  5. 1,
  6. $tree->getLevel(3)
  7. );
  8. $this->assertSame(
  9. 3,
  10. $tree->getLevel(6)
  11. );
  12. $this->assertSame(
  13. 0,
  14. $tree->getLevel(0)
  15. );
  16. $this->assertSame(
  17. 0,
  18. $tree->getLevel(1)
  19. );
  20. $this->assertSame(
  21. 0,
  22. $tree->getLevel(100000)
  23. );
  24. }

Tree.getData.setData 设置和获取节点数据

  1. public function testGetSetData(): void
  2. {
  3. $tree = new Tree([
  4. [1, 0, 'hello'],
  5. [2, 1, 'world'],
  6. ]);
  7. $nodes = <<<'eot'
  8. [
  9. {
  10. "value": 1,
  11. "data": "hello",
  12. "children": [
  13. {
  14. "value": 2,
  15. "data": "world"
  16. }
  17. ]
  18. }
  19. ]
  20. eot;
  21. $this->assertSame(
  22. $nodes,
  23. $this->varJson(
  24. $tree->toArray()
  25. )
  26. );
  27. $this->assertSame(
  28. 'world',
  29. $tree->getData(2)
  30. );
  31. $nodes = <<<'eot'
  32. [
  33. {
  34. "value": 1,
  35. "data": "hello",
  36. "children": [
  37. {
  38. "value": 2,
  39. "data": "world => foo"
  40. }
  41. ]
  42. }
  43. ]
  44. eot;
  45. $tree->setData(2, 'world => foo');
  46. $this->assertSame(
  47. $nodes,
  48. $this->varJson(
  49. $tree->toArray()
  50. )
  51. );
  52. $this->assertSame(
  53. 'world => foo',
  54. $tree->getData(2)
  55. );
  56. }

Tree.normalize 返回整理树节点数据结构

  1. public function testNormalize(): void
  2. {
  3. $tree = new Tree([
  4. [1, 0, 'hello'],
  5. [2, 1, 'world'],
  6. ]);
  7. $nodes = <<<'eot'
  8. [
  9. {
  10. "value": 1,
  11. "data": "hello",
  12. "children": [
  13. {
  14. "value": 2,
  15. "data": "world"
  16. }
  17. ]
  18. }
  19. ]
  20. eot;
  21. $this->assertSame(
  22. $nodes,
  23. $this->varJson(
  24. $tree->toArray()
  25. )
  26. );
  27. $nodes = <<<'eot'
  28. [
  29. {
  30. "value1": 1,
  31. "data1": "hello",
  32. "children": [
  33. {
  34. "value1": 2,
  35. "data1": "world"
  36. }
  37. ]
  38. }
  39. ]
  40. eot;
  41. $this->assertSame(
  42. $nodes,
  43. $this->varJson(
  44. $tree->normalize(null, [
  45. 'value' => 'value1',
  46. 'data' => 'data1',
  47. ])
  48. )
  49. );
  50. $nodes = <<<'eot'
  51. [
  52. {
  53. "value": 1,
  54. "data": "hello",
  55. "label": "hello",
  56. "children": [
  57. {
  58. "value": 2,
  59. "data": "world",
  60. "label": "world"
  61. }
  62. ]
  63. }
  64. ]
  65. eot;
  66. $this->assertSame(
  67. $nodes,
  68. $this->varJson(
  69. $tree->normalize(function ($item) {
  70. $item['label'] = $item['data'];
  71. return $item;
  72. })
  73. )
  74. );
  75. }

Tree.normalize 返回整理树某个节点及下级的数据结构

  1. public function testNormalizeNode(): void
  2. {
  3. // 可以返回子树
  4. $tree = $this->providerTree();
  5. $nodes = <<<'eot'
  6. [
  7. {
  8. "value": 5,
  9. "data": "subfoo",
  10. "children": [
  11. {
  12. "value": 6,
  13. "data": "subsubfoo"
  14. }
  15. ]
  16. }
  17. ]
  18. eot;
  19. $this->assertSame(
  20. $nodes,
  21. $this->varJson(
  22. $tree->normalize(null, [], 3)
  23. )
  24. );
  25. }