Passed
Push — master ( 6c8dfe...6e67eb )
by SignpostMarv
03:14
created

TraitWriteableTree   A

Complexity

Total Complexity 21

Size/Duplication

Total Lines 154
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
eloc 66
dl 0
loc 154
ccs 0
cts 66
cp 0
rs 10
c 0
b 0
f 0
wmc 21

6 Methods

Rating   Name   Duplication   Size   Complexity  
A ModifyDaftNestedObjectTreeRemoveWithIdUsingRootObject() 0 28 5
A ModifyDaftNestedObjectTreeInsert() 0 19 4
A ModifyDaftNestedObjectTreeInsertLoose() 0 28 3
A StoreThenRetrieveFreshLeaf() 0 14 2
A ModifyDaftNestedObjectTreeRemoveWithObject() 0 25 4
A ModifyDaftNestedObjectTreeRemoveWithId() 0 14 3
1
<?php
2
/**
3
* Base daft nested 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
trait TraitWriteableTree
16
{
17
    use TraitWriteableTreeUtilities;
18
19
    public function ModifyDaftNestedObjectTreeInsert(
20
        DaftNestedWriteableObject $newLeaf,
21
        DaftNestedWriteableObject $referenceLeaf,
22
        bool $before = false,
23
        bool $above = null
24
    ) : DaftNestedWriteableObject {
25
        if ($newLeaf->GetId() === $referenceLeaf->GetId()) {
26
            throw new InvalidArgumentException('Cannot modify leaf relative to itself!');
27
        }
28
29
        if (true === $above) {
30
            $this->ModifyDaftNestedObjectTreeInsertAbove($newLeaf, $referenceLeaf);
31
        } elseif (false === $above) {
32
            $this->ModifyDaftNestedObjectTreeInsertBelow($newLeaf, $referenceLeaf);
33
        } else {
34
            $this->ModifyDaftNestedObjectTreeInsertAdjacent($newLeaf, $referenceLeaf, $before);
35
        }
36
37
        return $this->RebuildAfterInsert($newLeaf);
38
    }
39
40
    /**
41
    * @param mixed $leaf
42
    * @param mixed $referenceId
43
    */
44
    public function ModifyDaftNestedObjectTreeInsertLoose(
45
        $leaf,
46
        $referenceId,
47
        bool $before = false,
48
        bool $above = null
49
    ) : DaftNestedWriteableObject {
50
        $leaf = $this->MaybeGetLeaf($leaf);
51
52
        $reference = $this->RecallDaftObject($referenceId);
53
        $tree = $this->ThrowIfNotTree();
54
55
        $resp = $this->ModifyDaftNestedObjectTreeInsertMaybeLooseIntoTree(
56
            $tree,
57
            $leaf,
58
            $reference,
59
            $referenceId === $tree->GetNestedObjectTreeRootId(),
60
            $before,
61
            $above
62
        );
63
64
        if ($resp instanceof DaftNestedWriteableObject) {
65
            return $resp;
66
        }
67
68
        throw new InvalidArgumentException(sprintf(
69
            'Argument %u passed to %s() did not resolve to a leaf node!',
70
            is_null($leaf) ? 1 : 2,
71
            __METHOD__
72
        ));
73
    }
74
75
    public function ModifyDaftNestedObjectTreeRemoveWithObject(
76
        DaftNestedWriteableObject $root,
77
        ? DaftNestedWriteableObject $replacementRoot
78
    ) : int {
79
        if (
80
            $this->CountDaftNestedObjectTreeWithObject($root, false, null) > 0 &&
81
            is_null($replacementRoot)
82
        ) {
83
            throw new BadMethodCallException('Cannot leave orphan objects in a tree');
84
        }
85
86
        $root = $this->StoreThenRetrieveFreshLeaf($root);
87
88
        if ( ! is_null($replacementRoot)) {
89
            $this->ModifyDaftNestedObjectTreeRemoveWithObjectPrepareRemovalAndRebuild(
90
                $root,
91
                $replacementRoot
92
            );
93
        }
94
95
        $this->RemoveDaftObject($root);
96
97
        $this->RebuildTreeInefficiently();
98
99
        return $this->CountDaftNestedObjectFullTree();
100
    }
101
102
    /**
103
    * @param mixed $root
104
    * @param scalar|scalar[]|null $replacementRoot
105
    */
106
    public function ModifyDaftNestedObjectTreeRemoveWithId($root, $replacementRoot) : int
107
    {
108
        $rootObject = $this->RecallDaftObject($root);
109
110
        $resp = null;
111
112
        if ($rootObject instanceof DaftNestedWriteableObject) {
113
            $resp = $this->ModifyDaftNestedObjectTreeRemoveWithIdUsingRootObject(
114
                $replacementRoot,
115
                $rootObject
116
            );
117
        }
118
119
        return is_int($resp) ? $resp : $this->CountDaftNestedObjectFullTree();
120
    }
121
122
    public function StoreThenRetrieveFreshLeaf(
123
        DaftNestedWriteableObject $leaf
124
    ) : DaftNestedWriteableObject {
125
        $this->RememberDaftObject($leaf);
126
        $this->ForgetDaftObject($leaf);
127
        $this->ForgetDaftObjectById($leaf->GetId());
128
129
        $fresh = $this->RecallDaftObject($leaf->GetId());
130
131
        if ( ! ($fresh instanceof DaftNestedWriteableObject)) {
132
            throw new RuntimeException('Was not able to obtain a fresh copy of the object!');
133
        }
134
135
        return $fresh;
136
    }
137
138
    /**
139
    * @param scalar|scalar[]|null $replacementRoot
140
    */
141
    protected function ModifyDaftNestedObjectTreeRemoveWithIdUsingRootObject(
142
        $replacementRoot,
143
        DaftNestedWriteableObject $rootObject
144
    ) : ? int {
145
        $tree = $this->ThrowIfNotTree();
146
147
        if (
148
            $tree->CountDaftNestedObjectTreeWithObject($rootObject, false, null) > 0 &&
149
            is_null($replacementRoot)
150
        ) {
151
            throw new BadMethodCallException('Cannot leave orphan objects in a tree');
152
        } elseif (
153
            ! is_null($replacementRoot) &&
154
            $replacementRoot !== $tree->GetNestedObjectTreeRootId()
155
        ) {
156
            $replacementRoot = $tree->RecallDaftObject($replacementRoot);
157
158
            return $this->MaybeRemoveWithPossibleObject($rootObject, $replacementRoot);
159
        }
160
161
        /**
162
        * @var scalar|scalar[] $replacementRoot
163
        */
164
        $replacementRoot = $replacementRoot;
165
166
        $this->UpdateRemoveThenRebuild($rootObject, $replacementRoot);
167
168
        return null;
169
    }
170
}
171