diff --git a/README.md b/README.md index 70e4359..4b2fda1 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,16 @@ SelectTree::make('categories') ->relationship(relationship: 'categories', titleAttribute: 'name', parentAttribute: 'parent_id', modifyChildQueryUsing: fn($query) => $query)); ``` +Note: when you filter the parent query, any results found by the child query whose parents have been filtered out will be promoted to root nodes by default (to prevent empty result sets). +To disable this feature, use the `strictNullParentRootNodes()` configuration method + +```php +SelectTree::make('categories') + ->relationship(relationship: 'categories', titleAttribute: 'name', parentAttribute: 'parent_id', modifyQueryUsing: fn($query) => $query->where('id', 1)) + ->strictNullParentRootNodes(); // only children of parent results from the parent query will be included in the tree +``` + + ## Methods Set a custom placeholder when no items are selected diff --git a/src/SelectTree.php b/src/SelectTree.php index 03a6738..ac4963f 100644 --- a/src/SelectTree.php +++ b/src/SelectTree.php @@ -72,6 +72,8 @@ class SelectTree extends Field implements HasAffixActions protected ?Closure $modifyChildQueryUsing = null; + protected Closure|bool $strictNullParentRootNodes = false; + protected Closure|int $defaultOpenLevel = 0; protected string $direction = 'auto'; @@ -246,8 +248,11 @@ private function buildTreeFromResults($results, $parent = null): Collection } } - // Filter the cache for missing parents in the result set and get the children - $orphanedResults = array_map( + // If the tree has strict rull parent root nodes, only retrieve children whose parent is the null value + // Otherwise, promote other orphaned children to root nodes + $orphanedResults = $this->hasStrictNullParentRootNodes() + ? [$parent => $resultCache[$parent]['children']] + : array_map( fn ($item) => $item['children'], array_filter( $resultCache, @@ -256,6 +261,7 @@ private function buildTreeFromResults($results, $parent = null): Collection ); // Move any remaining children from the cache into the root of the tree, since their parents do not show up in the result set + $resultMap[$parent] = []; foreach ($orphanedResults as $orphanedResult) { $resultMap[$parent] += $orphanedResult; @@ -333,6 +339,13 @@ public function query(Builder|Closure|null $query, string $titleAttribute, strin return $this; } + public function strictNullParentRootNodes(Closure|bool $condition = true): static + { + $this->strictNullParentRootNodes = $condition; + + return $this; + } + public function withCount(bool $withCount = true): static { $this->withCount = $withCount; @@ -400,6 +413,11 @@ public function getQuery(): ?Builder return $this->getRelationship()->getRelated()->query(); } + public function hasStrictNullParentRootNodes(): bool + { + return $this->evaluate($this->strictNullParentRootNodes); + } + public function getTitleAttribute(): string { return $this->evaluate($this->titleAttribute);