Test Failed
Push — master ( bc6ffe...852abc )
by SignpostMarv
02:22
created

ModifyDaftNestedObjectTreeInsertInefficient()   F

Complexity

Conditions 16
Paths 1296

Size

Total Lines 179
Code Lines 108

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 63
CRAP Score 21.8702

Importance

Changes 0
Metric Value
cc 16
eloc 108
nc 1296
nop 4
dl 0
loc 179
ccs 63
cts 88
cp 0.7159
crap 21.8702
rs 2
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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
abstract class DaftWriteableObjectMemoryTree extends DaftObjectMemoryTree implements DaftNestedWriteableObjectTree
16
{
17
    public function ModifyDaftNestedObjectTreeInsertBefore(
18
        DaftNestedWriteableObject $newLeaf,
19
        DaftNestedWriteableObject $referenceLeaf
20
    ) : DaftNestedWriteableObject {
21
        return $this->ModifyDaftNestedObjectTreeInsertInefficient($newLeaf, $referenceLeaf, true, null);
22
    }
23
24
    public function ModifyDaftNestedObjectTreeInsertAfter(
25
        DaftNestedWriteableObject $newLeaf,
26
        DaftNestedWriteableObject $referenceLeaf
27
    ) : DaftNestedWriteableObject {
28
        return $this->ModifyDaftNestedObjectTreeInsertInefficient($newLeaf, $referenceLeaf, false, null);
29
    }
30
31
    /**
32
    * @param mixed $newLeaf
33
    * @param mixed $referenceLeaf
34
    */
35 2
    public function ModifyDaftNestedObjectTreeInsertBeforeId(
36
        $newLeaf,
37
        $referenceLeaf
38
    ) : DaftNestedWriteableObject {
39 2
        return $this->ModifyDaftNestedObjectTreeInsertId($newLeaf, $referenceLeaf, true);
40
    }
41
42
    /**
43
    * @param mixed $newLeaf
44
    * @param mixed $referenceLeaf
45
    */
46 10
    public function ModifyDaftNestedObjectTreeInsertAfterId(
47
        $newLeaf,
48
        $referenceLeaf
49
    ) : DaftNestedWriteableObject {
50 10
        return $this->ModifyDaftNestedObjectTreeInsertId($newLeaf, $referenceLeaf, false);
51
    }
52
53 4
    public function ModifyDaftNestedObjectTreeInsertBelow(
54
        DaftNestedWriteableObject $newLeaf,
55
        DaftNestedWriteableObject $referenceLeaf
56
    ) : DaftNestedWriteableObject {
57 4
        return $this->ModifyDaftNestedObjectTreeInsertInefficient($referenceLeaf, $newLeaf, true, true);
58
    }
59 4
60
    /**
61 4
    * @param mixed $newLeafId
62
    * @param mixed $referenceLeafId
63
    */
64
    public function ModifyDaftNestedObjectTreeInsertBelowId(
65 4
        $newLeafId,
66
        $referenceLeafId
67
    ) : DaftNestedWriteableObject {
68
        if ($newLeafId === $this->GetNestedObjectTreeRootId()) {
69
            throw new InvalidArgumentException('Cannot use root ids as argument 1!');
70
        } elseif ($newLeafId instanceof DaftNestedWriteableObject) {
71
            $newLeafId = $this->StoreThenRetrieveFreshCopy($newLeafId)->GetId();
72 6
        }
73
74
        $newLeaf = $this->RecallDaftObject($newLeafId);
75
76
        if ( ! ($newLeaf instanceof DaftNestedWriteableObject)) {
77 6
            throw new InvalidArgumentException('Leaf does not exist in tree!');
78 6
        } elseif ($referenceLeafId === $this->GetNestedObjectTreeRootId()) {
79
            $tree = array_filter(
80
                $this->RecallDaftNestedObjectFullTree(0),
81
                function (DaftNestedWriteableObject $leaf) use ($newLeaf) : bool {
82
                    return $leaf->GetId() !== $newLeaf->GetId();
83
                }
84
            );
85
86 6
            if (count($tree) < 1) {
87
                $newLeaf->SetIntNestedLeft(0);
88
                $newLeaf->SetIntNestedRight(1);
89
                $newLeaf->SetIntNestedLevel(0);
90
                $newLeaf->AlterDaftNestedObjectParentId($this->GetNestedObjectTreeRootId());
91 6
92
                return $this->StoreThenRetrieveFreshCopy($newLeaf);
93
            }
94
95
            $referenceLeaf = end($tree);
96
        } else {
97 6
            $referenceLeaf = $this->RecallDaftObject($referenceLeafId);
98 4
        }
99 6
100
        if ( ! ($referenceLeaf instanceof DaftNestedWriteableObject)) {
101 6
            throw new RuntimeException('Could not retrieve reference leaf from tree!');
102 6
        }
103
104
        return $this->ModifyDaftNestedObjectTreeInsertInefficient($newLeaf, $referenceLeaf, false, false);
105
    }
106
107
    public function ModifyDaftNestedObjectTreeInsertAbove(
108 6
        DaftNestedWriteableObject $newLeaf,
109 2
        DaftNestedWriteableObject $referenceLeaf
110 6
    ) : DaftNestedWriteableObject {
111
        return $this->ModifyDaftNestedObjectTreeInsertInefficient($newLeaf, $referenceLeaf, false, true);
112 6
    }
113 2
114
    /**
115
    * @param mixed $newLeafId
116
    * @param mixed $referenceLeafId
117 6
    */
118 6
    public function ModifyDaftNestedObjectTreeInsertAboveId(
119
        $newLeafId,
120
        $referenceLeafId
121
    ) : DaftNestedWriteableObject {
122
        if ($referenceLeafId === $this->GetNestedObjectTreeRootId()) {
123
            throw new InvalidArgumentException('Cannot insert leaf above root!');
124
        }
125
126
        /**
127 6
        * @var DaftNestedWriteableObject|null $newLeaf
128 4
        */
129
        $newLeaf = $this->RecallDaftObject($newLeafId);
130
131 4
        /**
132
        * @var DaftNestedWriteableObject|null $referenceLeaf
133
        */
134 4
        $referenceLeaf = $this->RecallDaftObject($referenceLeafId);
135 4
136 4
        if ( ! ($newLeaf instanceof DaftNestedWriteableObject)) {
137
            throw new InvalidArgumentException(sprintf(
138 2
                'Argument 1 passed to %s was not found to be in this instance of %s',
139
                __METHOD__,
140
                static::class
141 4
            ));
142
        } elseif ( ! ($referenceLeaf instanceof DaftNestedWriteableObject)) {
143
            throw new InvalidArgumentException(sprintf(
144
                'Argument 2 passed to %s was not found to be in this instance of %s',
145 4
                __METHOD__,
146
                static::class
147 4
            ));
148 2
        }
149 2
150
        return $this->ModifyDaftNestedObjectTreeInsertAbove($newLeaf, $referenceLeaf);
151 2
    }
152 2
153
    public function ModifyDaftNestedObjectTreeRemoveWithObject(
154
        DaftNestedWriteableObject $root,
155 2
        ? DaftNestedWriteableObject $replacementRoot
156 2
    ) : int {
157 2
        if (
158 2
            $this->CountDaftNestedObjectTreeWithObject($root, false, null) > 0 &&
159 2
            is_null($replacementRoot)
160
        ) {
161 2
            throw new BadMethodCallException('Cannot leave orphan objects in a tree');
162
        }
163
164
        $root = $this->StoreThenRetrieveFreshCopy($root);
165
166
        $right = $root->GetIntNestedRight();
167 2
        $width = ($right - $root->GetIntNestedLeft()) + 1;
168
169 2
        $this->ModifyDaftNestedObjectTreeForRemoval($right, $width);
170
171 2
        if ( ! is_null($replacementRoot)) {
172 2
            $replacementRoot = $this->StoreThenRetrieveFreshCopy($replacementRoot);
173 2
174 2
            /**
175
            * @var DaftNestedWriteableObject $alter
176 2
            */
177
            foreach ($this->RecallDaftNestedObjectTreeWithObject($root, false, 1) as $alter) {
178
                $alter = $this->StoreThenRetrieveFreshCopy($alter);
179 2
                $this->ModifyDaftNestedObjectTreeInsertBelow($alter, $replacementRoot);
180
            }
181
        }
182
183
        $this->RemoveDaftObject($root);
184
185
        return $this->CountDaftNestedObjectFullTree();
186
    }
187 2
188
    /**
189 2
    * {@inheritdoc}
190
    */
191 2
    public function ModifyDaftNestedObjectTreeRemoveWithId($root, $replacementRoot) : int
192 2
    {
193
        $rootObject = $this->RecallDaftObject($root);
194
195 2
        if ( ! ($rootObject instanceof DaftNestedWriteableObject)) {
196
            return $this->CountDaftNestedObjectFullTree();
197 2
        }
198
199 2
        if (
200
            ! is_null($replacementRoot) &&
201
            $replacementRoot !== $this->GetNestedObjectTreeRootId()
202
        ) {
203 2
            $replacementRootObject = $this->RecallDaftObject($replacementRoot);
204
205
            if ( ! ($replacementRootObject instanceof DaftNestedWriteableObject)) {
206 4
                throw new InvalidArgumentException(
207
                    'Could not locate replacement root, cannot leave orphan objects!'
208
                );
209
            }
210 4
211
            return $this->ModifyDaftNestedObjectTreeRemoveWithObject(
212
                $rootObject,
213
                $replacementRootObject
214
            );
215
        }
216
217 6
        if (
218
            $this->CountDaftNestedObjectTreeWithObject($rootObject, false, null) > 0 &&
219
            is_null($replacementRoot)
220
        ) {
221 6
            throw new BadMethodCallException('Cannot leave orphan objects in a tree');
222 2
        }
223
224
        /**
225
        * @var DaftNestedWriteableObject $alter
226
        */
227
        foreach ($this->RecallDaftNestedObjectTreeWithObject($rootObject, false, null) as $alter) {
228 4
            $alter = $this->StoreThenRetrieveFreshCopy($alter);
229
            $alter->AlterDaftNestedObjectParentId($replacementRoot);
230
            $this->RememberDaftObject($alter);
231
        }
232
233 4
        $right = $rootObject->GetIntNestedRight();
234
        $width = ($right - $rootObject->GetIntNestedLeft()) + 1;
235 4
236
        $this->ModifyDaftNestedObjectTreeForRemoval($right, $width);
237
238
        $this->RemoveDaftObject($rootObject);
239
240
        return $this->CountDaftNestedObjectFullTree();
241 4
    }
242
243
    protected function RememberDaftObjectData(DefinesOwnIdPropertiesInterface $object) : void
244
    {
245
        static::ThrowIfNotType($object, DaftNestedWriteableObject::class, 1, __METHOD__);
246
247
        parent::RememberDaftObjectData($object);
248
    }
249 4
250
    /**
251
    * @param DaftObject|string $object
252 2
    */
253
    protected static function ThrowIfNotType(
254
        $object,
255
        string $type,
256
        int $argument,
257 2
        string $function
258 2
    ) : void {
259
        if ( ! is_a($object, DaftNestedWriteableObject::class, is_string($object))) {
260
            throw new DaftObjectRepositoryTypeByClassMethodAndTypeException(
261
                $argument,
262
                static::class,
263 2
                $function,
264
                DaftNestedWriteableObject::class,
265 2
                is_string($object) ? $object : get_class($object)
266 2
            );
267
        }
268 2
269
        parent::ThrowIfNotType($object, $type, $argument, $function);
270 2
    }
271
272
    protected function ModifyDaftNestedObjectTreeInsertAlt(
273
        DaftNestedWriteableObject $newLeaf,
274
        DaftNestedWriteableObject $referenceLeaf,
275
        bool $before,
0 ignored issues
show
Unused Code introduced by
The parameter $before 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

275
        /** @scrutinizer ignore-unused */ bool $before,

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...
276
        ? bool $above
277
    ) : DaftNestedWriteableObject {
278
        $newLeaf = $this->StoreThenRetrieveFreshCopy($newLeaf);
279
        $referenceLeaf = $this->StoreThenRetrieveFreshCopy($referenceLeaf);
280
281
        if (true === $above) {
282 2
            $refLeft = $referenceLeaf->GetIntNestedLeft();
283
            $refWidth = ($referenceLeaf->GetIntNestedRight() - $refLeft);
284 2
            $refLevel = $referenceLeaf->GetIntNestedLevel();
285
286
            $newRight = $newLeaf->GetIntNestedRight();
287
            $newLevel = $newLeaf->GetIntNestedLevel();
288
289
            /**
290 2
            * @var DaftNestedWriteableObject $alter
291
            */
292 2
            foreach (
293
                $this->RecallDaftNestedObjectTreeWithObject($referenceLeaf, true, null) as $alter
294 2
            ) {
295 2
                $alterLeft = $alter->GetIntNestedLeft();
296
                $alterRight = $alter->GetIntNestedRight();
297
                $alterWidth = $alterRight - $alterLeft;
298
                $alterLevel = $alter->GetIntNestedLevel();
299 2
300 2
                $alterLeftNew = ($newRight + ($alterLeft - $refLeft));
301
302
                $alter->SetIntNestedLeft($alterLeftNew);
303
                $alter->SetIntNestedRight($alterLeftNew + $alterWidth);
304
                $alter->SetIntNestedLevel($newLevel + ($alterLevel - $refLevel) + 1);
305
306
                $this->StoreThenRetrieveFreshCopy($alter);
307
            }
308
309
            $newLeaf->SetIntNestedRight($newRight + $refWidth + 1);
310
            $referenceLeaf = $this->RecallDaftObject($referenceLeaf->GetId());
311
312
            if ( ! ($referenceLeaf instanceof DaftNestedWriteableObject)) {
313
                throw new RuntimeException('Could not recall leaf from tree!');
314
            }
315
316
            $referenceLeaf->AlterDaftNestedObjectParentId($newLeaf->GetId());
317 2
            $this->StoreThenRetrieveFreshCopy($referenceLeaf);
318 2
        }
319
320
        $newLeaf = $this->StoreThenRetrieveFreshCopy($newLeaf);
321
322
        return $newLeaf;
323
    }
324
325
    protected function ModifyDaftNestedObjectTreeInsertInefficient(
326 2
        DaftNestedWriteableObject $newLeaf,
327
        DaftNestedWriteableObject $referenceLeaf,
328
        bool $before,
329
        ? bool $above
330
    ) : DaftNestedWriteableObject {
331
        $newLeafParent = $newLeaf->ObtainDaftNestedObjectParentId();
332 2
        $referenceParent = $referenceLeaf->ObtainDaftNestedObjectParentId();
333 2
334
        $newLeaf = $this->StoreThenRetrieveFreshCopy($newLeaf);
335 2
        $referenceLeaf = $this->StoreThenRetrieveFreshCopy($referenceLeaf);
336
337 2
        $newLeaf->AlterDaftNestedObjectParentId($newLeafParent);
338
        $referenceLeaf->AlterDaftNestedObjectParentId($referenceParent);
339 2
340
        if (is_null($above)) {
341
            $newLeaf->AlterDaftNestedObjectParentId(
342 14
                $referenceLeaf->ObtainDaftNestedObjectParentId()
343
            );
344 14
        } elseif (false === $above) {
345
            $newLeaf->AlterDaftNestedObjectParentId($referenceLeaf->GetId());
346 14
        } else {
347 14
            $referenceLeaf->AlterDaftNestedObjectParentId($newLeaf->GetId());
348
        }
349
350
        $parentIdXref = [
351
            (array) $this->GetNestedObjectTreeRootId(),
352 16
        ];
353
        $xRefChildren = [
354
            [],
355
        ];
356
        $idXref = [];
357
358 16
        $level = 0;
0 ignored issues
show
Unused Code introduced by
The assignment to $level is dead and can be removed.
Loading history...
359 2
360 2
        $tree = $this->RecallDaftNestedObjectFullTree();
361 2
        $tree[] = $newLeaf;
362 2
        $tree[] = $referenceLeaf;
363 2
364 2
        $uniqueTree = [];
365
366
        $sort = [];
367
368 14
        foreach ($tree as $leaf) {
369 14
            if ( ! in_array($leaf->GetId(), $idXref, true)) {
370
                $idXref[] = $leaf->GetId();
371 8
                $uniqueTree[] = $leaf;
372
                $sort[] = count($sort);
373
            }
374
        }
375
376
        if ($before) {
377 8
            $pos = (int) array_search($referenceLeaf->GetId(), $idXref, true);
378 8
379
            $j = count($sort);
380 8
            for ($i = $pos; $i < $j; ++$i) {
381 8
                ++$sort[$i];
382 8
            }
383 8
384 8
            $newPos = (int) array_search($newLeaf->GetId(), $idXref, true);
385
            $sort[$newPos] = $sort[$pos] - 1;
386 8
        } else {
387 8
            $pos = (int) array_search($referenceLeaf->GetId(), $idXref, true);
388 8
389
            $j = count($sort);
390
            for ($i = $pos + 1; $i < $j; ++$i) {
391
                $sort[$i] += 2;
392
            }
393
394 8
            $newPos = (int) array_search($newLeaf->GetId(), $idXref, true);
395
            $sort[$newPos] = $sort[$pos] + 1;
396 8
        }
397 8
398 8
        $newLeafId = $newLeaf->GetId();
0 ignored issues
show
Unused Code introduced by
The assignment to $newLeafId is dead and can be removed.
Loading history...
399 8
400
        usort(
401 8
            $uniqueTree,
402
            function (
403 8
                DaftNestedWriteableObject $a,
404 8
                DaftNestedWriteableObject $b
405 8
            ) use (
406
                $idXref,
407 8
                $sort
408
            ) : int {
409
                $a = (int) array_search($a->GetId(), $idXref, true);
410 8
                $b = (int) array_search($b->GetId(), $idXref, true);
411 8
412
                return $sort[$a] <=> $sort[$b];
413 8
            }
414
        );
415
416
        $tree = $uniqueTree;
417 8
        unset($uniqueTree);
418 8
419
        foreach ($tree as $leaf) {
420
            $leafParentId = $leaf->ObtainDaftNestedObjectParentId();
421 8
            $pos = array_search($leafParentId, $parentIdXref, true);
422
423 8
            if (false === $pos) {
424
                $parentIdXref[] = $leafParentId;
425
426 8
                /**
427
                * @var int $pos
428
                */
429
                $pos = array_search($leafParentId, $parentIdXref, true);
430
431
                $xRefChildren[$pos] = [];
432 8
            }
433 8
434
            if ( ! in_array($leaf, $xRefChildren[$pos], true)) {
435
                $xRefChildren[$pos][] = $leaf;
436 4
            }
437 4
438
            if ( ! in_array($leaf->GetId(), $idXref, true)) {
439 4
                $idXref[] = $leaf->GetId();
440 4
            }
441 4
        }
442
443 4
        $rebuild = function (
444 2
            DaftNestedWriteableObject $leaf,
445 4
            int $level,
446
            int $n,
447 4
            array $parentIds,
448
            array $ids,
449
            array $children
450
        ) use (
451
            &$rebuild
452 4
        ) : int {
453
            $id = $leaf->GetId();
454
455
            $pos = (int) array_search($id, $ids, true);
0 ignored issues
show
Unused Code introduced by
The assignment to $pos is dead and can be removed.
Loading history...
456
457
            $leaf->SetIntNestedLevel($level);
458
            $leaf->SetIntNestedLeft($n);
459
460
            $parentPos = array_search($id, $parentIds, true);
461 4
462
            if (false !== $parentPos) {
463
                foreach ($children[$parentPos] as $childLeaf) {
464
                    $n = $rebuild(
465
                        $childLeaf,
466
                        $level + 1,
467
                        $n + 1,
468
                        $parentIds,
469
                        $ids,
470
                        $children
471
                    );
472
                }
473
            }
474 4
475
            ++$n;
476
477
            $leaf->SetIntNestedRight($n);
478
479
            $this->StoreThenRetrieveFreshCopy($leaf);
480
481
            return $n + 1;
482
        };
483
484
        $n = 0;
485
486
        foreach ($xRefChildren[0] as $rootLeaf) {
487
            $n = $rebuild(
488
                $rootLeaf,
489
                0,
490
                $n,
491
                $parentIdXref,
492
                $idXref,
493
                $xRefChildren
494
            );
495
        }
496
497
        $newLeaf = $this->RecallDaftObject($newLeaf->GetId());
498
499
        if ( ! ($newLeaf instanceof DaftNestedWriteableObject)) {
500
            throw new RuntimeException('Was not able to retrieve leaf from tree!');
501
        }
502
503
        return $newLeaf;
504
    }
505
506
    /**
507
    * @param mixed $newLeafId
508
    * @param mixed $referenceLeafId
509
    */
510
    protected function ModifyDaftNestedObjectTreeInsertId(
511
        $newLeafId,
512
        $referenceLeafId,
513
        bool $before
514
    ) : DaftNestedWriteableObject {
515
        /**
516
        * @var DaftNestedWriteableObject|null $newLeaf
517
        */
518
        $newLeaf =
519
            ($newLeafId instanceof DaftNestedWriteableObject)
520
                ? $newLeafId
521
                : $this->RecallDaftObject($newLeafId);
522
523
        if ( ! ($newLeaf instanceof DaftNestedWriteableObject)) {
524
            throw new RuntimeException('Leaf could not be retrieved from argument 1!');
525
        }
526
527
        $referenceLeaf = null;
528
529
        if ($referenceLeafId === $this->GetNestedObjectTreeRootId()) {
530 4
            $tree = array_filter(
531
                $this->RecallDaftNestedObjectFullTree(0),
532 4
                function (DaftNestedWriteableObject $leaf) use ($newLeaf) : bool {
533 4
                    return $leaf->GetId() !== $newLeaf->GetId();
534
                }
535 4
            );
536 4
537
            if (count($tree) < 1) {
538
                $newLeaf = $this->StoreThenRetrieveFreshCopy($newLeaf);
539 4
540
                $newLeaf->SetIntNestedLeft(0);
541
                $newLeaf->SetIntNestedRight(1);
542
                $newLeaf->SetIntNestedLevel(0);
543
                $newLeaf->AlterDaftNestedObjectParentId($referenceLeafId);
544
545
                return $this->StoreThenRetrieveFreshCopy($newLeaf);
546
            }
547
548
            $referenceLeaf = $before ? current($tree) : end($tree);
549
550
            return $this->ModifyDaftNestedObjectTreeInsertInefficient(
551
                $newLeaf,
552
                $referenceLeaf,
553
                $before,
554
                null
555
            );
556
        }
557
558
        $referenceLeaf = $this->RecallDaftObject($referenceLeafId);
559
560
        if ( ! ($referenceLeaf instanceof DaftNestedWriteableObject)) {
561
            throw new InvalidArgumentException(
562
                'Specified reference id does not correspond to an object in the tree'
563
            );
564
        }
565 4
566
        return $this->ModifyDaftNestedObjectTreeInsertInefficient($newLeaf, $referenceLeaf, $before, null);
567 4
    }
568
569
    protected function ModifyDaftNestedObjectTreeForRemoval(int $right, int $width) : void
570
    {
571
        /**
572
        * @var DaftNestedWriteableObject $alter
573 4
        */
574
        foreach ($this->RecallDaftNestedObjectFullTree() as $alter) {
575
            $alter = $this->StoreThenRetrieveFreshCopy($alter);
576
577
            $alterLeft = $alter->GetIntNestedLeft();
578
            $alterRight = $alter->GetIntNestedRight();
579
            $changed = false;
580 10
581
            if ($alterRight > $right) {
582
                $alter->SetIntNestedRight($alterRight - $width);
583
                $changed = true;
584
            }
585
            if ($alterLeft > $right) {
586
                $alter->SetIntNestedLeft($alterLeft - $width);
587
                $changed = true;
588
            }
589 10
590 10
            if ($changed) {
591 10
                $this->RememberDaftObject($alter);
592
            }
593 10
        }
594
    }
595
596
    protected function StoreThenRetrieveFreshCopy(
597 10
        DaftNestedWriteableObject $leaf
598
    ) : DaftNestedWriteableObject {
599 10
        $this->RememberDaftObject($leaf);
600
        $this->ForgetDaftObject($leaf);
601 10
        $this->ForgetDaftObjectById($leaf->GetId());
602 10
603 10
        $fresh = $this->RecallDaftObject($leaf->GetId());
604
605 10
        if ( ! ($fresh instanceof DaftNestedWriteableObject)) {
606 10
            throw new RuntimeException('Was not able to obtain a fresh copy of the object!');
607
        }
608
609 10
        return $fresh;
610 10
    }
611
}
612