From 3e47b3736ed5769a241481fd65562158bc383513 Mon Sep 17 00:00:00 2001 From: gp-lnuff Date: Fri, 22 May 2026 18:03:34 +0200 Subject: [PATCH 1/3] feat: toggle strict null parent root nodes --- src/SelectTree.php | 43 ++++++++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/src/SelectTree.php b/src/SelectTree.php index 03a6738..490db96 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,19 +248,22 @@ private function buildTreeFromResults($results, $parent = null): Collection } } - // Filter the cache for missing parents in the result set and get the children - $orphanedResults = array_map( - fn ($item) => $item['children'], - array_filter( - $resultCache, - fn ($item) => ! $item['in_set'] - ) - ); - - // 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; + if (! $this->hasStrictNullParentRootNodes()) { + + // Filter the cache for missing parents in the result set and get the children + $orphanedResults = array_map( + fn ($item) => $item['children'], + array_filter( + $resultCache, + fn ($item) => ! $item['in_set'] + ) + ); + + // 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; + } } // Recursively build the tree starting from the root (null parent) @@ -333,6 +338,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 +412,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); From 46bbef8eef6a96f6323c3f3c0bd19c982cdd3756 Mon Sep 17 00:00:00 2001 From: gp-lnuff Date: Mon, 25 May 2026 13:08:32 +0200 Subject: [PATCH 2/3] chore: docs --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) 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 From 085b5ea80dc4828b42917dbc02f05c10dd6947b3 Mon Sep 17 00:00:00 2001 From: gp-lnuff Date: Tue, 26 May 2026 09:28:29 +0200 Subject: [PATCH 3/3] fix: logic --- src/SelectTree.php | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/src/SelectTree.php b/src/SelectTree.php index 490db96..ac4963f 100644 --- a/src/SelectTree.php +++ b/src/SelectTree.php @@ -248,22 +248,23 @@ private function buildTreeFromResults($results, $parent = null): Collection } } - if (! $this->hasStrictNullParentRootNodes()) { - - // Filter the cache for missing parents in the result set and get the children - $orphanedResults = array_map( - fn ($item) => $item['children'], - array_filter( - $resultCache, - fn ($item) => ! $item['in_set'] - ) - ); - - // 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; - } + // 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, + fn ($item) => ! $item['in_set'] + ) + ); + + // 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; } // Recursively build the tree starting from the root (null parent)