1 | <?php |
||||||
2 | |||||||
3 | declare(strict_types=1); |
||||||
4 | |||||||
5 | namespace Cycle\ORM; |
||||||
6 | |||||||
7 | use Cycle\ORM\Heap\Node; |
||||||
8 | use Cycle\ORM\Relation\ActiveRelationInterface; |
||||||
9 | use Cycle\ORM\Relation\DependencyInterface; |
||||||
10 | use Cycle\ORM\Relation\RelationInterface; |
||||||
11 | use Cycle\ORM\Relation\SameRowRelationInterface; |
||||||
12 | use Cycle\ORM\Relation\ShadowBelongsTo; |
||||||
13 | use Cycle\ORM\Relation\ShadowHasMany; |
||||||
14 | use Cycle\ORM\Service\EntityFactoryInterface; |
||||||
15 | |||||||
16 | /** |
||||||
17 | * Manages the position of node in the relation graph and provide access to neighbours. |
||||||
18 | * |
||||||
19 | * @internal |
||||||
20 | */ |
||||||
21 | final class RelationMap |
||||||
22 | { |
||||||
23 | /** @var ActiveRelationInterface[] */ |
||||||
24 | private array $innerRelations; |
||||||
25 | |||||||
26 | /** @var DependencyInterface[] */ |
||||||
27 | private array $dependencies = []; |
||||||
28 | |||||||
29 | /** @var RelationInterface[] */ |
||||||
30 | private array $slaves = []; |
||||||
31 | |||||||
32 | /** @var SameRowRelationInterface[] */ |
||||||
33 | 6878 | private array $embedded = []; |
|||||
34 | |||||||
35 | 6878 | private function __construct(array $innerRelations, array $outerRelations) |
|||||
0 ignored issues
–
show
|
|||||||
36 | { |
||||||
37 | 6878 | $this->innerRelations = $innerRelations; |
|||||
38 | 5364 | ||||||
39 | 1760 | foreach ($innerRelations as $name => $relation) { |
|||||
40 | 4650 | if ($relation instanceof DependencyInterface) { |
|||||
41 | 344 | $this->dependencies[$name] = $relation; |
|||||
42 | } elseif ($relation instanceof SameRowRelationInterface) { |
||||||
43 | 4386 | $this->embedded[$name] = $relation; |
|||||
44 | } else { |
||||||
45 | $this->slaves[$name] = $relation; |
||||||
46 | } |
||||||
47 | } |
||||||
48 | 6878 | } |
|||||
49 | |||||||
50 | 6878 | public static function build(OrmInterface $orm, string $role): self |
|||||
51 | 6878 | { |
|||||
52 | $factory = $orm->getFactory(); |
||||||
53 | 6878 | $schema = $orm->getSchema(); |
|||||
54 | 6878 | ||||||
55 | $outerRelations = $schema->getOuterRelations($role); |
||||||
0 ignored issues
–
show
The method
getOuterRelations() does not exist on Cycle\ORM\SchemaInterface . Since it exists in all sub-types, consider adding an abstract or default implementation to Cycle\ORM\SchemaInterface .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
56 | $innerRelations = $schema->getInnerRelations($role); |
||||||
0 ignored issues
–
show
The method
getInnerRelations() does not exist on Cycle\ORM\SchemaInterface . Since it exists in all sub-types, consider adding an abstract or default implementation to Cycle\ORM\SchemaInterface .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
57 | 6878 | ||||||
58 | 6878 | // Build relations |
|||||
59 | 5196 | $relations = []; |
|||||
60 | foreach ($innerRelations as $relName => $relSchema) { |
||||||
61 | $relations[$relName] = $factory->relation($orm, $schema, $role, $relName); |
||||||
62 | } |
||||||
63 | 6878 | ||||||
64 | 6878 | // add Parent's relations |
|||||
65 | 800 | $parent = $schema->define($role, SchemaInterface::PARENT); |
|||||
66 | 424 | while ($parent !== null) { |
|||||
67 | foreach ($schema->getInnerRelations($parent) as $relName => $relSchema) { |
||||||
68 | if (isset($relations[$relName])) { |
||||||
69 | 424 | continue; |
|||||
70 | } |
||||||
71 | $relations[$relName] = $factory->relation($orm, $schema, $parent, $relName); |
||||||
72 | 800 | } |
|||||
73 | 800 | ||||||
74 | $outerRelations += $schema->getOuterRelations($parent); |
||||||
75 | $parent = $schema->define($parent, SchemaInterface::PARENT); |
||||||
76 | 6878 | } |
|||||
77 | |||||||
78 | 6878 | $result = new self($relations, $outerRelations); |
|||||
79 | 4536 | ||||||
80 | 4536 | foreach ($outerRelations as $outerRole => $relations) { |
|||||
81 | foreach ($relations as $container => $relationSchema) { |
||||||
82 | $result->registerOuterRelation($outerRole, $container, $relationSchema); |
||||||
83 | 6878 | } |
|||||
84 | } |
||||||
85 | return $result; |
||||||
86 | 4536 | } |
|||||
87 | |||||||
88 | public function hasDependencies(): bool |
||||||
89 | 4536 | { |
|||||
90 | return $this->dependencies !== []; |
||||||
91 | 4536 | } |
|||||
92 | 1494 | ||||||
93 | public function hasSlaves(): bool |
||||||
94 | 3656 | { |
|||||
95 | 886 | return $this->slaves !== []; |
|||||
96 | } |
||||||
97 | 886 | ||||||
98 | 656 | public function hasEmbedded(): bool |
|||||
99 | 656 | { |
|||||
100 | 656 | return $this->embedded !== []; |
|||||
101 | 656 | } |
|||||
102 | 656 | ||||||
103 | /** |
||||||
104 | 656 | * Init relation data in entity data and entity state. |
|||||
105 | */ |
||||||
106 | 886 | public function init(EntityFactoryInterface $factory, Node $node, array $data): array |
|||||
107 | { |
||||||
108 | 3648 | foreach ($this->innerRelations as $name => $relation) { |
|||||
109 | if (!\array_key_exists($name, $data)) { |
||||||
110 | 530 | if ($node->hasRelation($name)) { |
|||||
111 | 530 | continue; |
|||||
112 | 530 | } |
|||||
113 | |||||||
114 | $data[$name] = $relation->initReference($node); |
||||||
115 | 3264 | $node->setRelation($name, $data[$name]); |
|||||
116 | 3264 | continue; |
|||||
117 | } |
||||||
118 | |||||||
119 | 2900 | $item = $data[$name]; |
|||||
120 | if (\is_object($item) || $item === null) { |
||||||
121 | 2900 | // cyclic initialization |
|||||
122 | $node->setRelation($name, $item); |
||||||
123 | continue; |
||||||
124 | 2860 | } |
|||||
125 | |||||||
126 | 2860 | // init relation for the entity and for state and the same time |
|||||
127 | $data[$name] = $relation->init($factory, $node, $item); |
||||||
128 | } |
||||||
129 | 2764 | ||||||
130 | return $data; |
||||||
131 | 2764 | } |
|||||
132 | |||||||
133 | /** |
||||||
134 | * @return RelationInterface[] |
||||||
135 | */ |
||||||
136 | public function getSlaves(): array |
||||||
137 | 4986 | { |
|||||
138 | return $this->slaves; |
||||||
139 | 4986 | } |
|||||
140 | 3990 | ||||||
141 | 2446 | /** |
|||||
142 | 122 | * @return array<string, DependencyInterface> |
|||||
143 | */ |
||||||
144 | public function getMasters(): array |
||||||
145 | 2438 | { |
|||||
146 | 2438 | return $this->dependencies; |
|||||
147 | 2438 | } |
|||||
148 | |||||||
149 | /** |
||||||
150 | 2426 | * @return SameRowRelationInterface[] |
|||||
151 | 2426 | */ |
|||||
152 | public function getEmbedded(): array |
||||||
153 | 280 | { |
|||||
154 | 280 | return $this->embedded; |
|||||
155 | } |
||||||
156 | |||||||
157 | /** |
||||||
158 | 2394 | * @return ActiveRelationInterface[] |
|||||
159 | */ |
||||||
160 | public function getRelations(): array |
||||||
161 | 4986 | { |
|||||
162 | return $this->innerRelations; |
||||||
163 | } |
||||||
164 | |||||||
165 | private function registerOuterRelation(string $role, string $container, array $relationSchema): void |
||||||
166 | { |
||||||
167 | 1718 | // todo: it better to check instanceOf \Cycle\ORM\Relation\DependencyInterface instead of int |
|||||
168 | $relationType = $relationSchema[Relation::TYPE]; |
||||||
169 | 1718 | // skip dependencies |
|||||
170 | if ($relationType === Relation::BELONGS_TO || $relationType === Relation::REFERS_TO) { |
||||||
171 | return; |
||||||
172 | } |
||||||
173 | if ($relationType === Relation::MANY_TO_MANY) { |
||||||
174 | $handshaked = \is_string($relationSchema[Relation::SCHEMA][Relation::INVERSION] ?? null); |
||||||
175 | 2080 | // Create ShadowHasMany |
|||||
176 | if (!$handshaked) { |
||||||
177 | 2080 | $relation = new ShadowHasMany( |
|||||
178 | $role . '.' . $container . ':' . $relationSchema[Relation::TARGET], |
||||||
179 | $relationSchema[Relation::SCHEMA][Relation::THROUGH_ENTITY], |
||||||
180 | (array) $relationSchema[Relation::SCHEMA][Relation::OUTER_KEY], |
||||||
181 | (array) $relationSchema[Relation::SCHEMA][Relation::THROUGH_OUTER_KEY], |
||||||
182 | ); |
||||||
183 | 168 | $this->slaves[$relation->getName()] = $relation; |
|||||
184 | } |
||||||
185 | 168 | return; |
|||||
186 | } |
||||||
187 | if ($relationType === Relation::MORPHED_HAS_ONE || $relationType === Relation::MORPHED_HAS_MANY) { |
||||||
188 | // todo: find morphed collisions, decide handshake |
||||||
189 | $relation = new ShadowBelongsTo('~morphed~' . $container, $role, $relationSchema); |
||||||
190 | $this->dependencies[$relation->getName()] ??= $relation; |
||||||
191 | 6820 | return; |
|||||
192 | } |
||||||
193 | 6820 | ||||||
194 | $relation = new ShadowBelongsTo($container, $role, $relationSchema); |
||||||
195 | $this->dependencies[$relation->getName()] = $relation; |
||||||
196 | } |
||||||
197 | } |
||||||
198 |
This check looks for parameters that have been defined for a function or method, but which are not used in the method body.