Skip to content

Commit 55fbea9

Browse files
committed
Refactored a bit and updated docs
1 parent 68a3320 commit 55fbea9

File tree

6 files changed

+196
-154
lines changed

6 files changed

+196
-154
lines changed

CHANGELOG.markdown

+4
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@
1313
* #79: implemented scoping feature
1414
* #81: moving node now makes model dirty before saving it
1515
* #45: descendants is now a relation that can be eagerly loaded
16+
* `hasChildren` and `hasParent` are now deprecated. Use `has('children')`
17+
`has('parent')` instead
18+
* Default order is no longer applied for `siblings()`, `descendants()`,
19+
`prevNodes`, `nextNodes`
1620

1721
### 3.1.1
1822

README.markdown

+136-88
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ Another important note is that __structural manipulations are deferred__ until y
6868
hit `save` on model (some methods implicitly call `save` and return boolean result
6969
of the operation).
7070

71-
If model is successfully saved it doesn't mean that node has moved. If your application
71+
If model is successfully saved it doesn't mean that node was moved. If your application
7272
depends on whether the node has actually changed its position, use `hasMoved` method:
7373

7474
```php
@@ -77,12 +77,17 @@ if ($node->save()) {
7777
}
7878
```
7979

80-
#### Creating a new node
80+
#### Creating nodes
8181

82-
When you just create a node, it will be appended to the end of the tree:
82+
When you simply creating a node, it will be appended to the end of the tree:
8383

8484
```php
85-
Category::create($attributes);
85+
Category::create($attributes); // Saved as root
86+
```
87+
88+
```php
89+
$node = new Category($attributes);
90+
$node->save(); // Saved as root
8691
```
8792

8893
In this case the node is considered a _root_ which means that it doesn't have a parent.
@@ -103,7 +108,7 @@ The node will be appended to the end of the tree.
103108

104109
If you want to make node a child of other node, you can make it last or first child.
105110

106-
In following examples, `$parent` is some existing node.
111+
*In following examples, `$parent` is some existing node.*
107112

108113
There are few ways to append a node:
109114

@@ -142,8 +147,8 @@ $parent->prependNode($node);
142147

143148
You can make `$node` to be a neighbor of the `$neighbor` node using following methods:
144149

145-
*Neighbor is existing node, target node can be fresh. If target node exists,
146-
it will be moved to the new position and parent will be changed if required.*
150+
*`$neighbor` must exists, target node can be fresh. If target node exists,
151+
it will be moved to the new position and parent will be changed if it's required.*
147152

148153
```php
149154
# Explicit save
@@ -155,20 +160,6 @@ $node->insertAfterNode($neighbor);
155160
$node->insertBeforeNode($neighbor);
156161
```
157162

158-
#### Shifting a node
159-
160-
To shift node up or down inside parent:
161-
162-
```php
163-
$bool = $node->down();
164-
$bool = $node->up();
165-
166-
// Shift node by 3 siblings
167-
$bool = $node->down(3);
168-
```
169-
170-
The result of the operation is boolean value of whether the node has changed the position.
171-
172163
#### Building a tree from array
173164

174165
When using static method `create` on node, it checks whether attributes contains
@@ -194,7 +185,7 @@ $node = Category::create([
194185

195186
### Retrieving nodes
196187

197-
In some cases we will use an `$id` variable which is an id of the target node.
188+
*In some cases we will use an `$id` variable which is an id of the target node.*
198189

199190
#### Ancestors
200191

@@ -205,20 +196,20 @@ $result = $node->getAncestors();
205196
// #2 Using a query
206197
$result = $node->ancestors()->get();
207198

208-
// #3 Getting ancestors by id of the node
199+
// #3 Getting ancestors by primary key
209200
$result = Category::ancestorsOf($id);
210201
```
211202

212203
#### Descendants
213204

214205
```php
215-
// #1 Using accessor
216-
$result = $node->getDescendants();
206+
// #1 Using relationship
207+
$result = $node->descendants;
217208

218-
// #2 Using a query
209+
// #2 Using a query
219210
$result = $node->descendants()->get();
220211

221-
// #3 Getting ancestors by id of the node
212+
// #3 Getting descendants by primary key
222213
$result = Category::descendantsOf($id);
223214
```
224215

@@ -230,7 +221,7 @@ $result = $node->getSiblings();
230221
$result = $node->siblings()->get();
231222
```
232223

233-
To get just next siblings ([default order](#default-order) is applied here):
224+
To get only next siblings:
234225

235226
```php
236227
// Get a sibling that is immediately after the node
@@ -243,7 +234,7 @@ $result = $node->getNextSiblings();
243234
$result = $node->nextSiblings()->get();
244235
```
245236

246-
To get previous siblings ([reversed order](#default-order) is applied):
237+
To get previous siblings:
247238

248239
```php
249240
// Get a sibling that is immediately before the node
@@ -272,51 +263,6 @@ $categories[] = $category->getKey();
272263
$goods = Goods::whereIn('category_id', $categories)->get();
273264
```
274265

275-
### Deleting nodes
276-
277-
To delete a node:
278-
279-
```php
280-
$node->delete();
281-
```
282-
283-
**IMPORTANT!** Any descendant that node has will also be deleted!
284-
285-
**IMPORTANT!** Nodes are required to be deleted as models, **don't** try do delete them using a query like so:
286-
287-
```php
288-
Category::where('id', '=', $id)->delete();
289-
```
290-
291-
This will brake the tree!
292-
293-
`SoftDeletes` trait is supported, also on model level.
294-
295-
### Collection extension
296-
297-
This package provides few helpful methods for collection of nodes. You can link nodes in plain collection like so:
298-
299-
```php
300-
$results = Categories::get();
301-
302-
$results->linkNodes();
303-
```
304-
305-
This will fill `parent` and `children` relations on every node so you can iterate over them without extra database
306-
requests.
307-
308-
To convert plain collection to tree:
309-
310-
```
311-
$tree = $results->toTree();
312-
```
313-
314-
`$tree` will contain only root nodes and to access children you can use `children` relation.
315-
316-
### Query builder extension
317-
318-
This packages extends default query builder to introduce few helpful features.
319-
320266
#### Including node depth
321267

322268
If you need to know at which level the node is:
@@ -352,13 +298,26 @@ You can get nodes in reversed order:
352298
$result = Category::reversed()->get();
353299
```
354300

301+
##### Shifting a node
302+
303+
To shift node up or down inside parent to affect default order:
304+
305+
```php
306+
$bool = $node->down();
307+
$bool = $node->up();
308+
309+
// Shift node by 3 siblings
310+
$bool = $node->down(3);
311+
```
312+
313+
The result of the operation is boolean value of whether the node has changed its
314+
position.
315+
355316
#### Constraints
356317

357318
Various constraints that can be applied to the query builder:
358319

359320
- __whereIsRoot()__ to get only root nodes;
360-
- __hasChildren()__ to get nodes that have children;
361-
- __hasParent()__ to get non-root nodes;
362321
- __whereIsAfter($id)__ to get every node (not just siblings) that are after a node
363322
with specified id;
364323
- __whereIsBefore($id)__ to get every node that is before a node with specified id.
@@ -380,21 +339,88 @@ $result = Category::whereAncestorOf($node)->get();
380339

381340
`$node` can be either a primary key of the model or model instance.
382341

383-
### Node methods
342+
#### Building a tree
343+
344+
After getting a set of nodes, you can convert it to tree. For example:
345+
346+
```php
347+
$tree = Category::get()->toTree();
348+
```
349+
350+
This will fill `parent` and `children` relationships on every node in the set and
351+
you can render a tree using recursive algorithm:
352+
353+
```php
354+
$nodes = Category::get()->toTree();
355+
356+
$traverse = function ($categories, $prefix = '-') use (&$traverse) {
357+
foreach ($categories as $category) {
358+
echo PHP_EOL.$prefix.' '.$category->name;
359+
360+
$traverse($category->children, $prefix.'-');
361+
}
362+
};
363+
364+
$traverse($nodes);
365+
```
366+
367+
This will output something like this:
368+
369+
```
370+
- Root
371+
-- Child 1
372+
--- Sub child 1
373+
-- Child 2
374+
- Another root
375+
```
376+
377+
##### Getting subtree
378+
379+
Sometimes you don't need whole tree to be loaded and just some subtree of specific node.
380+
It is show in following example:
381+
382+
```php
383+
$root = Category::find($rootId);
384+
$tree = $root->descendants->toTree($root);
385+
```
386+
387+
Now `$tree` contains children of `$root` node.
388+
389+
If you don't need `$root` node itself, do following instead:
390+
391+
```php
392+
$tree = Category::descendantsOf($rootId)->toTree($rootId);
393+
```
394+
395+
### Deleting nodes
396+
397+
To delete a node:
398+
399+
```php
400+
$node->delete();
401+
```
384402

385-
Compute the number of descendants:
403+
**IMPORTANT!** Any descendant that node has will also be deleted!
404+
405+
**IMPORTANT!** Nodes are required to be deleted as models, **don't** try do delete them using a query like so:
386406

387407
```php
388-
$node->getDescendantCount();
408+
Category::where('id', '=', $id)->delete();
389409
```
390410

411+
This will brake the tree!
412+
413+
`SoftDeletes` trait is supported, also on model level.
414+
415+
### Helper methods
416+
391417
To check if node is a descendant of other node:
392418

393419
```php
394420
$bool = $node->isDescendantOf($parent);
395421
```
396422

397-
To check whether the node is root:
423+
To check whether the node is a root:
398424

399425
```php
400426
$bool = $node->isRoot();
@@ -431,8 +457,8 @@ It will return an array with following keys:
431457

432458
#### Fixing tree
433459

434-
Since v3.1 tree can now be fixed. Using inheritance info from `parent_id` column, proper `_lft` and `_rgt` values
435-
are set for every node.
460+
Since v3.1 tree can now be fixed. Using inheritance info from `parent_id` column,
461+
proper `_lft` and `_rgt` values are set for every node.
436462

437463
```php
438464
Node::fixTree();
@@ -453,11 +479,36 @@ protected function getScopeAttributes()
453479
}
454480
```
455481

456-
But now in order to execute some custom query for retrieving nodes, you need to
457-
provide attributes that are used for scoping:
482+
But now in order to execute some custom query, you need to provide attributes
483+
that are used for scoping:
458484

459485
```php
460-
MenuItem::scoped([ 'menu_id' => 5 ])->withDepth()->get();
486+
MenuItem::scoped([ 'menu_id' => 5 ])->withDepth()->get(); // OK
487+
MenuItem::descendantsOf($id)->get(); // WRONG: returns nodes from other scope
488+
MenuItem::scoped([ 'menu_id' => 5 ])->fixTree();
489+
```
490+
491+
When requesting nodes using model instance, scopes applied automatically based
492+
on data of that model. See examples:
493+
494+
```php
495+
$node = MenuItem::findOrFail($id);
496+
497+
$node->siblings()->withDepth()->get(); // OK
498+
```
499+
500+
To get scoped query builder using instance:
501+
502+
```php
503+
$node->newScopedQuery();
504+
```
505+
506+
Note, that scoping is not required when retrieving model by primary key
507+
(since the key is unique):
508+
509+
```php
510+
$node = MenuItem::findOrFail($id); // OK
511+
$node = MenuItem::scoped([ 'menu_id' => 5 ])->findOrFail(); // OK, but redundant
461512
```
462513

463514
Requirements
@@ -466,9 +517,6 @@ Requirements
466517
- PHP >= 5.4
467518
- Laravel >= 4.1
468519

469-
Models are extended from new base class rather than `Eloquent`, so it's not possible
470-
to use another framework that overrides `Eloquent`.
471-
472520
It is highly suggested to use database that supports transactions (like MySql's InnoDb)
473521
to secure a tree from possible corruption.
474522

UPGRADE.markdown

+3
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ old `Kalnoy\Nesetedset\Node` class is still available.
66
Some methods on trait were renamed (see changelog), but still available on legacy
77
node class.
88

9+
Default order is no longer applied for `siblings()`, `descendants()`,
10+
`prevNodes`, `nextNodes`.
11+
912
### Upgrading to 3.0
1013

1114
Some methods were renamed, see changelog for more details.

0 commit comments

Comments
 (0)