From 03a0b185ac6636f5ae104764da3648185df0f30a Mon Sep 17 00:00:00 2001
From: Jules <jules.graus@gmail.com>
Date: Thu, 21 Nov 2024 15:08:42 +0100
Subject: [PATCH 1/5] Fixes php 8.4 deprecation warnings like: "Implicitly
 marking parameter ... as nullable is deprecated, the explicit nullable type
 must be used instead in ..."

Example Warning: PHP Deprecated:  Kalnoy\Nestedset\NodeTrait::create(): Implicitly marking parameter $parent as nullable is deprecated, the explicit nullable type must be used instead in /var/www/html/vendor/kalnoy/nestedset/src/NodeTrait.php on line 754

And fixes "Class "Laravel\SerializableClosure\Support\ReflectionClosure" not found" when running the tests.
---
 composer.json        |  3 ++-
 src/NodeTrait.php    | 17 +++++------------
 src/QueryBuilder.php | 14 +++++++-------
 tests/NodeTest.php   |  4 ++--
 4 files changed, 16 insertions(+), 22 deletions(-)

diff --git a/composer.json b/composer.json
index 6f9ccba..5f85d6b 100644
--- a/composer.json
+++ b/composer.json
@@ -19,7 +19,8 @@
         "php": "^7.2.5|^8.0",
         "illuminate/support": "^7.0|^8.0|^9.0|^10.0|^11.0",
         "illuminate/database": "^7.0|^8.0|^9.0|^10.0|^11.0",
-        "illuminate/events": "^7.0|^8.0|^9.0|^10.0|^11.0"
+        "illuminate/events": "^7.0|^8.0|^9.0|^10.0|^11.0",
+        "laravel/serializable-closure": "^2.0"
     },
     "autoload": {
         "psr-4": {
diff --git a/src/NodeTrait.php b/src/NodeTrait.php
index c406ed8..38db1cb 100644
--- a/src/NodeTrait.php
+++ b/src/NodeTrait.php
@@ -671,7 +671,7 @@ public function newEloquentBuilder($query)
      *
      * @return QueryBuilder
      */
-    public function newNestedSetQuery($table = null)
+    public function newNestedSetQuery(?string $table = null)
     {
         $builder = $this->usesSoftDelete()
             ? $this->withTrashed()
@@ -681,22 +681,19 @@ public function newNestedSetQuery($table = null)
     }
 
     /**
-     * @param string $table
-     *
      * @return QueryBuilder
      */
-    public function newScopedQuery($table = null)
+    public function newScopedQuery(?string $table = null)
     {
         return $this->applyNestedSetScope($this->newQuery(), $table);
     }
 
     /**
      * @param mixed $query
-     * @param string $table
      *
      * @return mixed
      */
-    public function applyNestedSetScope($query, $table = null)
+    public function applyNestedSetScope($query, ?string $table = null)
     {
         if ( ! $scoped = $this->getScopeAttributes()) {
             return $query;
@@ -748,10 +745,8 @@ public function newCollection(array $models = array())
      * {@inheritdoc}
      *
      * Use `children` key on `$attributes` to create child nodes.
-     *
-     * @param self $parent
      */
-    public static function create(array $attributes = [], self $parent = null)
+    public static function create(array $attributes = [], self|null $parent = null)
     {
         $children = Arr::pull($attributes, 'children');
 
@@ -1221,11 +1216,9 @@ protected function isSameScope(self $node): bool
     }
 
     /**
-     * @param array|null $except
-     *
      * @return \Illuminate\Database\Eloquent\Model
      */
-    public function replicate(array $except = null)
+    public function replicate(?array $except = null)
     {
         $defaults = [
             $this->getParentIdName(),
diff --git a/src/QueryBuilder.php b/src/QueryBuilder.php
index 10edb27..65bf7fa 100644
--- a/src/QueryBuilder.php
+++ b/src/QueryBuilder.php
@@ -188,7 +188,7 @@ public function ancestorsAndSelf($id, array $columns = [ '*' ])
      *
      * @return $this
      */
-    public function whereNodeBetween($values, $boolean = 'and', $not = false, $query = null)
+    public function whereNodeBetween($values, $boolean = 'and', $not = false, ?Query $query = null)
     {
         ($query ?? $this->query)->whereBetween($this->model->getTable() . '.' . $this->model->getLftName(), $values, $boolean, $not);
 
@@ -861,7 +861,7 @@ public function isBroken()
      *
      * @return int The number of changed nodes
      */
-    public function fixTree($root = null)
+    public function fixTree(?Model $root = null)
     {
         $columns = [
             $this->model->getKeyName(),
@@ -899,7 +899,7 @@ public function fixSubtree($root)
      *
      * @return int
      */
-    protected function fixNodes(array &$dictionary, $parent = null)
+    protected function fixNodes(array &$dictionary, ?Model $parent = null)
     {
         $parentId = $parent ? $parent->getKey() : null;
         $cut = $parent ? $parent->getLft() + 1 : 1;
@@ -941,7 +941,7 @@ protected function fixNodes(array &$dictionary, $parent = null)
      * @internal param int $fixed
      */
     protected static function reorderNodes(
-        array &$dictionary, array &$updated, $parentId = null, $cut = 1
+        array &$dictionary, array &$updated, null|int|string $parentId = null, $cut = 1
     ) {
         if ( ! isset($dictionary[$parentId])) {
             return $cut;
@@ -973,11 +973,11 @@ protected static function reorderNodes(
      * @param array $data
      * @param bool $delete Whether to delete nodes that exists but not in the data
      *                     array
-     * @param null $root
+     * @param ?Model|NodeTrait $root
      *
      * @return int
      */
-    public function rebuildTree(array $data, $delete = false, $root = null)
+    public function rebuildTree(array $data, $delete = false, ?Model $root = null)
     {
         if ($this->model->usesSoftDelete()) {
             $this->withTrashed();
@@ -1084,7 +1084,7 @@ protected function buildRebuildDictionary(array &$dictionary,
      *
      * @return $this
      */
-    public function applyNestedSetScope($table = null)
+    public function applyNestedSetScope(?string $table = null)
     {
         return $this->model->applyNestedSetScope($this, $table);
     }
diff --git a/tests/NodeTest.php b/tests/NodeTest.php
index 3b0831a..c5ef004 100644
--- a/tests/NodeTest.php
+++ b/tests/NodeTest.php
@@ -82,7 +82,7 @@ public function assertTreeNotBroken($table = 'categories')
         $this->assertEquals(array('errors' => null), $actual, "The tree structure of $table is broken!");
     }
 
-    public function dumpTree($items = null)
+    public function dumpTree(?array $items = null)
     {
         if ( ! $items) $items = Category::withTrashed()->defaultOrder()->get();
 
@@ -997,4 +997,4 @@ public function testReplication()
 function all($items)
 {
     return is_array($items) ? $items : $items->all();
-}
\ No newline at end of file
+}

From afdf2f2b74d72d87ea7127dcfa6a62c7fb6b96d9 Mon Sep 17 00:00:00 2001
From: julesgraus <jules.graus@gmail.com>
Date: Fri, 28 Mar 2025 15:59:31 +0100
Subject: [PATCH 2/5] Update composer.json

Fix quote problem due to incorrect rebase / merge
---
 composer.json | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/composer.json b/composer.json
index d1f311c..844bc3d 100644
--- a/composer.json
+++ b/composer.json
@@ -19,8 +19,8 @@
         "php": "^7.2.5|^8.0",
 
         "illuminate/support": "^7.0|^8.0|^9.0|^10.0|^11.0|^12.0",
-        "illuminate/database": "^7.0|^8.0|^9.0|^10.0|^11.0|^12.0"",
-        "illuminate/events": "^7.0|^8.0|^9.0|^10.0|^11.0|^12.0"",
+        "illuminate/database": "^7.0|^8.0|^9.0|^10.0|^11.0|^12.0",
+        "illuminate/events": "^7.0|^8.0|^9.0|^10.0|^11.0|^12.0",
         "laravel/serializable-closure": "^2.0"
     },
     "autoload": {

From f76e11913cad779f5031b8e28b953696e5697cb1 Mon Sep 17 00:00:00 2001
From: Jules <jules.graus@gmail.com>
Date: Fri, 28 Mar 2025 19:25:49 +0100
Subject: [PATCH 3/5] Exclude data and model dirs in phpunit configuration.
 PhpUnit sees them as tests files because of the suffix defined in the phpunit
 config.

---
 phpunit.xml       | 2 ++
 src/NodeTrait.php | 2 +-
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/phpunit.xml b/phpunit.xml
index 10f1f41..fac2e3f 100644
--- a/phpunit.xml
+++ b/phpunit.xml
@@ -3,6 +3,8 @@
   <testsuites>
     <testsuite name="Package Test Suite">
       <directory suffix=".php">./tests/</directory>
+      <exclude>./tests/data</exclude>
+      <exclude>./tests/models</exclude>
     </testsuite>
   </testsuites>
   <source>
diff --git a/src/NodeTrait.php b/src/NodeTrait.php
index 38db1cb..9d20e6b 100644
--- a/src/NodeTrait.php
+++ b/src/NodeTrait.php
@@ -746,7 +746,7 @@ public function newCollection(array $models = array())
      *
      * Use `children` key on `$attributes` to create child nodes.
      */
-    public static function create(array $attributes = [], self|null $parent = null)
+    public static function create(array $attributes = [], ?self $parent = null)
     {
         $children = Arr::pull($attributes, 'children');
 

From d77cedb98db6e1ba093a952724f44cc952314e36 Mon Sep 17 00:00:00 2001
From: Jules <jules.graus@gmail.com>
Date: Tue, 8 Apr 2025 18:17:18 +0200
Subject: [PATCH 4/5] Drop php 8.0 support and earlier

---
 composer.json | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/composer.json b/composer.json
index 844bc3d..c4d4c64 100644
--- a/composer.json
+++ b/composer.json
@@ -16,8 +16,7 @@
         }
     ],
     "require": {
-        "php": "^7.2.5|^8.0",
-
+        "php": "^8.0",
         "illuminate/support": "^7.0|^8.0|^9.0|^10.0|^11.0|^12.0",
         "illuminate/database": "^7.0|^8.0|^9.0|^10.0|^11.0|^12.0",
         "illuminate/events": "^7.0|^8.0|^9.0|^10.0|^11.0|^12.0",

From 436fc85332db3a4172ce7fe7a2a7b42ab2f1b88f Mon Sep 17 00:00:00 2001
From: Jules <jules.graus@gmail.com>
Date: Tue, 8 Apr 2025 20:02:41 +0200
Subject: [PATCH 5/5] Update test workflow to drop support for php 8.0 and
 older

---
 .github/workflows/run-tests.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml
index e5b672b..4a4efbd 100644
--- a/.github/workflows/run-tests.yml
+++ b/.github/workflows/run-tests.yml
@@ -22,7 +22,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        php: [7.2, 7.3, 7.4, 8.0, 8.1, '8.2']
+        php: [8.1, 8.2]
 
     name: P${{ matrix.php }}