Passed
Push — master ( 61bbc0...3efc91 )
by Anton
02:31
created

RelationMap::queueRelations()   B

Complexity

Conditions 10
Paths 32

Size

Total Lines 55
Code Lines 32

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 10
eloc 32
c 2
b 0
f 0
nc 32
nop 4
dl 0
loc 55
rs 7.6666

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
/**
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;
13
14
use Cycle\ORM\Command\Branch\ContextSequence;
15
use Cycle\ORM\Command\CommandInterface;
16
use Cycle\ORM\Command\ContextCarrierInterface as CC;
17
use Cycle\ORM\Heap\Node;
18
use Cycle\ORM\Promise\PromiseInterface;
19
use Cycle\ORM\Promise\ReferenceInterface;
20
use Cycle\ORM\Relation\DependencyInterface;
21
use Cycle\ORM\Relation\RelationInterface;
22
23
/**
24
 * Manages the position of node in the relation graph and provide access to neighbours.
25
 */
26
final class RelationMap
27
{
28
    /** @var ORMInterface @internal */
29
    private $orm;
30
31
    /** @var RelationInterface[] */
32
    private $relations = [];
33
34
    /** @var DependencyInterface[] */
35
    private $dependencies = [];
36
37
    /**
38
     * @param ORMInterface $orm
39
     * @param array        $relations
40
     */
41
    public function __construct(ORMInterface $orm, array $relations)
42
    {
43
        $this->orm = $orm;
44
        $this->relations = $relations;
45
46
        foreach ($this->relations as $name => $relation) {
47
            if ($relation instanceof DependencyInterface) {
48
                $this->dependencies[$name] = $relation;
49
            }
50
        }
51
    }
52
53
    /**
54
     * Init relation data in entity data and entity state.
55
     *
56
     * @param Node  $node
57
     * @param array $data
58
     * @return array
59
     */
60
    public function init(Node $node, array $data): array
61
    {
62
        foreach ($this->relations as $name => $relation) {
63
            if (!array_key_exists($name, $data)) {
64
                if ($node->hasRelation($name)) {
65
                    continue;
66
                }
67
68
                [$data[$name], $orig] = $relation->initPromise($node);
69
                $node->setRelation($name, $orig);
70
                continue;
71
            }
72
73
            $item = $data[$name];
74
            if (is_object($item) || $item === null) {
75
                // cyclic initialization
76
                $node->setRelation($name, $item);
77
                continue;
78
            }
79
80
            // init relation for the entity and for state and the same time
81
            [$data[$name], $orig] = $relation->init($node, $item);
82
            $node->setRelation($name, $orig);
83
        }
84
85
        return $data;
86
    }
87
88
    /**
89
     * Queue entity relations.
90
     *
91
     * @param CC     $parentStore
92
     * @param object $parentEntity
93
     * @param Node   $parentNode
94
     * @param array  $parentData
95
     * @return CC
96
     */
97
    public function queueRelations(CC $parentStore, $parentEntity, Node $parentNode, array $parentData): CC
98
    {
99
        $state = $parentNode->getState();
100
        $sequence = new ContextSequence();
101
102
        // queue all "left" graph branches
103
        foreach ($this->dependencies as $name => $relation) {
104
            if (!$relation->isCascade() || $parentNode->getState()->visited($name)) {
105
                continue;
106
            }
107
            $state->markVisited($name);
108
109
            $command = $this->queueRelation(
110
                $parentStore,
111
                $parentEntity,
112
                $parentNode,
113
                $relation,
114
                $relation->extract($parentData[$name] ?? null),
115
                $parentNode->getRelation($name)
116
            );
117
118
            if ($command !== null) {
119
                $sequence->addCommand($command);
120
            }
121
        }
122
123
        // queue target entity
124
        $sequence->addPrimary($parentStore);
125
126
        // queue all "right" graph branches
127
        foreach ($this->relations as $name => $relation) {
128
            if (!$relation->isCascade() || $parentNode->getState()->visited($name)) {
129
                continue;
130
            }
131
            $state->markVisited($name);
132
133
            $command = $this->queueRelation(
134
                $parentStore,
135
                $parentEntity,
136
                $parentNode,
137
                $relation,
138
                $relation->extract($parentData[$name] ?? null),
139
                $parentNode->getRelation($name)
140
            );
141
142
            if ($command !== null) {
143
                $sequence->addCommand($command);
144
            }
145
        }
146
147
        if (\count($sequence) === 1) {
148
            return current($sequence->getCommands());
149
        }
150
151
        return $sequence;
152
    }
153
154
    /**
155
     * Queue the relation.
156
     *
157
     * @param CC                $parentStore
158
     * @param object            $parentEntity
159
     * @param Node              $parentNode
160
     * @param RelationInterface $relation
161
     * @param mixed             $related
162
     * @param mixed             $original
163
     * @return CommandInterface|null
164
     */
165
    private function queueRelation(
166
        CC $parentStore,
167
        $parentEntity,
168
        Node $parentNode,
169
        RelationInterface $relation,
170
        $related,
171
        $original
172
    ): ?CommandInterface {
173
        if (
174
            ($related instanceof ReferenceInterface || $related === null)
175
            && !($related instanceof PromiseInterface && $related->__loaded())
176
            && $related === $original
177
        ) {
178
            // no changes in non changed promised relation
179
            return null;
180
        }
181
182
        $relStore = $relation->queue(
183
            $parentStore,
184
            $parentEntity,
185
            $parentNode,
186
            $related,
187
            $original
188
        );
189
190
        // update current relation state
191
        $parentNode->getState()->setRelation($relation->getName(), $related);
192
193
        return $relStore;
194
    }
195
196
    /**
197
     * Check if both references are equal.
198
     *
199
     * @param mixed $a
200
     * @param mixed $b
201
     * @return bool
202
     */
203
    private function sameReference($a, $b): bool
0 ignored issues
show
Unused Code introduced by
The method sameReference() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
204
    {
205
        if (!$a instanceof ReferenceInterface || !$b instanceof ReferenceInterface) {
206
            return false;
207
        }
208
209
        return $a->__role() === $b->__role() && $a->__scope() === $b->__scope();
210
    }
211
}
212