Passed
Pull Request — master (#180)
by Aleksei
02:27
created

Node::hasState()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * Cycle DataMapper ORM
5
 *
6
 * @license   MIT
7
 * @author    Anton Titov (Wolfy-J)
8
 */
9
10
declare(strict_types=1);
11
12
namespace Cycle\ORM\Heap;
13
14
use Cycle\ORM\Context\ConsumerInterface;
15
use Cycle\ORM\Context\ProducerInterface;
16
use Cycle\ORM\Heap\Traits\RelationTrait;
17
18
/**
19
 * Node (metadata) carries meta information about entity state, changes forwards data to other points through
20
 * inner states.
21
 */
22
final class Node implements ProducerInterface, ConsumerInterface
23
{
24
    use RelationTrait;
25
26
    // Different entity states in a pool
27
    public const PROMISED         = 0;
28
    public const NEW              = 1;
29
    public const MANAGED          = 2;
30
    public const SCHEDULED_INSERT = 3;
31
    public const SCHEDULED_UPDATE = 4;
32
    public const SCHEDULED_DELETE = 5;
33
    public const DELETED          = 6;
34
35
    /** @var string */
36
    private $role;
37
38
    /** @var int */
39
    private $status;
40
41
    /** @var array */
42
    private $data;
43
44
    /** @var null|State */
45
    private $state;
46
47
    /**
48
     * @param int    $status
49
     * @param array  $data
50
     * @param string $role
51
     */
52
    public function __construct(int $status, array $data, string $role)
53
    {
54
        $this->status = $status;
55
        $this->data = $data;
56
        $this->role = $role;
57
    }
58
59
    /**
60
     * Reset state.
61
     */
62
    public function __destruct()
63
    {
64
        $this->data = [];
65
        $this->state = null;
66
        $this->relations = [];
67
    }
68
69
    /**
70
     * @return string
71
     */
72
    public function getRole(): string
73
    {
74
        return $this->role;
75
    }
76
77
    /**
78
     * Current point state (set of changes).
79
     *
80
     * @return State
81
     */
82
    public function getState(): State
83
    {
84
        if ($this->state === null) {
85
            $this->state = new State($this->status, $this->data);
86
        }
87
88
        return $this->state;
89
    }
90
91
    public function hasState(): bool
92
    {
93
        return $this->state !== null;
94
    }
95
96
    /**
97
     * Set new state value.
98
     *
99
     * @param int $state
100
     */
101
    public function setStatus(int $state): void
102
    {
103
        $this->getState()->setStatus($state);
104
    }
105
106
    /**
107
     * Get current state.
108
     *
109
     * @return int
110
     */
111
    public function getStatus(): int
112
    {
113
        if ($this->state !== null) {
114
            return $this->state->getStatus();
115
        }
116
117
        return $this->status;
118
    }
119
120
    /**
121
     * Set new state data (will trigger state handlers).
122
     *
123
     * @param array $data
124
     */
125
    public function setData(array $data): void
126
    {
127
        $this->getState()->setData($data);
128
    }
129
130
    /**
131
     * Get current state data. Mutalbe inside the transaction.
132
     *
133
     * @return array
134
     */
135
    public function getData(): array
136
    {
137
        if ($this->state !== null) {
138
            return $this->state->getData();
139
        }
140
141
        return $this->data;
142
    }
143
144
    /**
145
     * The intial (post-load) node date. Does not change during the transaction.
146
     *
147
     * @return array
148
     */
149
    public function getInitialData(): array
150
    {
151
        return $this->data;
152
    }
153
154
    /**
155
     * @inheritdoc
156
     */
157
    public function forward(
158
        string $key,
159
        ConsumerInterface $consumer,
160
        string $target,
161
        bool $trigger = false,
162
        int $stream = self::DATA
163
    ): void {
164
        $this->getState()->forward($key, $consumer, $target, $trigger, $stream);
165
    }
166
167
    /**
168
     * @inheritdoc
169
     */
170
    public function register(string $key, $value, bool $fresh = false, int $stream = self::DATA): void
171
    {
172
        $this->getState()->register($key, $value, $fresh, $stream);
173
    }
174
175
    /**
176
     * Sync the point state and return data diff.
177
     *
178
     * @return array
179
     */
180
    public function syncState(): array
181
    {
182
        if ($this->state === null) {
183
            return [];
184
        }
185
186
        $changes = array_udiff_assoc($this->state->getData(), $this->data, [static::class, 'compare']);
187
        foreach ($this->state->getRelations() as $name => $relation) {
188
            $this->setRelation($name, $relation);
189
        }
190
191
        // DELETE handled separately
192
        $this->status = self::MANAGED;
193
        $this->data = $this->state->getData();
194
        $this->state = null;
195
196
        return $changes;
197
    }
198
199
    /**
200
     * Reset point state and flush all the changes.
201
     */
202
    public function resetState(): void
203
    {
204
        $this->state = null;
205
    }
206
207
    /**
208
     * @param mixed $a
209
     * @param mixed $b
210
     * @return int
211
     */
212
    public static function compare($a, $b): int
213
    {
214
        if ($a == $b) {
215
            if (($a === null) !== ($b === null)) {
216
                return 1;
217
            }
218
219
            return 0;
220
        }
221
222
        return ($a > $b) ? 1 : -1;
223
    }
224
}
225