Skip to content

Commit ece673a

Browse files
committed
Refactor more and add UPGRADE guide and CHANGELOG
1 parent 5e52c7a commit ece673a

File tree

5 files changed

+302
-131
lines changed

5 files changed

+302
-131
lines changed

CHANGELOG.markdown

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,22 @@
1+
### 1.2.0
2+
3+
* Added `insertAfter`, `insertBefore` methods.
4+
* `prepend` and `append` methods now save target model.
5+
* You can now call `refreshNode` to make sure that node has updated structural
6+
data (lft and rgt values).
7+
* The root node is not required now. You can use `saveAsRoot` or `makeRoot` method.
8+
New model is saved as root by default.
9+
* You can now create as many nodes and in any order as possible within single
10+
request.
11+
* Laravel 2 is supported but not required.
12+
* `ancestorsOf` now doesn't include target node into results.
13+
* New constraint methods `hasParent` and `hasChildren`.
14+
* New method `isDescendantOf` that checks if node is a descendant of other node.
15+
* Default order is not applied by default.
16+
* New method `descendantsOf` that allows to get descendants by id of the node.
17+
* Added `countErrors` and `isBroken` methods to check whether the tree is broken.
18+
119
### 1.1.0
20+
221
* `Collection::toDictionary` is now obsolete. Use `Collection::groupBy`.
322
* Laravel 4.2 is required

UPGRADE.markdown

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
### Upgrading to 1.2
2+
3+
Calling `$parent->append($node)` and `$parent->prepend($node)` now automatically
4+
saves `$node`. Those functions returns whether the node was saved.
5+
6+
`ancestorsOf` now return ancestors only not including target node.
7+
8+
Default order is not applied automatically.

src/Kalnoy/Nestedset/Node.php

Lines changed: 55 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ class Node extends Eloquent {
6666
*
6767
* @var int
6868
*/
69-
static $actionsPerformed = 0;
69+
protected static $actionsPerformed = 0;
7070

7171
/**
7272
* {@inheritdoc}
@@ -290,6 +290,7 @@ public function refreshNode()
290290
$attributes = $this->newServiceQuery()->getNodeData($this->getKey());
291291

292292
$this->attributes = array_merge($this->attributes, $attributes);
293+
$this->original = array_merge($this->original, $attributes);
293294
}
294295

295296
/**
@@ -414,7 +415,7 @@ public function prev()
414415
*/
415416
public function ancestors()
416417
{
417-
return $this->newQuery()->whereAncestorOf($this->getKey());
418+
return $this->newQuery()->whereAncestorOf($this->getKey())->defaultOrder();
418419
}
419420

420421
/**
@@ -576,68 +577,36 @@ public function down($amount = 1)
576577
*/
577578
protected function insertAt($position)
578579
{
579-
$this->refreshNode();
580-
581-
if ($this->exists && $this->getLft() < $position && $position < $this->getRgt())
582-
{
583-
throw new Exception("Trying to insert node into one of it's descendants.");
584-
}
580+
++static::$actionsPerformed;
585581

586-
if ($this->exists)
587-
{
588-
$this->moveNode($position);
589-
}
590-
else
591-
{
592-
$this->insertNode($position);
593-
}
582+
$result = $this->exists ? $this->moveNode($position) : $this->insertNode($position);
594583

595-
++static::$actionsPerformed;
584+
return $result;
596585
}
597586

598587
/**
599-
* Move a node to new position.
588+
* Move a node to the new position.
589+
*
590+
* @since 2.0
600591
*
601-
* @param int $lft
602-
* @param int $rgt
603-
* @param int $pos
592+
* @param int $position
604593
*
605594
* @return int
606595
*/
607-
protected function moveNode($pos)
596+
protected function moveNode($position)
608597
{
609-
$lft = $this->getLft();
610-
$rgt = $this->getRgt();
611-
612-
$from = min($lft, $pos);
613-
$to = max($rgt, $pos - 1);
614-
615-
// The height of node that is being moved
616-
$height = $rgt - $lft + 1;
617-
618-
// The distance that our node will travel to reach it's destination
619-
$distance = $to - $from + 1 - $height;
620-
621-
if ($pos > $lft) $height *= -1; else $distance *= -1;
598+
$updated = $this->newServiceQuery()->moveNode($this->getKey(), $position);
622599

623-
$params = compact('lft', 'rgt', 'from', 'to', 'height', 'distance');
600+
if ($updated) $this->refreshNode();
624601

625-
$query = $this->newServiceQuery()->getQuery()
626-
->whereBetween(static::LFT, array($from, $to))
627-
->orWhereBetween(static::RGT, array($from, $to));
628-
629-
$grammar = $query->getGrammar();
630-
631-
// Sync with original since those attributes are updated after prev operation
632-
$this->original[static::LFT] = $this->attributes[static::LFT] += $distance;
633-
$this->original[static::RGT] = $this->attributes[static::RGT] += $distance;
634-
635-
return $query->update($this->getColumnsPatch($params, $grammar));
602+
return $updated > 0;
636603
}
637604

638605
/**
639606
* Insert new node at specified position.
640607
*
608+
* @since 2.0
609+
*
641610
* @param int $position
642611
*/
643612
protected function insertNode($position)
@@ -648,74 +617,8 @@ protected function insertNode($position)
648617

649618
$this->setAttribute(static::LFT, $position);
650619
$this->setAttribute(static::RGT, $position + $height - 1);
651-
}
652-
653-
/**
654-
* Make or remove gap in the tree. Negative height will remove gap.
655-
*
656-
* @param int $cut
657-
* @param int $height
658-
*
659-
* @return int the number of updated nodes.
660-
*/
661-
protected function makeGap($cut, $height)
662-
{
663-
$params = compact('cut', 'height');
664-
665-
$query = $this->newServiceQuery()->getQuery();
666-
667-
return $query
668-
->where(static::LFT, '>=', $cut)
669-
->orWhere(static::RGT, '>=', $cut)
670-
->update($this->getColumnsPatch($params, $query->getGrammar()));
671-
}
672-
673-
/**
674-
* Get patch for columns.
675-
*
676-
* @param array $params
677-
* @param \Illuminate\Database\Query\Grammars\Grammar $grammar
678-
*
679-
* @return array
680-
*/
681-
protected function getColumnsPatch(array $params, $grammar)
682-
{
683-
$columns = array();
684-
685-
foreach (array(static::LFT, static::RGT) as $col)
686-
{
687-
$columns[$col] = $this->getColumnPatch($grammar->wrap($col), $params);
688-
}
689620

690-
return $columns;
691-
}
692-
693-
/**
694-
* Get patch for single column.
695-
*
696-
* @param string $col
697-
* @param array $params
698-
*
699-
* @return string
700-
*/
701-
protected function getColumnPatch($col, array $params)
702-
{
703-
extract($params);
704-
705-
if ($height > 0) $height = '+'.$height;
706-
707-
if (isset($cut))
708-
{
709-
return new Expression("case when $col >= $cut then $col $height else $col end");
710-
}
711-
712-
if ($distance > 0) $distance = '+'.$distance;
713-
714-
return new Expression("case ".
715-
"when $col between $lft and $rgt then $col $distance ".
716-
"when $col between $from and $to then $col $height ".
717-
"else $col end"
718-
);
621+
return true;
719622
}
720623

721624
/**
@@ -737,7 +640,7 @@ protected function deleteNode()
737640
/**
738641
* {@inheritdoc}
739642
*
740-
* @since 1.2
643+
* @since 2.0
741644
*/
742645
public function newEloquentBuilder($query)
743646
{
@@ -775,7 +678,7 @@ public function newFromBuilder($attributes = array())
775678
}
776679

777680
/**
778-
* Get node size (rgt-lft).
681+
* Get node height (rgt - lft + 1).
779682
*
780683
* @return int
781684
*/
@@ -1002,4 +905,40 @@ public function isDescendantOf(Node $other)
1002905
{
1003906
return $this->getLft() > $other->getLft() and $this->getLft() < $other->getRgt();
1004907
}
908+
909+
/**
910+
* Get statistics of errors of the tree.
911+
*
912+
* @since 2.0
913+
*
914+
* @return array
915+
*/
916+
public function countErrors()
917+
{
918+
return $this->newServiceQuery()->countErrors();
919+
}
920+
921+
/**
922+
* Get the number of total errors of the tree.
923+
*
924+
* @since 2.0
925+
*
926+
* @return int
927+
*/
928+
public function getTotalErrors()
929+
{
930+
return array_sum($this->countErrors());
931+
}
932+
933+
/**
934+
* Get whether the tree is broken.
935+
*
936+
* @since 2.0
937+
*
938+
* @return bool
939+
*/
940+
public function isBroken()
941+
{
942+
return $this->getTotalErrors() > 0;
943+
}
1005944
}

0 commit comments

Comments
 (0)