1 | <?php |
||||
2 | |||||
3 | namespace SoliDry\Extension; |
||||
4 | |||||
5 | use Illuminate\Http\Request; |
||||
6 | use Illuminate\Http\Response; |
||||
7 | use SoliDry\Blocks\FileManager; |
||||
8 | use SoliDry\Helpers\Classes; |
||||
9 | use SoliDry\Helpers\ConfigHelper; |
||||
10 | use SoliDry\Helpers\Json; |
||||
11 | use SoliDry\Helpers\MigrationsHelper; |
||||
12 | use SoliDry\Types\DirsInterface; |
||||
13 | use SoliDry\Types\ModelsInterface; |
||||
14 | use SoliDry\Types\PhpInterface; |
||||
15 | use SoliDry\Types\ApiInterface; |
||||
16 | use SoliDry\Helpers\ConfigHelper as conf; |
||||
17 | |||||
18 | /** |
||||
19 | * Trait BaseRelationsTrait |
||||
20 | * |
||||
21 | * @package SoliDry\Extension |
||||
22 | * |
||||
23 | * @property Json json |
||||
24 | * @property \SoliDry\Containers\Response response |
||||
25 | */ |
||||
26 | trait BaseRelationsTrait |
||||
27 | { |
||||
28 | use BaseModelTrait; |
||||
29 | |||||
30 | /** |
||||
31 | * GET the relationships of this particular Entity |
||||
32 | * |
||||
33 | * @param Request $request |
||||
34 | * @param int|string $id |
||||
35 | * @param string $relation |
||||
36 | * @return Response |
||||
37 | */ |
||||
38 | public function relations(Request $request, $id, string $relation): Response |
||||
39 | { |
||||
40 | $model = $this->getEntity($id); |
||||
41 | if (empty($model)) { |
||||
42 | return $this->response->getModelNotFoundError($this->entity, $id); |
||||
43 | } |
||||
44 | |||||
45 | return $this->response->getRelations($model->$relation, $relation, $request); |
||||
46 | } |
||||
47 | |||||
48 | /** |
||||
49 | * GET the fully represented relationships of this particular Entity |
||||
50 | * |
||||
51 | * @param Request $request |
||||
52 | * @param int|string $id |
||||
53 | * @param string $relation |
||||
54 | * @return Response |
||||
55 | */ |
||||
56 | public function related(Request $request, $id, string $relation): Response |
||||
57 | { |
||||
58 | $data = ($request->input(ModelsInterface::PARAM_DATA) === NULL) ? ModelsInterface::DEFAULT_DATA |
||||
59 | : Json::decode(urldecode($request->input(ModelsInterface::PARAM_DATA))); |
||||
60 | |||||
61 | $model = $this->getEntity($id); |
||||
62 | if (empty($model)) { |
||||
63 | return $this->response->getModelNotFoundError($this->entity, $id); |
||||
64 | } |
||||
65 | |||||
66 | $relEntity = ucfirst($relation); |
||||
67 | $formRequestEntity = $this->getFormRequestEntity(conf::getModuleName(), $relEntity); |
||||
0 ignored issues
–
show
Bug
introduced
by
Loading history...
|
|||||
68 | $relFormRequest = new $formRequestEntity(); |
||||
69 | |||||
70 | $this->response->setFormRequest($relFormRequest); |
||||
71 | $this->response->setEntity($relEntity); |
||||
72 | |||||
73 | return $this->response->getRelated($model->$relation, $data); |
||||
74 | } |
||||
75 | |||||
76 | /** |
||||
77 | * POST relationships for specific entity id |
||||
78 | * |
||||
79 | * @param Request $request |
||||
80 | * @param int|string $id |
||||
81 | * @param string $relation |
||||
82 | * @return Response |
||||
83 | */ |
||||
84 | public function createRelations(Request $request, $id, string $relation): Response |
||||
85 | { |
||||
86 | $model = $this->presetRelations($request, $id, $relation); |
||||
87 | |||||
88 | return $this->response->get($model, []); |
||||
89 | } |
||||
90 | |||||
91 | /** |
||||
92 | * PATCH relationships for specific entity id |
||||
93 | * |
||||
94 | * @param Request $request |
||||
95 | * @param int|string $id |
||||
96 | * @param string $relation |
||||
97 | * @return Response |
||||
98 | */ |
||||
99 | public function updateRelations(Request $request, $id, string $relation): Response |
||||
100 | { |
||||
101 | $model = $this->presetRelations($request, $id, $relation); |
||||
102 | |||||
103 | return $this->response->get($model, []); |
||||
104 | } |
||||
105 | |||||
106 | /** |
||||
107 | * @param Request $request |
||||
108 | * @param int|string $id |
||||
109 | * @param string $relation |
||||
110 | * @return mixed |
||||
111 | */ |
||||
112 | private function presetRelations(Request $request, $id, string $relation) |
||||
113 | { |
||||
114 | $json = Json::decode($request->getContent()); |
||||
115 | $this->setRelationships($json, $id, true); |
||||
116 | |||||
117 | // set include for relations |
||||
118 | $_GET['include'] = $relation; |
||||
119 | $model = $this->getEntity($id); |
||||
120 | |||||
121 | if (empty($model)) { |
||||
122 | return $this->response->getModelNotFoundError($this->entity, $id); |
||||
123 | } |
||||
124 | |||||
125 | return $model; |
||||
126 | } |
||||
127 | |||||
128 | /** |
||||
129 | * DELETE relationships for specific entity id |
||||
130 | * |
||||
131 | * @param Request $request JSON API formatted string |
||||
132 | * @param int|string $id int id of an entity |
||||
133 | * @param string $relation |
||||
134 | * @return Response |
||||
135 | */ |
||||
136 | public function deleteRelations(Request $request, $id, string $relation): Response |
||||
137 | { |
||||
138 | $json = Json::decode($request->getContent()); |
||||
139 | $jsonApiRels = Json::getData($json); |
||||
140 | if (empty($jsonApiRels) === false) { |
||||
141 | $lowEntity = strtolower($this->entity); |
||||
142 | foreach ($jsonApiRels as $index => $val) { |
||||
143 | $rId = $val[ApiInterface::RAML_ID]; |
||||
144 | // if pivot file exists then save |
||||
145 | $ucEntity = ucfirst($relation); |
||||
146 | $file = DirsInterface::MODULES_DIR . PhpInterface::SLASH |
||||
147 | . ConfigHelper::getModuleName() . PhpInterface::SLASH . |
||||
148 | DirsInterface::ENTITIES_DIR . PhpInterface::SLASH . |
||||
149 | $this->entity . $ucEntity . PhpInterface::PHP_EXT; |
||||
150 | if (file_exists(PhpInterface::SYSTEM_UPDIR . $file)) { // ManyToMany rel |
||||
151 | $pivotEntity = Classes::getModelEntity($this->entity . $ucEntity); |
||||
152 | // clean up old links |
||||
153 | $this->getModelEntities( |
||||
154 | $pivotEntity, |
||||
155 | [ |
||||
156 | [ |
||||
157 | $lowEntity . PhpInterface::UNDERSCORE . ApiInterface::RAML_ID => $id, |
||||
158 | $relation . PhpInterface::UNDERSCORE . ApiInterface::RAML_ID => $rId, |
||||
159 | ], |
||||
160 | ] |
||||
161 | )->delete(); |
||||
162 | } else { // OneToOne/Many - note this is always updates one row related to entity e.g.: |
||||
163 | // find article by id and update tag_id or topic_id |
||||
164 | $entity = Classes::getModelEntity($this->entity); |
||||
165 | |||||
166 | /** @var \Illuminate\Database\Eloquent\Builder $model */ |
||||
167 | $model = $this->getModelEntities( |
||||
168 | $entity, [ |
||||
169 | ApiInterface::RAML_ID, |
||||
170 | $id, |
||||
171 | ] |
||||
172 | ); |
||||
173 | |||||
174 | $model->update([$relation . PhpInterface::UNDERSCORE . ApiInterface::RAML_ID => 0]); |
||||
175 | } |
||||
176 | } |
||||
177 | } |
||||
178 | |||||
179 | return $this->response->getDeleteRelations(); |
||||
180 | } |
||||
181 | |||||
182 | /** |
||||
183 | * @param array $json |
||||
184 | * @param int|string $eId |
||||
185 | * @param bool $isRemovable |
||||
186 | */ |
||||
187 | protected function setRelationships(array $json, $eId, bool $isRemovable = false): void |
||||
188 | { |
||||
189 | $jsonApiRels = Json::getRelationships($json); |
||||
190 | if (empty($jsonApiRels) === false) { |
||||
191 | foreach ($jsonApiRels as $entity => $value) { |
||||
192 | if (empty($value[ApiInterface::RAML_DATA][ApiInterface::RAML_ID]) === false) { |
||||
193 | // if there is only one relationship |
||||
194 | $rId = $value[ApiInterface::RAML_DATA][ApiInterface::RAML_ID]; |
||||
195 | $this->saveRelationship($entity, $eId, $rId, $isRemovable); |
||||
196 | } else { |
||||
197 | // if there is an array of relationships |
||||
198 | foreach ($value[ApiInterface::RAML_DATA] as $index => $val) { |
||||
199 | $rId = $val[ApiInterface::RAML_ID]; |
||||
200 | $this->saveRelationship($entity, $eId, $rId, $isRemovable); |
||||
201 | } |
||||
202 | } |
||||
203 | } |
||||
204 | } |
||||
205 | } |
||||
206 | |||||
207 | /** |
||||
208 | * @param $entity |
||||
209 | * @param int|string $eId |
||||
210 | * @param int|string $rId |
||||
211 | * @param bool $isRemovable |
||||
212 | */ |
||||
213 | private function saveRelationship($entity, $eId, $rId, bool $isRemovable = false): void |
||||
214 | { |
||||
215 | $ucEntity = Classes::getClassName($entity); |
||||
216 | $lowEntity = MigrationsHelper::getTableName($this->entity); |
||||
217 | // if pivot file exists then save |
||||
218 | $filePivot = FileManager::getPivotFile($this->entity, $ucEntity); |
||||
219 | $filePivotInverse = FileManager::getPivotFile($ucEntity, $this->entity); |
||||
220 | $pivotExists = file_exists(PhpInterface::SYSTEM_UPDIR . $filePivot); |
||||
221 | $pivotInverseExists = file_exists(PhpInterface::SYSTEM_UPDIR . $filePivotInverse); |
||||
222 | if ($pivotExists === true || $pivotInverseExists === true) { // ManyToMany rel |
||||
223 | $pivotEntity = NULL; |
||||
224 | |||||
225 | if ($pivotExists) { |
||||
226 | $pivotEntity = Classes::getModelEntity($this->entity . $ucEntity); |
||||
227 | } else { |
||||
228 | if ($pivotInverseExists) { |
||||
229 | $pivotEntity = Classes::getModelEntity($ucEntity . $this->entity); |
||||
230 | } |
||||
231 | } |
||||
232 | |||||
233 | if ($isRemovable === true) { |
||||
234 | $this->clearPivotBeforeSave($pivotEntity, $lowEntity, $eId); |
||||
0 ignored issues
–
show
It seems like
$pivotEntity can also be of type null ; however, parameter $pivotEntity of SoliDry\Extension\BaseRe...:clearPivotBeforeSave() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
235 | } |
||||
236 | $this->savePivot($pivotEntity, $lowEntity, $entity, $eId, $rId); |
||||
0 ignored issues
–
show
It seems like
$pivotEntity can also be of type null ; however, parameter $pivotEntity of SoliDry\Extension\BaseRelationsTrait::savePivot() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
237 | } else { // OneToOne |
||||
238 | $this->saveModel($ucEntity, $lowEntity, $eId, $rId); |
||||
239 | } |
||||
240 | } |
||||
241 | |||||
242 | /** |
||||
243 | * @param string $pivotEntity |
||||
244 | * @param string $lowEntity |
||||
245 | * @param int|string $eId |
||||
246 | */ |
||||
247 | private function clearPivotBeforeSave(string $pivotEntity, string $lowEntity, $eId): void |
||||
248 | { |
||||
249 | if ($this->relsRemoved === false) { |
||||
250 | // clean up old links |
||||
251 | $this->getModelEntities( |
||||
252 | $pivotEntity, |
||||
253 | [$lowEntity . PhpInterface::UNDERSCORE . ApiInterface::RAML_ID, $eId] |
||||
254 | )->delete(); |
||||
255 | $this->relsRemoved = true; |
||||
0 ignored issues
–
show
|
|||||
256 | } |
||||
257 | } |
||||
258 | |||||
259 | /** |
||||
260 | * @param string $pivotEntity |
||||
261 | * @param string $lowEntity |
||||
262 | * @param string $entity |
||||
263 | * @param int|string $eId |
||||
264 | * @param int|string $rId |
||||
265 | */ |
||||
266 | private function savePivot(string $pivotEntity, string $lowEntity, string $entity, $eId, $rId): void |
||||
267 | { |
||||
268 | $pivot = new $pivotEntity(); |
||||
269 | $pivot->{$entity . PhpInterface::UNDERSCORE . ApiInterface::RAML_ID} = $rId; |
||||
270 | $pivot->{$lowEntity . PhpInterface::UNDERSCORE . ApiInterface::RAML_ID} = $eId; |
||||
271 | $pivot->save(); |
||||
272 | } |
||||
273 | |||||
274 | /** |
||||
275 | * Saves model with related id from linked table full duplex |
||||
276 | * |
||||
277 | * @param string $ucEntity |
||||
278 | * @param string $lowEntity |
||||
279 | * @param int|string $eId |
||||
280 | * @param int|string $rId |
||||
281 | */ |
||||
282 | private function saveModel(string $ucEntity, string $lowEntity, $eId, $rId): void |
||||
283 | { |
||||
284 | $relEntity = Classes::getModelEntity($ucEntity); |
||||
285 | $model = $this->getModelEntity($relEntity, $rId); |
||||
286 | |||||
287 | // swap table and field trying to find rels with inverse |
||||
288 | if (!property_exists($model, $lowEntity . PhpInterface::UNDERSCORE . ApiInterface::RAML_ID)) { |
||||
289 | $ucTmp = $ucEntity; |
||||
290 | $ucEntity = ucfirst($lowEntity); |
||||
291 | $relEntity = Classes::getModelEntity($ucEntity); |
||||
292 | $model = $this->getModelEntity($relEntity, $eId); |
||||
293 | $lowEntity = strtolower($ucTmp); |
||||
294 | |||||
295 | $model->{$lowEntity . PhpInterface::UNDERSCORE . ApiInterface::RAML_ID} = $rId; |
||||
296 | $model->save(); |
||||
297 | |||||
298 | return; |
||||
299 | } |
||||
300 | |||||
301 | $model->{$lowEntity . PhpInterface::UNDERSCORE . ApiInterface::RAML_ID} = $eId; |
||||
302 | $model->save(); |
||||
303 | } |
||||
304 | } |