Passed
Push — master ( ca8ef0...366131 )
by SignpostMarv
05:50
created

RebuildAfterInsert()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 6
ccs 3
cts 3
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
* Base daft objects.
4
*
5
* @author SignpostMarv
6
*/
7
declare(strict_types=1);
8
9
namespace SignpostMarv\DaftObject;
10
11
use BadMethodCallException;
12
use InvalidArgumentException;
13
use RuntimeException;
14
15
/**
16
* @template T as DaftNestedWriteableObject
17
*
18
* @template-extends DaftObjectMemoryTree<T>
19
*
20
* @template-implements DaftNestedWriteableObjectTree<T>
21
*/
22
abstract class DaftWriteableObjectMemoryTree extends DaftObjectMemoryTree implements DaftNestedWriteableObjectTree
23
{
24
    const DEFINITELY_BELOW = false;
25
26
    const EXCLUDE_ROOT = false;
27
28
    const INSERT_AFTER = false;
29
30
    const LIMIT_ONE = 1;
31
32
    const RELATIVE_DEPTH_SAME = 0;
33
34
    const INT_ARG_INDEX_SECOND = 2;
35
36
    /**
37
    * {@inheritdoc}
38
    *
39
    * @psalm-return T
40
    */
41 62
    public function RecallDaftNestedWriteableObjectOrThrow($id) : DaftNestedWriteableObject
42
    {
43
        /**
44
        * @var DaftNestedWriteableObject|null
45
        *
46
        * @psalm-var T|null
47
        */
48 62
        $out = $this->RecallDaftNestedObjectOrThrow($id);
49
50 60
        if (is_null($out)) {
51
            throw new DaftObjectNotRecalledException(
52
                'Argument 1 passed to ' .
53
                DaftNestedWriteableObjectTree::class .
54
                '::RecallDaftNestedWriteableObjectOrThrow() did not resolve to an instance of ' .
55
                DaftNestedWriteableObject::class .
56
                ' from ' .
57
                static::class .
58
                '::RecallDaftObject()'
59
            );
60
        }
61
62 60
        return $out;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $out returns the type SignpostMarv\DaftObject\DaftNestedObject which includes types incompatible with the type-hinted return SignpostMarv\DaftObject\DaftNestedWriteableObject.
Loading history...
63
    }
64
65
    /**
66
    * @psalm-param T $newLeaf
67
    * @psalm-param T $referenceLeaf
68
    *
69
    * @psalm-return T
70
    */
71 84
    public function ModifyDaftNestedObjectTreeInsert(
72
        DaftNestedWriteableObject $newLeaf,
73
        DaftNestedWriteableObject $referenceLeaf,
74
        bool $before = self::INSERT_AFTER,
75
        bool $above = null
76
    ) : DaftNestedWriteableObject {
77 84
        if ($newLeaf->GetId() === $referenceLeaf->GetId()) {
78 40
            throw new InvalidArgumentException('Cannot modify leaf relative to itself!');
79
        }
80
81 60
        if ((bool) $above) {
82 48
            $this->ModifyDaftNestedObjectTreeInsertAbove($newLeaf, $referenceLeaf);
83 32
        } elseif (self::DEFINITELY_BELOW === $above) {
84 6
            $this->ModifyDaftNestedObjectTreeInsertBelow($newLeaf, $referenceLeaf);
85
        } else {
86 28
            $this->ModifyDaftNestedObjectTreeInsertAdjacent($newLeaf, $referenceLeaf, $before);
87
        }
88
89 60
        return $this->RebuildAfterInsert($newLeaf);
90
    }
91
92
    /**
93
    * @param DaftNestedWriteableObject|scalar|(scalar|array|object|null)[] $leaf
94
    * @param DaftNestedWriteableObject|scalar|(scalar|array|object|null)[] $referenceId
95
    *
96
    * @psalm-param T|scalar|(scalar|array|object|null)[] $leaf
97
    * @psalm-param T|scalar|(scalar|array|object|null)[] $referenceId
98
    *
99
    * @psalm-return T
100
    */
101 48
    public function ModifyDaftNestedObjectTreeInsertLoose(
102
        $leaf,
103
        $referenceId,
104
        bool $before = self::INSERT_AFTER,
105
        bool $above = null
106
    ) : DaftNestedWriteableObject {
107
        /**
108
        * @var DaftNestedWriteableObject
109
        *
110
        * @psalm-var T
111
        */
112 48
        $leaf = $this->MaybeGetLeafOrThrow($leaf);
113
114 24
        $reference = $this->MaybeRecallLoose($referenceId);
115
116 24
        return $this->ModifyDaftNestedObjectTreeInsertMaybeLooseIntoTree(
117 24
            $this,
118 24
            $leaf,
119 24
            $reference,
120 24
            $referenceId === $this->GetNestedObjectTreeRootId(),
121 24
            $before,
122 24
            $above
123
        );
124
    }
125
126
    /**
127
    * @psalm-param T $root
128
    * @psalm-param T|null $replacementRoot
129
    */
130 8
    public function ModifyDaftNestedObjectTreeRemoveWithObject(
131
        DaftNestedWriteableObject $root,
132
        ? DaftNestedWriteableObject $replacementRoot
133
    ) : int {
134
        if (
135 8
            $this->CountDaftNestedObjectTreeWithObject(
136 8
                $root,
137 8
                false,
138 8
                null
139 8
            ) > AbstractArrayBackedDaftNestedObject::COUNT_EXPECT_NON_EMPTY &&
140 8
            is_null($replacementRoot)
141
        ) {
142 2
            throw new BadMethodCallException('Cannot leave orphan objects in a tree');
143
        }
144
145 6
        $root = $this->StoreThenRetrieveFreshLeaf($root);
146
147 6
        if ( ! is_null($replacementRoot)) {
148 4
            $this->ModifyDaftNestedObjectTreeRemoveWithObjectPrepareRemovalAndRebuild(
149 4
                $root,
150 4
                $replacementRoot
151
            );
152
        }
153
154 6
        $this->RemoveDaftObject($root);
155
156 6
        $this->RebuildTreeInefficiently();
157
158 6
        return $this->CountDaftNestedObjectFullTree();
159
    }
160
161
    /**
162
    * @param scalar|(scalar|array|object|null)[] $root
163
    * @param scalar|(scalar|array|object|null)[]|null $replacementRoot
164
    */
165 12
    public function ModifyDaftNestedObjectTreeRemoveWithId($root, $replacementRoot) : int
166
    {
167 12
        $rootObject = $this->RecallDaftObject($root);
168
169 12
        $resp = null;
170
171 12
        if ($rootObject instanceof DaftNestedWriteableObject) {
172 12
            $resp = $this->ModifyDaftNestedObjectTreeRemoveWithIdUsingRootObject(
173 12
                $replacementRoot,
174 12
                $rootObject
175
            );
176
        }
177
178 8
        return is_int($resp) ? $resp : $this->CountDaftNestedObjectFullTree();
179
    }
180
181
    /**
182
    * @psalm-param T $leaf
183
    *
184
    * @psalm-return T
185
    */
186 62
    public function StoreThenRetrieveFreshLeaf(
187
        DaftNestedWriteableObject $leaf
188
    ) : DaftNestedWriteableObject {
189 62
        $this->RememberDaftObject($leaf);
190 62
        $this->ForgetDaftObject($leaf);
191 62
        $this->ForgetDaftObjectById($leaf->GetId());
192
193 62
        return $this->RecallDaftNestedWriteableObjectOrThrow($leaf->GetId());
194
    }
195
196
    /**
197
    * @psalm-param T $object
198
    */
199 88
    public function RememberDaftObject(SuitableForRepositoryType $object) : void
200
    {
201
        /**
202
        * @var DaftNestedWriteableObject
203
        *
204
        * @psalm-var T
205
        */
206 88
        $object = $object;
207
208 88
        $left = $object->GetIntNestedLeft();
0 ignored issues
show
Bug introduced by
The method GetIntNestedLeft() does not exist on SignpostMarv\DaftObject\SuitableForRepositoryType. It seems like you code against a sub-type of SignpostMarv\DaftObject\SuitableForRepositoryType such as SignpostMarv\DaftObject\DaftNestedObject. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

208
        /** @scrutinizer ignore-call */ 
209
        $left = $object->GetIntNestedLeft();
Loading history...
209 88
        $right = $object->GetIntNestedRight();
0 ignored issues
show
Bug introduced by
The method GetIntNestedRight() does not exist on SignpostMarv\DaftObject\SuitableForRepositoryType. It seems like you code against a sub-type of SignpostMarv\DaftObject\SuitableForRepositoryType such as SignpostMarv\DaftObject\DaftNestedObject. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

209
        /** @scrutinizer ignore-call */ 
210
        $right = $object->GetIntNestedRight();
Loading history...
210 88
        $level = $object->GetIntNestedLevel();
0 ignored issues
show
Bug introduced by
The method GetIntNestedLevel() does not exist on SignpostMarv\DaftObject\SuitableForRepositoryType. It seems like you code against a sub-type of SignpostMarv\DaftObject\SuitableForRepositoryType such as SignpostMarv\DaftObject\DaftNestedObject. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

210
        /** @scrutinizer ignore-call */ 
211
        $level = $object->GetIntNestedLevel();
Loading history...
211
212 88
        if (0 === $left && 0 === $right && 0 === $level) {
213 86
            $fullTreeCount = $this->CountDaftNestedObjectFullTree();
214
215 86
            if ($fullTreeCount > AbstractArrayBackedDaftNestedObject::COUNT_EXPECT_NON_EMPTY) {
216 60
                $tree = $this->RecallDaftNestedObjectFullTree();
217
218
                /**
219
                * @var DaftNestedWriteableObject
220
                *
221
                * @psalm-var T
222
                */
223 60
                $end = end($tree);
224
225 60
                $left = $end->GetIntNestedRight() + 1;
226
            } else {
227 86
                $left = $fullTreeCount + $fullTreeCount;
228
            }
229
230 86
            $object->SetIntNestedLeft($left);
0 ignored issues
show
Bug introduced by
The method SetIntNestedLeft() does not exist on SignpostMarv\DaftObject\SuitableForRepositoryType. It seems like you code against a sub-type of SignpostMarv\DaftObject\SuitableForRepositoryType such as SignpostMarv\DaftObject\DaftNestedWriteableObject or SignpostMarv\DaftObject\...yBackedDaftNestedObject. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

230
            $object->/** @scrutinizer ignore-call */ 
231
                     SetIntNestedLeft($left);
Loading history...
231 86
            $object->SetIntNestedRight($left + 1);
0 ignored issues
show
Bug introduced by
The method SetIntNestedRight() does not exist on SignpostMarv\DaftObject\SuitableForRepositoryType. It seems like you code against a sub-type of SignpostMarv\DaftObject\SuitableForRepositoryType such as SignpostMarv\DaftObject\DaftNestedWriteableObject or SignpostMarv\DaftObject\...yBackedDaftNestedObject. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

231
            $object->/** @scrutinizer ignore-call */ 
232
                     SetIntNestedRight($left + 1);
Loading history...
232
        }
233
234 88
        parent::RememberDaftObject($object);
235 88
    }
236
237
    /**
238
    * @psalm-param T $newLeaf
239
    * @psalm-param T $referenceLeaf
240
    */
241 52
    protected function ModifyDaftNestedObjectTreeInsertAdjacent(
242
        DaftNestedWriteableObject $newLeaf,
243
        DaftNestedWriteableObject $referenceLeaf,
244
        bool $before
245
    ) : void {
246
        /**
247
        * @var array<int, DaftNestedWriteableObject>
248
        *
249
        * @psalm-var array<int, T>
250
        */
251 52
        $siblings = $this->SiblingsExceptLeaf($newLeaf, $referenceLeaf);
252
253 52
        $siblingIds = [];
254 52
        $siblingSort = [];
255 52
        $j = count($siblings);
256
257 52
        foreach ($siblings as $leaf) {
258
            /**
259
            * @var scalar|(scalar|array|object|null)[]
260
            */
261 28
            $siblingId = $leaf->GetId();
262 28
            $siblingIds[] = $siblingId;
263 28
            $siblingSort[] = $leaf->GetIntNestedSortOrder();
264
        }
265
266 52
        $pos = array_search($referenceLeaf->GetId(), $siblingIds, true);
267
268 52
        if (false === $pos) {
269 24
            throw new RuntimeException('Reference leaf not found in siblings tree!');
270
        }
271
272 28
        for ($i = 0; $i < $j; ++$i) {
273 28
            $siblings[$i]->SetIntNestedSortOrder(
274 28
                $siblingSort[$i] +
275 28
                (($before ? ($i < $pos) : ($i <= $pos)) ? self::DECREMENT : self::INCREMENT)
276
            );
277 28
            $this->StoreThenRetrieveFreshLeaf($siblings[$i]);
278
        }
279
280 28
        $newLeaf->SetIntNestedSortOrder($siblingSort[$pos]);
281 28
        $newLeaf->AlterDaftNestedObjectParentId($referenceLeaf->ObtainDaftNestedObjectParentId());
282
283 28
        $this->StoreThenRetrieveFreshLeaf($newLeaf);
284 28
    }
285
286 60
    protected function RebuildTreeInefficiently() : void
287
    {
288 60
        $rebuilder = new InefficientDaftNestedRebuild($this);
289 60
        $rebuilder->RebuildTree();
290 60
    }
291
292 24
    private function ModifyDaftNestedObjectTreeInsertMaybeLooseIntoTree(
293
        DaftNestedWriteableObjectTree $tree,
294
        DaftNestedWriteableObject $leaf,
295
        ? DaftNestedWriteableObject $reference,
296
        bool $isRoot,
0 ignored issues
show
Unused Code introduced by
The parameter $isRoot is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

296
        /** @scrutinizer ignore-unused */ bool $isRoot,

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
297
        bool $before,
298
        ? bool $above
299
    ) : DaftNestedWriteableObject {
300 24
        if ($reference instanceof DaftNestedWriteableObject) {
301 18
            return $tree->ModifyDaftNestedObjectTreeInsert($leaf, $reference, $before, $above);
302
        }
303
304 24
        return $this->ModifyDaftNestedObjectTreeInsertLooseIntoTree($leaf, $before, $above);
305
    }
306
307
    /**
308
    * @psalm-param T $newLeaf
309
    *
310
    * @psalm-return T
311
    */
312 60
    private function RebuildAfterInsert(
313
        DaftNestedWriteableObject $newLeaf
314
    ) : DaftNestedWriteableObject {
315 60
        $this->RebuildTreeInefficiently();
316
317 60
        return $this->RecallDaftNestedWriteableObjectOrThrow($newLeaf->GetId());
318
    }
319
320
    /**
321
    * @psalm-param T $root
322
    * @psalm-param T $replacementRoot
323
    */
324 4
    private function ModifyDaftNestedObjectTreeRemoveWithObjectPrepareRemovalAndRebuild(
325
        DaftNestedWriteableObject $root,
326
        DaftNestedWriteableObject $replacementRoot
327
    ) : void {
328
        /**
329
        * @var scalar|(scalar|array|object|null)[]
330
        */
331 4
        $replacementRootId = $this->StoreThenRetrieveFreshLeaf($replacementRoot)->GetId();
332
333 4
        $this->UpdateRoots($root, $replacementRootId);
334 4
    }
335
336
    /**
337
    * @param scalar|(scalar|array|object|null)[] $replacementRootId
338
    *
339
    * @psalm-param T $root
340
    */
341 10
    private function UpdateRoots(DaftNestedWriteableObject $root, $replacementRootId) : void
342
    {
343
        /**
344
        * @var array<int, DaftNestedWriteableObject>
345
        *
346
        * @psalm-var array<int, T>
347
        */
348 10
        $alterThese = $this->RecallDaftNestedObjectTreeWithObject($root, false, self::LIMIT_ONE);
349
350 10
        foreach ($alterThese as $alter) {
351 4
            $alter->AlterDaftNestedObjectParentId($replacementRootId);
352 4
            $this->RememberDaftObject($alter);
353
        }
354 10
    }
355
356
    /**
357
    * @param DaftNestedWriteableObject|scalar|(scalar|array|object|null)[] $leaf
358
    *
359
    * @psalm-param T|scalar|(scalar|array|object|null)[] $leaf
360
    *
361
    * @psalm-return T
362
    */
363 48
    private function MaybeGetLeafOrThrow($leaf) : DaftNestedWriteableObject
364
    {
365 48
        if ($leaf === $this->GetNestedObjectTreeRootId()) {
366 24
            throw new InvalidArgumentException('Cannot pass root id as new leaf');
367 24
        } elseif ($leaf instanceof DaftNestedWriteableObject) {
368 24
            return $this->StoreThenRetrieveFreshLeaf($leaf);
369
        }
370
371
        /**
372
        * @psalm-var scalar|(scalar|array|object|null)[]
373
        */
374 16
        $leaf = $leaf;
375
376 16
        return $this->RecallDaftNestedWriteableObjectOrThrow($leaf);
377
    }
378
379
    /**
380
    * @param DaftNestedWriteableObject|scalar|(scalar|array|object|null)[] $leaf
381
    *
382
    * @psalm-param T|scalar|(scalar|array|object|null)[] $leaf
383
    */
384 24
    private function MaybeRecallLoose($leaf) : ? DaftNestedWriteableObject
385
    {
386 24
        if ($leaf instanceof DaftNestedWriteableObject) {
387 2
            return $leaf;
388
        }
389
390
        /**
391
        * @var scalar|(scalar|array|object|null)[]
392
        */
393 24
        $leaf = $leaf;
394
395
        /**
396
        * @var DaftNestedWriteableObject|null
397
        *
398
        * @psalm-var T|null
399
        */
400 24
        $out = $this->RecallDaftObject($leaf);
401
402 24
        return $out;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $out could return the type SignpostMarv\DaftObject\SuitableForRepositoryType which includes types incompatible with the type-hinted return SignpostMarv\DaftObject\...tedWriteableObject|null. Consider adding an additional type-check to rule them out.
Loading history...
403
    }
404
405
    /**
406
    * @psalm-param T $leaf
407
    *
408
    * @psalm-return T
409
    */
410 24
    private function ModifyDaftNestedObjectTreeInsertLooseIntoTree(
411
        DaftNestedWriteableObject $leaf,
412
        bool $before,
413
        ? bool $above
414
    ) : DaftNestedWriteableObject {
415
        /**
416
        * @var array<int, DaftNestedWriteableObject>
417
        *
418
        * @psalm-var array<int, T>
419
        */
420 24
        $leaves = array_filter(
421 24
            $this->RecallDaftNestedObjectFullTree(self::RELATIVE_DEPTH_SAME),
422
            /**
423
            * @psalm-param T $e
424
            */
425
            function (DaftNestedWriteableObject $e) use ($leaf) : bool {
426 24
                return $e->GetId() !== $leaf->GetId();
427 24
            }
428
        );
429
430 24
        if (count($leaves) < 1) {
431 24
            $leaf->SetIntNestedLeft(0);
432 24
            $leaf->SetIntNestedRight(1);
433 24
            $leaf->SetIntNestedLevel(0);
434 24
            $leaf->AlterDaftNestedObjectParentId($this->GetNestedObjectTreeRootId());
435
436 24
            return $this->StoreThenRetrieveFreshLeaf($leaf);
437
        }
438
439
        /**
440
        * @psalm-var T
441
        */
442 24
        $reference = $before ? current($leaves) : end($leaves);
443
444 24
        return $this->ModifyDaftNestedObjectTreeInsert($leaf, $reference, $before, $above);
445
    }
446
447
    /**
448
    * @param scalar|(scalar|array|object|null)[] $replacementRoot
449
    *
450
    * @psalm-param T $rootObject
451
    */
452 6
    private function UpdateRemoveThenRebuild(
453
        DaftNestedWriteableObject $rootObject,
454
        $replacementRoot
455
    ) : void {
456 6
        $this->UpdateRoots($rootObject, $replacementRoot);
457
458 6
        $this->RemoveDaftObject($rootObject);
459
460 6
        $this->RebuildTreeInefficiently();
461 6
    }
462
463
    /**
464
    * @psalm-param T $newLeaf
465
    * @psalm-param T $referenceLeaf
466
    */
467 48
    private function ModifyDaftNestedObjectTreeInsertAbove(
468
        DaftNestedWriteableObject $newLeaf,
469
        DaftNestedWriteableObject $referenceLeaf
470
    ) : void {
471 48
        $newLeaf->AlterDaftNestedObjectParentId($referenceLeaf->ObtainDaftNestedObjectParentId());
472 48
        $referenceLeaf->AlterDaftNestedObjectParentId($newLeaf->GetId());
473
474 48
        $this->StoreThenRetrieveFreshLeaf($newLeaf);
475 48
        $this->StoreThenRetrieveFreshLeaf($referenceLeaf);
476 48
    }
477
478
    /**
479
    * @psalm-param T $newLeaf
480
    * @psalm-param T $referenceLeaf
481
    */
482 6
    private function ModifyDaftNestedObjectTreeInsertBelow(
483
        DaftNestedWriteableObject $newLeaf,
484
        DaftNestedWriteableObject $referenceLeaf
485
    ) : void {
486 6
        $newLeaf->AlterDaftNestedObjectParentId($referenceLeaf->GetId());
487 6
        $this->StoreThenRetrieveFreshLeaf($newLeaf);
488 6
    }
489
490
    /**
491
    * @psalm-param T $newLeaf
492
    * @psalm-param T $referenceLeaf
493
    *
494
    * @psalm-return array<int, T>
495
    */
496 52
    private function SiblingsExceptLeaf(
497
        DaftNestedWriteableObject $newLeaf,
498
        DaftNestedWriteableObject $referenceLeaf
499
    ) : array {
500
        /**
501
        * @var array<int, DaftNestedWriteableObject>
502
        *
503
        * @psalm-var array<int, T>
504
        */
505 52
        $siblings = $this->RecallDaftNestedObjectTreeWithId(
506 52
            $referenceLeaf->ObtainDaftNestedObjectParentId(),
507 52
            self::EXCLUDE_ROOT,
508 52
            self::RELATIVE_DEPTH_SAME
509
        );
510
511 52
        $siblings = array_values(array_filter(
512 52
            $siblings,
513
            /**
514
            * @psalm-param T $leaf
515
            */
516
            function (DaftNestedWriteableObject $leaf) use ($newLeaf) : bool {
517 28
                return $leaf->GetId() !== $newLeaf->GetId();
518 52
            }
519
        ));
520
521 52
        return $siblings;
522
    }
523
524
    /**
525
    * @param scalar|(scalar|array|object|null)[]|null $replacementRoot
526
    *
527
    * @psalm-param T $rootObject
528
    */
529 12
    private function ModifyDaftNestedObjectTreeRemoveWithIdUsingRootObject(
530
        $replacementRoot,
531
        DaftNestedWriteableObject $rootObject
532
    ) : ? int {
533
        if (
534 12
            $this->CountDaftNestedObjectTreeWithObject(
535 12
                $rootObject,
536 12
                false,
537 12
                null
538 12
            ) > AbstractArrayBackedDaftNestedObject::COUNT_EXPECT_NON_EMPTY &&
539 12
            is_null($replacementRoot)
540
        ) {
541 2
            throw new BadMethodCallException('Cannot leave orphan objects in a tree');
542
        } elseif (
543 10
            ! is_null($replacementRoot) &&
544 10
            $replacementRoot !== $this->GetNestedObjectTreeRootId()
545
        ) {
546 4
            return $this->ModifyDaftNestedObjectTreeRemoveWithObject(
547 4
                $rootObject,
548 4
                $this->RecallDaftNestedWriteableObjectOrThrow($replacementRoot)
549
            );
550
        }
551
552
        /**
553
        * @var scalar|(scalar|array|object|null)[]
554
        */
555 6
        $replacementRoot = $replacementRoot;
556
557 6
        $this->UpdateRemoveThenRebuild($rootObject, $replacementRoot);
558
559 6
        return null;
560
    }
561
}
562