Skip to content

Commit d7be0f0

Browse files
committed
Temporary fix for issue etrepat#112
1 parent e2dba60 commit d7be0f0

File tree

3 files changed

+122
-0
lines changed

3 files changed

+122
-0
lines changed

src/Baum/Node.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,16 @@ public static function buildTree($nodeList) {
461461
return with(new static)->makeTree($nodeList);
462462
}
463463

464+
/**
465+
* Pass it a nested array of ID's to re-order the tree in the DB.
466+
*
467+
* @param array|\Illuminate\Support\Contracts\ArrayableInterface
468+
* @return boolean
469+
*/
470+
public static function rebuildTree($nodeList) {
471+
return with(new static)->updateTree($nodeList);
472+
}
473+
464474
/**
465475
* Query scope which extracts a certain node object from the current query
466476
* expression.
@@ -1228,6 +1238,20 @@ public function makeTree($nodeList) {
12281238
return $mapper->map($nodeList);
12291239
}
12301240

1241+
/**
1242+
* Maps the provided tree structure into the database using the current node
1243+
* as the parent. The provided tree structure will be inserted/updated as the
1244+
* descendancy subtree of the current node instance.
1245+
*
1246+
* @param array|\Illuminate\Support\Contracts\ArrayableInterface
1247+
* @return boolean
1248+
*/
1249+
public function updateTree($nodeList) {
1250+
$mapper = new SetMapper($this);
1251+
1252+
return $mapper->updateMap($nodeList);
1253+
}
1254+
12311255
/**
12321256
* Main move method. Here we handle all node movements with the corresponding
12331257
* lft/rgt index updates.

src/Baum/SetMapper.php

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,61 @@ public function map($nodeList) {
5353
});
5454
}
5555

56+
/**
57+
* Update a tree structure in the database. Unguards & wraps in transaction.
58+
*
59+
* @param array|\Illuminate\Support\Contracts\ArrayableInterface
60+
* @return boolean
61+
*/
62+
public function updateMap($nodeList) {
63+
$self = $this;
64+
65+
return $this->wrapInTransaction(function() use ($self, $nodeList) {
66+
forward_static_call(array(get_class($self->node), 'unguard'));
67+
$result = true;
68+
try {
69+
$flattenTree = $this->flattenNestable($nodeList);
70+
foreach ($flattenTree as $branch) {
71+
$self->node->flushEventListeners();
72+
$model = $self->node->find($branch['id']);
73+
$model->fill($branch);
74+
$model->save();
75+
}
76+
} catch (\Exception $e) {
77+
$result = false;
78+
}
79+
forward_static_call(array(get_class($self->node), 'reguard'));
80+
return $result;
81+
});
82+
}
83+
84+
/**
85+
* Flattens an array to contain 'id', 'lft', 'rgt', 'depth', 'parent_id' as a valid tree
86+
* @param $nestableArray
87+
* @param null $parent_id
88+
* @param int $depth
89+
* @return array
90+
*/
91+
private $bound = 0;
92+
public function flattenNestable($nestableArray, $parent_id = null, $depth = 0)
93+
{
94+
$return = array();
95+
foreach ($nestableArray as $subArray) {
96+
$returnSubSubArray = array();
97+
$lft = ++$this->bound;
98+
if (isset($subArray['children'])) {
99+
$returnSubSubArray = $this->flattenNestable($subArray['children'], $subArray['id'], ($depth + 1));
100+
$rgt = $this->bound + 1;
101+
++$this->bound;
102+
} else {
103+
$rgt = ++$this->bound;
104+
}
105+
$return[] = array('id' => $subArray['id'], 'parent_id' => $parent_id, 'depth' => $depth, 'lft' => $lft, 'rgt' => $rgt);
106+
$return = array_merge($return, $returnSubSubArray);
107+
}
108+
return $return;
109+
}
110+
56111
/**
57112
* Maps a tree structure into the database without unguarding nor wrapping
58113
* inside a transaction.

tests/suite/Category/CategoryTreeMapperTest.php

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ class CategoryTreeMapperTest extends BaumTestCase {
66

77
public function setUp() {
88
with(new CategoryMigrator)->up();
9+
Category::boot();
910
}
1011

1112
public function testBuildTree() {
@@ -29,6 +30,48 @@ public function testBuildTree() {
2930
$this->assertArraysAreEqual($tree, array_ints_keys(hmap($hierarchy, array('id', 'name'))));
3031
}
3132

33+
public function testBuildTreeAndUpdate() {
34+
$tree = array(
35+
array('id' => 1, 'name' => 'A'),
36+
array('id' => 2, 'name' => 'B'),
37+
array('id' => 3, 'name' => 'C', 'children' => array(
38+
array('id' => 4, 'name' => 'C.1', 'children' => array(
39+
array('id' => 5, 'name' => 'C.1.1'),
40+
array('id' => 6, 'name' => 'C.1.2')
41+
)),
42+
array('id' => 7, 'name' => 'C.2'),
43+
array('id' => 8, 'name' => 'C.3')
44+
)),
45+
array('id' => 9, 'name' => 'D')
46+
);
47+
$this->assertTrue(Category::buildTree($tree));
48+
$this->assertTrue(Category::isValid());
49+
50+
$hierarchy = Category::all()->toHierarchy()->toArray();
51+
$this->assertArraysAreEqual($tree, array_ints_keys(hmap($hierarchy, array('id', 'name'))));
52+
53+
// Now try and update the already existing tree
54+
$tree = array(
55+
array('id' => 9),
56+
array('id' => 8),
57+
array('id' => 7, 'children' => array(
58+
array('id' => 6, 'children' => array(
59+
array('id' => 5),
60+
array('id' => 4)
61+
)),
62+
array('id' => 3),
63+
array('id' => 2)
64+
)),
65+
array('id' => 1)
66+
);
67+
68+
$this->assertTrue(Category::rebuildTree($tree));
69+
$this->assertTrue(Category::isValid());
70+
71+
$hierarchy = Category::all()->toHierarchy()->toArray();
72+
$this->assertArraysAreEqual($tree, array_ints_keys(hmap($hierarchy, array('id'))));
73+
}
74+
3275
public function testBuildTreePrunesAndInserts() {
3376
$tree = array(
3477
array('id' => 1, 'name' => 'A'),

0 commit comments

Comments
 (0)