Passed
Push — master ( 6ea451...1ef48a )
by Anton
01:35
created

AbstractRelation::resolve()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 1
dl 0
loc 8
rs 10
c 0
b 0
f 0
1
<?php
2
declare(strict_types=1);
3
/**
4
 * Spiral Framework.
5
 *
6
 * @license   MIT
7
 * @author    Anton Titov (Wolfy-J)
8
 */
9
10
namespace Cycle\ORM\Relation;
11
12
use Cycle\ORM\Exception\RelationException;
13
use Cycle\ORM\Heap\Node;
14
use Cycle\ORM\MapperInterface;
15
use Cycle\ORM\ORMInterface;
16
use Cycle\ORM\Promise\PromiseInterface;
17
use Cycle\ORM\Promise\ReferenceInterface;
18
use Cycle\ORM\Relation;
19
use Cycle\ORM\Schema;
20
use Cycle\ORM\Select\ConstrainInterface;
21
use Cycle\ORM\Select\SourceInterface;
22
use Cycle\ORM\Select\SourceProviderInterface;
23
24
abstract class AbstractRelation implements RelationInterface
25
{
26
    use Traits\ContextTrait;
27
28
    /** @var ORMInterface|SourceProviderInterface @internal */
29
    protected $orm;
30
31
    /** @var string */
32
    protected $name;
33
34
    /** @var string */
35
    protected $target;
36
37
    /** @var array */
38
    protected $schema;
39
40
    /** @var string */
41
    protected $innerKey;
42
43
    /** @var string */
44
    protected $outerKey;
45
46
    /**
47
     * @param ORMInterface $orm
48
     * @param string       $name
49
     * @param string       $target
50
     * @param array        $schema
51
     */
52
    public function __construct(ORMInterface $orm, string $name, string $target, array $schema)
53
    {
54
        $this->orm = $orm;
55
        $this->name = $name;
56
        $this->target = $target;
57
        $this->schema = $schema;
58
        $this->innerKey = $schema[Relation::INNER_KEY];
59
        $this->outerKey = $schema[Relation::OUTER_KEY];
60
    }
61
62
    /**
63
     * @inheritdoc
64
     */
65
    public function getName(): string
66
    {
67
        return $this->name;
68
    }
69
70
    /**
71
     * @inheritdoc
72
     */
73
    public function isCascade(): bool
74
    {
75
        return $this->schema[Relation::CASCADE] ?? false;
76
    }
77
78
    /**
79
     * @inheritdoc
80
     */
81
    public function init(array $data): array
82
    {
83
        $item = $this->orm->make($this->target, $data, Node::MANAGED);
0 ignored issues
show
Bug introduced by
The method make() does not exist on Cycle\ORM\Select\SourceProviderInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Cycle\ORM\Select\SourceProviderInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

83
        /** @scrutinizer ignore-call */ 
84
        $item = $this->orm->make($this->target, $data, Node::MANAGED);
Loading history...
84
85
        return [$item, $item];
86
    }
87
88
    /**
89
     * @inheritdoc
90
     */
91
    public function extract($data)
92
    {
93
        return $data;
94
    }
95
96
    /**
97
     * @return string
98
     */
99
    public function __toString()
100
    {
101
        // this is incorrect class
102
        return sprintf("%s(%s)->%s", $this->name, get_class($this), $this->target);
103
    }
104
105
    /**
106
     * Indicates that relation can not be nullable.
107
     *
108
     * @return bool
109
     */
110
    protected function isRequired(): bool
111
    {
112
        if (array_key_exists(Relation::NULLABLE, $this->schema)) {
113
            return !$this->schema[Relation::NULLABLE];
114
        }
115
116
        return true;
117
    }
118
119
    /**
120
     * Get the scope name associated with the relation.
121
     *
122
     * @return null|ConstrainInterface
123
     */
124
    protected function getConstrain(): ?ConstrainInterface
125
    {
126
        $constrain = $this->schema[Relation::CONSTRAIN] ?? true;
127
        if ($constrain instanceof ConstrainInterface) {
128
            return $constrain;
129
        }
130
131
        if ($constrain == null) {
132
            return null;
133
        }
134
135
        return $this->getSource()->getConstrain();
136
    }
137
138
    /**
139
     * Get Node for the given entity. Null if entity does not exists. Automatically
140
     * register entity claims.
141
     *
142
     * @param object $entity
143
     * @param int    $claim
144
     * @return Node|null
145
     */
146
    protected function getNode($entity, int $claim = 0): ?Node
147
    {
148
        if (is_null($entity)) {
149
            return null;
150
        }
151
152
        if ($entity instanceof ReferenceInterface) {
153
            return new Node(Node::PROMISED, $entity->__scope(), $entity->__role());
154
        }
155
156
        $node = $this->orm->getHeap()->get($entity);
0 ignored issues
show
Bug introduced by
The method getHeap() does not exist on Cycle\ORM\Select\SourceProviderInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Cycle\ORM\Select\SourceProviderInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

156
        $node = $this->orm->/** @scrutinizer ignore-call */ getHeap()->get($entity);
Loading history...
157
158
        if (is_null($node)) {
159
            $node = new Node(Node::NEW, [], $this->orm->getMapper($entity)->getRole());
0 ignored issues
show
Bug introduced by
The method getMapper() does not exist on Cycle\ORM\Select\SourceProviderInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Cycle\ORM\Select\SourceProviderInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

159
            $node = new Node(Node::NEW, [], $this->orm->/** @scrutinizer ignore-call */ getMapper($entity)->getRole());
Loading history...
160
            $this->orm->getHeap()->attach($entity, $node);
161
        }
162
163
        if ($claim === 1) {
164
            $node->getState()->addClaim();
165
        }
166
167
        if ($claim === -1) {
168
            $node->getState()->decClaim();
169
        }
170
171
        return $node;
172
    }
173
174
    /**
175
     * Get the source associated with the role.
176
     *
177
     * @param string|null $role
178
     * @return SourceInterface
179
     */
180
    protected function getSource(string $role = null): SourceInterface
181
    {
182
        return $this->orm->getSource($role ?? $this->target);
183
    }
184
185
    /**
186
     * Get the mapper associated with a role.
187
     *
188
     * @param string|null $role
189
     * @return MapperInterface
190
     */
191
    protected function getMapper(string $role = null): MapperInterface
192
    {
193
        return $this->orm->getMapper($role ?? $this->target);
194
    }
195
196
    /**
197
     * @param Node   $node
198
     * @param string $field
199
     * @return string
200
     */
201
    protected function columnName(Node $node, string $field): string
202
    {
203
        return $this->orm->getSchema()->define($node->getRole(), Schema::COLUMNS)[$field] ?? $field;
0 ignored issues
show
Bug introduced by
The method getSchema() does not exist on Cycle\ORM\Select\SourceProviderInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Cycle\ORM\Select\SourceProviderInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

203
        return $this->orm->/** @scrutinizer ignore-call */ getSchema()->define($node->getRole(), Schema::COLUMNS)[$field] ?? $field;
Loading history...
204
    }
205
206
    /**
207
     * Assert that given entity is allowed for the relation.
208
     *
209
     * @param Node $relNode
210
     *
211
     * @throws RelationException
212
     */
213
    protected function assertValid(Node $relNode)
214
    {
215
        if ($relNode->getRole() != $this->target) {
216
            throw new RelationException(sprintf("Unable to link %s, given `%s`", $this, $relNode->getRole()));
217
        }
218
    }
219
220
    /**
221
     * Resolve the reference to the object.
222
     *
223
     * @param ReferenceInterface $reference
224
     * @return mixed|null
225
     */
226
    protected function resolve(ReferenceInterface $reference)
227
    {
228
        if ($reference instanceof PromiseInterface) {
229
            return $reference->__resolve();
230
        }
231
232
        $scope = $reference->__scope();
233
        return $this->orm->get($reference->__role(), key($scope), current($scope), true);
0 ignored issues
show
Bug introduced by
The method get() does not exist on Cycle\ORM\Select\SourceProviderInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Cycle\ORM\Select\SourceProviderInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

233
        return $this->orm->/** @scrutinizer ignore-call */ get($reference->__role(), key($scope), current($scope), true);
Loading history...
234
    }
235
}