Skip to content

Commit 933557d

Browse files
committed
getDescendants now returns empty collection if node doesn't exists
1 parent 87e9240 commit 933557d

File tree

3 files changed

+57
-14
lines changed

3 files changed

+57
-14
lines changed

src/Node.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -740,7 +740,7 @@ public function newEloquentBuilder($query)
740740
*
741741
* @return QueryBuilder
742742
*/
743-
protected function newServiceQuery()
743+
public function newServiceQuery()
744744
{
745745
return static::$_softDelete ? $this->withTrashed() : $this->newQuery();
746746
}
@@ -758,6 +758,7 @@ public function newCollection(array $models = array())
758758
*/
759759
public function newFromBuilder($attributes = array())
760760
{
761+
/** @var Node $instance */
761762
$instance = parent::newFromBuilder($attributes);
762763

763764
$instance->clearAction();
@@ -833,7 +834,7 @@ public function setParentIdAttribute($value)
833834
{
834835
if ($value)
835836
{
836-
$this->appendTo(static::findOrFail($value));
837+
$this->appendTo($this->newQuery()->findOrFail($value));
837838
}
838839
else
839840
{

src/QueryBuilder.php

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
namespace Kalnoy\Nestedset;
44

5+
use Illuminate\Database\Eloquent\ModelNotFoundException;
6+
use Illuminate\Database\Query\Builder as Query;
57
use LogicException;
68
use Illuminate\Database\Eloquent\Builder;
79
use Illuminate\Database\ConnectionInterface;
@@ -11,20 +13,30 @@
1113

1214
class QueryBuilder extends Builder {
1315

16+
/**
17+
* @var Node
18+
*/
19+
protected $model;
20+
1421
/**
1522
* Get node's `lft` and `rgt` values.
1623
*
1724
* @since 2.0
1825
*
1926
* @param mixed $id
27+
* @param bool $required
2028
*
2129
* @return array
2230
*/
23-
public function getNodeData($id)
31+
public function getNodeData($id, $required = false)
2432
{
2533
$this->query->where($this->model->getKeyName(), '=', $id);
2634

27-
return (array)$this->query->first([ $this->model->getLftName(), $this->model->getRgtName() ]);
35+
$data = $this->query->first([ $this->model->getLftName(), $this->model->getRgtName() ]);
36+
37+
if ( ! $data and $required) throw new ModelNotFoundException;
38+
39+
return (array)$data;
2840
}
2941

3042
/**
@@ -33,12 +45,13 @@ public function getNodeData($id)
3345
* @since 2.0
3446
*
3547
* @param mixed $id
48+
* @param bool $required
3649
*
3750
* @return array
3851
*/
39-
public function getPlainNodeData($id)
52+
public function getPlainNodeData($id, $required = false)
4053
{
41-
return array_values($this->getNodeData($id));
54+
return array_values($this->getNodeData($id, $required));
4255
}
4356

4457
/**
@@ -144,7 +157,7 @@ public function orWhereNodeBetween($values)
144157
*/
145158
public function whereDescendantOf($id, $boolean = 'and', $not = false)
146159
{
147-
$data = $this->model->newQuery()->getPlainNodeData($id);
160+
$data = $this->model->newServiceQuery()->getPlainNodeData($id, true);
148161

149162
// Don't include the node
150163
++$data[0];
@@ -164,7 +177,15 @@ public function whereDescendantOf($id, $boolean = 'and', $not = false)
164177
*/
165178
public function descendantsOf($id, array $columns = array('*'))
166179
{
167-
return $this->whereDescendantOf($id)->get($columns);
180+
try
181+
{
182+
return $this->whereDescendantOf($id)->get($columns);
183+
}
184+
185+
catch (ModelNotFoundException $e)
186+
{
187+
return $this->model->newCollection();
188+
}
168189
}
169190

170191
/**
@@ -180,7 +201,7 @@ public function descendantsOf($id, array $columns = array('*'))
180201
public function whereIsAfter($id, $boolean = 'and')
181202
{
182203
$table = $this->wrappedTable();
183-
list($lft, $rgt) = $this->wrappedColumns();
204+
list($lft,) = $this->wrappedColumns();
184205
$key = $this->wrappedKey();
185206

186207
$this->query->whereRaw("{$lft} > (select _n.{$lft} from {$table} _n where _n.{$key} = ?)", [ $id ], $boolean);
@@ -201,7 +222,7 @@ public function whereIsAfter($id, $boolean = 'and')
201222
public function whereIsBefore($id, $boolean = 'and')
202223
{
203224
$table = $this->wrappedTable();
204-
list($lft, $rgt) = $this->wrappedColumns();
225+
list($lft,) = $this->wrappedColumns();
205226
$key = $this->wrappedKey();
206227

207228
$this->query->whereRaw("{$lft} < (select _b.{$lft} from {$table} _b where _b.{$key} = ?)", [ $id ], $boolean);
@@ -291,7 +312,7 @@ public function withoutRoot()
291312
}
292313

293314
/**
294-
* Equivalent of `withouRoot`.
315+
* Equivalent of `withoutRoot`.
295316
*
296317
* @since 2.0
297318
*
@@ -358,7 +379,7 @@ public function reversed()
358379
*/
359380
public function moveNode($key, $position)
360381
{
361-
list($lft, $rgt) = $this->model->newQuery()->getPlainNodeData($key);
382+
list($lft, $rgt) = $this->model->newServiceQuery()->getPlainNodeData($key, true);
362383

363384
if ($lft < $position && $position < $rgt)
364385
{
@@ -384,7 +405,7 @@ public function moveNode($key, $position)
384405

385406
$boundary = [ $from, $to ];
386407

387-
$query = $this->query->where(function ($inner) use ($boundary)
408+
$query = $this->query->where(function (Query $inner) use ($boundary)
388409
{
389410
$inner->whereBetween($this->model->getLftName(), $boundary);
390411
$inner->orWhereBetween($this->model->getRgtName(), $boundary);
@@ -407,7 +428,7 @@ public function makeGap($cut, $height)
407428
{
408429
$params = compact('cut', 'height');
409430

410-
$this->query->where(function ($inner) use ($cut)
431+
$this->query->where(function (Query $inner) use ($cut)
411432
{
412433
$inner->where($this->model->getLftName(), '>=', $cut);
413434
$inner->orWhere($this->model->getRgtName(), '>=', $cut);
@@ -453,13 +474,19 @@ protected function columnPatch($col, array $params)
453474
{
454475
extract($params);
455476

477+
/** @var int $height */
456478
if ($height > 0) $height = '+'.$height;
457479

458480
if (isset($cut))
459481
{
460482
return new Expression("case when {$col} >= {$cut} then {$col}{$height} else {$col} end");
461483
}
462484

485+
/** @var int $distance */
486+
/** @var int $lft */
487+
/** @var int $rgt */
488+
/** @var int $from */
489+
/** @var int $to */
463490
if ($distance > 0) $distance = '+'.$distance;
464491

465492
return new Expression("case ".

tests/NodeTest.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -520,4 +520,19 @@ public function testCreatesTree()
520520
$this->assertTrue(isset($node->children));
521521
$this->assertCount(2, $node->children);
522522
}
523+
524+
public function testDescendantsOfNonExistingNode()
525+
{
526+
$node = new Category;
527+
528+
$this->assertTrue($node->getDescendants()->isEmpty());
529+
}
530+
531+
/**
532+
* @expectedException \Illuminate\Database\Eloquent\ModelNotFoundException
533+
*/
534+
public function testWhereDescendantsOf()
535+
{
536+
Category::whereDescendantOf(124)->get();
537+
}
523538
}

0 commit comments

Comments
 (0)