State   A
last analyzed

Complexity

Total Complexity 40

Size/Duplication

Total Lines 190
Duplicated Lines 0 %

Test Coverage

Coverage 88.73%

Importance

Changes 0
Metric Value
eloc 61
c 0
b 0
f 0
dl 0
loc 190
ccs 63
cts 71
cp 0.8873
rs 9.2
wmc 40

19 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 2
A setStatus() 0 3 1
A addToStorage() 0 3 1
A hasChanges() 0 3 2
A getData() 0 3 1
A getTransactionData() 0 3 1
A clearStorage() 0 6 2
A getValue() 0 3 2
A getStatus() 0 3 1
A isReady() 0 3 1
A register() 0 4 1
B updateTransactionData() 0 25 9
A getStorage() 0 3 1
A setData() 0 4 2
A hasValue() 0 6 4
A getChanges() 0 20 6
A getRelationStatus() 0 4 1
A __destruct() 0 3 1
A setRelationStatus() 0 6 1

How to fix   Complexity   

Complex Class

Complex classes like State often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use State, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Cycle\ORM\Heap;
6
7
use Cycle\ORM\Heap\Traits\WaitFieldTrait;
8
use Cycle\ORM\Heap\Traits\RelationTrait;
9
use Cycle\ORM\Relation\RelationInterface;
10
use JetBrains\PhpStorm\ExpectedValues;
11
12
/**
13
 * Current node state.
14
 */
15
final class State
16
{
17
    use RelationTrait;
18
    use WaitFieldTrait;
19
20
    private array $transactionData;
21
22
    /** @var array<string, int> */
23
    private array $relationStatus = [];
24
25
    /** @var array<string, State[]> */
26
    private array $storage = [];
27
28
    /**
29
     * @param array<string, mixed> $data
30
     * @param array<string, mixed> $transactionRaw
31
     */
32 2970
    public function __construct(
33
        #[ExpectedValues(valuesFromClass: Node::class)]
34
        private int $state,
35
        private array $data,
36
        private array $transactionRaw = [],
37
    ) {
38 2970
        $this->transactionData = $state === Node::NEW ? [] : $data;
39
    }
40
41
    /**
42
     * Storage to store temporary cross entity nodes.
43
     *
44
     * @return State[]
45
     *
46
     * @internal
47
     */
48 162
    public function getStorage(string $type): array
49
    {
50 162
        return $this->storage[$type] ?? ($this->storage[$type] = []);
51
    }
52
53 160
    public function addToStorage(string $type, self $node): void
54
    {
55 160
        $this->storage[$type][] = $node;
56
    }
57
58 162
    public function clearStorage(?string $type = null): void
59
    {
60 162
        if ($type === null) {
61
            $this->storage = [];
62
        } else {
63 162
            unset($this->storage[$type]);
64
        }
65
    }
66
67
    /**
68
     * Set new state value.
69
     */
70 2604
    public function setStatus(int $state): void
71
    {
72 2604
        $this->state = $state;
73
    }
74
75
    /**
76
     * Get current state.
77
     */
78 2868
    public function getStatus(): int
79
    {
80 2868
        return $this->state;
81
    }
82
83
    /**
84
     * Set new state data (will trigger state handlers).
85
     */
86 2932
    public function setData(array $data): void
87
    {
88 2932
        foreach ($data as $column => $value) {
89 2932
            $this->register($column, $value);
90
        }
91
    }
92
93
    /**
94
     * Get current state data.
95
     */
96 2918
    public function getData(): array
97
    {
98 2918
        return $this->data;
99
    }
100
101
    /**
102
     * Get current state data.
103
     */
104 2772
    public function getTransactionData(): array
105
    {
106 2772
        return $this->transactionData;
107
    }
108
109 2334
    public function updateTransactionData(?array $fields = null): void
110
    {
111 2334
        if ($fields === null) {
112 2334
            foreach ($this->data as $field => $value) {
113 2334
                $this->transactionData[$field] = $value;
114 2334
                if (isset($this->transactionRaw[$field])) {
115 70
                    $this->transactionRaw[$field] = Node::convertToSolid($this->data[$field]);
116
                }
117
            }
118 2334
            $this->state = Node::MANAGED;
119 2334
            return;
120
        }
121 184
        $changes = false;
122 184
        foreach ($this->data as $field => $value) {
123 184
            if (\in_array($field, $fields, true)) {
124 48
                $this->transactionData[$field] = $this->data[$field];
125 48
                if (\array_key_exists($field, $this->transactionRaw)) {
126
                    $this->transactionRaw[$field] = Node::convertToSolid($this->data[$field]);
127
                }
128 48
                continue;
129
            }
130 184
            $changes = $changes || Node::compare($value, $this->transactionRaw[$field] ?? $this->transactionData[$field] ?? null) !== 0;
131
        }
132 184
        if (!$changes) {
133 88
            $this->state = Node::MANAGED;
134
        }
135
    }
136
137 2716
    public function hasChanges(): bool
138
    {
139 2716
        return $this->state === Node::NEW || $this->getChanges() !== [];
140
    }
141
142 2518
    public function getChanges(): array
143
    {
144 2518
        if ($this->state === Node::NEW) {
145 296
            return $this->data;
146
        }
147 2514
        $result = [];
148 2514
        foreach ($this->data as $field => $value) {
149 2514
            if (!\array_key_exists($field, $this->transactionData)) {
150 238
                $result[$field] = $value;
151 238
                continue;
152
            }
153 2498
            $c = Node::compare(
154
                $value,
155 2498
                \array_key_exists($field, $this->transactionRaw) ? $this->transactionRaw[$field] : $this->transactionData[$field],
156
            );
157 2498
            if ($c !== 0) {
158 884
                $result[$field] = $value;
159
            }
160
        }
161 2514
        return $result;
162
    }
163
164 1432
    public function getValue(string $key): mixed
165
    {
166 1432
        return \array_key_exists($key, $this->data) ? $this->data[$key] : ($this->transactionData[$key] ?? null);
167
    }
168
169
    public function hasValue(string $key, bool $allowNull = true): bool
170
    {
171
        if (!$allowNull) {
172
            return isset($this->data[$key]) || isset($this->transactionData[$key]);
173
        }
174
        return \array_key_exists($key, $this->data) || \array_key_exists($key, $this->transactionData);
175
    }
176
177 2952
    public function register(string $key, mixed $value): void
178
    {
179 2952
        $this->freeWaitingField($key);
180 2952
        $this->data[$key] = $value;
181
    }
182
183
    public function isReady(): bool
184
    {
185
        return $this->waitingFields === [];
186
    }
187
188 2942
    public function setRelationStatus(
189
        string $name,
190 2942
        #[ExpectedValues(valuesFromClass: RelationInterface::class)]
191
        int $status,
192
    ): void {
193 2210
        $this->relationStatus[$name] = $status;
194
    }
195
196
    #[ExpectedValues(valuesFromClass: RelationInterface::class)]
197
    public function getRelationStatus(string $name): int
198 2210
    {
199
        return $this->relationStatus[$name] ?? RelationInterface::STATUS_PREPARE;
200
    }
201 2258
202
    public function __destruct()
203
    {
204 2258
        unset($this->relations, $this->storage, $this->data, $this->transactionData);
205
    }
206
}
207