1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace AlgoWeb\PODataLaravel\Models; |
4
|
|
|
|
5
|
|
|
use Illuminate\Database\Eloquent\Model; |
6
|
|
|
|
7
|
|
|
class MetadataRelationHolder |
8
|
|
|
{ |
9
|
|
|
protected $relations = []; |
10
|
|
|
|
11
|
|
|
public function __construct() |
12
|
|
|
{ |
13
|
|
|
} |
14
|
|
|
|
15
|
|
|
/** |
16
|
|
|
* Add model's relationships to holder |
17
|
|
|
* |
18
|
|
|
* @param Model $model |
19
|
|
|
*/ |
20
|
|
|
public function addModel(Model $model) |
21
|
|
|
{ |
22
|
|
|
if (!in_array('AlgoWeb\\PODataLaravel\\Models\\MetadataTrait', class_uses($model))) { |
23
|
|
|
$msg = 'Supplied model does not use MetadataTrait'; |
24
|
|
|
throw new \InvalidArgumentException($msg); |
25
|
|
|
} |
26
|
|
|
$className = get_class($model); |
27
|
|
|
if (array_key_exists($className, $this->relations)) { |
28
|
|
|
$msg = $className.' already added'; |
29
|
|
|
throw new \InvalidArgumentException($msg); |
30
|
|
|
} |
31
|
|
|
$this->relations[$className] = $model->getRelationships(); |
32
|
|
|
} |
33
|
|
|
|
34
|
|
|
public function getRelationsByKey($className, $keyName) |
35
|
|
|
{ |
36
|
|
|
if (!array_key_exists($className, $this->relations)) { |
37
|
|
|
$msg = $className . ' does not exist in holder'; |
38
|
|
|
throw new \InvalidArgumentException($msg); |
39
|
|
|
} |
40
|
|
|
|
41
|
|
|
$rels = $this->relations[$className]; |
42
|
|
|
if (!array_key_exists($keyName, $rels)) { |
43
|
|
|
$msg = 'Key ' . $keyName . ' not registered on ' . $className; |
44
|
|
|
throw new \InvalidArgumentException($msg); |
45
|
|
|
} |
46
|
|
|
|
47
|
|
|
$result = []; |
48
|
|
|
$payload = $rels[$keyName]; |
49
|
|
|
$principalType = $className; |
50
|
|
|
foreach ($payload as $dependentType => $targDeets) { |
51
|
|
|
if (!array_key_exists($dependentType, $this->relations)) { |
52
|
|
|
continue; |
53
|
|
|
} |
54
|
|
|
// if principal and ostensible dependent type are equal, drop through to specific handler |
55
|
|
|
// at moment, this is only for morphTo relations - morphedByMany doesn't cause this |
56
|
|
|
if ($principalType === $dependentType) { |
57
|
|
|
$morphToLines = $this->getMorphToRelations($principalType, $targDeets, $keyName); |
58
|
|
|
foreach ($morphToLines as $morph) { |
59
|
|
|
if (!in_array($morph, $result)) { |
60
|
|
|
$result[] = $morph; |
61
|
|
|
} |
62
|
|
|
} |
63
|
|
|
continue; |
64
|
|
|
} |
65
|
|
|
|
66
|
|
|
$foreign = $this->relations[$dependentType]; |
67
|
|
|
|
68
|
|
|
foreach ($targDeets as $principalProperty => $rawDeets) { |
69
|
|
|
$targKey = $rawDeets['local']; |
70
|
|
|
$principalMult = $rawDeets['multiplicity']; |
71
|
|
|
$principalProperty = $rawDeets['property']; |
72
|
|
|
if (!array_key_exists($targKey, $foreign)) { |
73
|
|
|
continue; |
74
|
|
|
} |
75
|
|
|
$foreignDeets = $foreign[$targKey]; |
76
|
|
|
foreach ($foreignDeets as $foreignType => $raw) { |
77
|
|
|
if (!array_key_exists($foreignType, $this->relations)) { |
78
|
|
|
continue; |
79
|
|
|
} |
80
|
|
View Code Duplication |
foreach ($raw as $dependentProperty => $dependentPayload) { |
|
|
|
|
81
|
|
|
if ($keyName == $dependentPayload['local']) { |
82
|
|
|
$dependentMult = $dependentPayload['multiplicity']; |
83
|
|
|
// generate forward and reverse relations |
84
|
|
|
list($forward, $reverse) = $this->calculateRoundTripRelationsGenForwardReverse( |
85
|
|
|
$principalType, |
86
|
|
|
$principalMult, |
87
|
|
|
$principalProperty, |
88
|
|
|
$dependentType, |
89
|
|
|
$dependentMult, |
90
|
|
|
$dependentProperty |
91
|
|
|
); |
92
|
|
|
if (!in_array($forward, $result)) { |
93
|
|
|
// add forward relation |
94
|
|
|
$result[] = $forward; |
95
|
|
|
} |
96
|
|
|
if (!in_array($reverse, $result)) { |
97
|
|
|
// add reverse relation |
98
|
|
|
$result[] = $reverse; |
99
|
|
|
} |
100
|
|
|
} |
101
|
|
|
} |
102
|
|
|
} |
103
|
|
|
} |
104
|
|
|
} |
105
|
|
|
return $result; |
106
|
|
|
} |
107
|
|
|
|
108
|
|
|
private function getMorphToRelations($principalType, $targDeets, $keyName) |
109
|
|
|
{ |
110
|
|
|
$result = []; |
111
|
|
|
$deetKeys = array_keys($targDeets); |
112
|
|
|
$principalProperty = $deetKeys[0]; |
113
|
|
|
$principalDeets = $targDeets[$principalProperty]; |
114
|
|
|
$principalMult = $principalDeets['multiplicity']; |
115
|
|
|
|
116
|
|
|
foreach ($this->relations as $dependentType => $dependentDeets) { |
117
|
|
|
foreach ($dependentDeets as $targKey => $rawDeets) { |
118
|
|
|
foreach ($rawDeets as $targType => $interDeets) { |
119
|
|
|
if ($targType != $principalType) { |
120
|
|
|
continue; |
121
|
|
|
} |
122
|
|
View Code Duplication |
foreach ($interDeets as $dependentProperty => $finalDeets) { |
|
|
|
|
123
|
|
|
if ($keyName !== $finalDeets['local']) { |
124
|
|
|
continue; |
125
|
|
|
} |
126
|
|
|
$dependentMult = $finalDeets['multiplicity']; |
127
|
|
|
list($forward, $reverse) = $this->calculateRoundTripRelationsGenForwardReverse( |
128
|
|
|
$principalType, |
129
|
|
|
$principalMult, |
130
|
|
|
$principalProperty, |
131
|
|
|
$dependentType, |
132
|
|
|
$dependentMult, |
133
|
|
|
$dependentProperty |
134
|
|
|
); |
135
|
|
|
if (!in_array($forward, $result)) { |
136
|
|
|
// add forward relation |
137
|
|
|
$result[] = $forward; |
138
|
|
|
} |
139
|
|
|
if (!in_array($reverse, $result)) { |
140
|
|
|
// add reverse relation |
141
|
|
|
$result[] = $reverse; |
142
|
|
|
} |
143
|
|
|
} |
144
|
|
|
} |
145
|
|
|
} |
146
|
|
|
} |
147
|
|
|
return $result; |
148
|
|
|
} |
149
|
|
|
|
150
|
|
|
/** |
151
|
|
|
* @param $principalType |
152
|
|
|
* @param $principalMult |
153
|
|
|
* @param $principalProperty |
154
|
|
|
* @param $dependentType |
155
|
|
|
* @param $dependentMult |
156
|
|
|
* @param $dependentProperty |
157
|
|
|
* @return array[] |
158
|
|
|
*/ |
159
|
|
View Code Duplication |
private function calculateRoundTripRelationsGenForwardReverse( |
|
|
|
|
160
|
|
|
$principalType, |
161
|
|
|
$principalMult, |
162
|
|
|
$principalProperty, |
163
|
|
|
$dependentType, |
164
|
|
|
$dependentMult, |
165
|
|
|
$dependentProperty |
166
|
|
|
) { |
167
|
|
|
$forward = [ |
168
|
|
|
'principalType' => $principalType, |
169
|
|
|
'principalMult' => $dependentMult, |
170
|
|
|
'principalProp' => $principalProperty, |
171
|
|
|
'dependentType' => $dependentType, |
172
|
|
|
'dependentMult' => $principalMult, |
173
|
|
|
'dependentProp' => $dependentProperty |
174
|
|
|
]; |
175
|
|
|
$reverse = [ |
176
|
|
|
'principalType' => $dependentType, |
177
|
|
|
'principalMult' => $principalMult, |
178
|
|
|
'principalProp' => $dependentProperty, |
179
|
|
|
'dependentType' => $principalType, |
180
|
|
|
'dependentMult' => $dependentMult, |
181
|
|
|
'dependentProp' => $principalProperty |
182
|
|
|
]; |
183
|
|
|
return [$forward, $reverse]; |
184
|
|
|
} |
185
|
|
|
} |
186
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.