1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace AlgoWeb\PODataLaravel\Query; |
4
|
|
|
|
5
|
|
|
use AlgoWeb\PODataLaravel\Enums\ActionVerb; |
6
|
|
|
use Illuminate\Database\Eloquent\Relations\Relation; |
7
|
|
|
use POData\Common\InvalidOperationException; |
8
|
|
|
use POData\Providers\Metadata\ResourceProperty; |
9
|
|
|
use POData\Providers\Metadata\ResourceSet; |
10
|
|
|
use POData\UriProcessor\QueryProcessor\Expression\Parser\IExpressionProvider; |
11
|
|
|
use POData\UriProcessor\QueryProcessor\ExpressionParser\FilterInfo; |
12
|
|
|
use POData\UriProcessor\QueryProcessor\OrderByParser\InternalOrderByInfo; |
13
|
|
|
use POData\UriProcessor\QueryProcessor\SkipTokenParser\SkipTokenInfo; |
14
|
|
|
use POData\UriProcessor\ResourcePathProcessor\SegmentParser\KeyDescriptor; |
15
|
|
|
use POData\Providers\Query\IQueryProvider; |
16
|
|
|
use POData\Providers\Expression\MySQLExpressionProvider; |
17
|
|
|
use POData\Providers\Query\QueryType; |
18
|
|
|
use POData\Providers\Query\QueryResult; |
19
|
|
|
use POData\Providers\Expression\PHPExpressionProvider; |
20
|
|
|
use \POData\Common\ODataException; |
21
|
|
|
use AlgoWeb\PODataLaravel\Interfaces\AuthInterface; |
22
|
|
|
use AlgoWeb\PODataLaravel\Auth\NullAuthProvider; |
23
|
|
|
use Illuminate\Support\Facades\App; |
24
|
|
|
use Illuminate\Database\Eloquent\Model; |
25
|
|
|
use Symfony\Component\Process\Exception\InvalidArgumentException; |
26
|
5 |
|
|
27
|
|
|
class LaravelQuery implements IQueryProvider |
28
|
|
|
{ |
29
|
5 |
|
protected $expression; |
30
|
5 |
|
protected $auth; |
31
|
5 |
|
protected $reader; |
32
|
5 |
|
public $queryProviderClassName; |
33
|
|
|
private $verbMap = []; |
34
|
|
|
|
35
|
|
|
public function __construct(AuthInterface $auth = null) |
36
|
|
|
{ |
37
|
|
|
/* MySQLExpressionProvider();*/ |
38
|
|
|
$this->expression = new LaravelExpressionProvider(); //PHPExpressionProvider('expression'); |
39
|
|
|
$this->queryProviderClassName = get_class($this); |
40
|
|
|
$this->auth = isset($auth) ? $auth : new NullAuthProvider(); |
41
|
|
|
$this->reader = new LaravelReadQuery($this->auth); |
42
|
|
|
$this->verbMap['create'] = ActionVerb::CREATE(); |
43
|
|
|
$this->verbMap['update'] = ActionVerb::UPDATE(); |
44
|
|
|
$this->verbMap['delete'] = ActionVerb::DELETE(); |
45
|
|
|
} |
46
|
|
|
|
47
|
|
|
/** |
48
|
|
|
* Indicates if the QueryProvider can handle ordered paging, this means respecting order, skip, and top parameters |
49
|
|
|
* If the query provider can not handle ordered paging, it must return the entire result set and POData will |
50
|
|
|
* perform the ordering and paging |
51
|
|
|
* |
52
|
|
|
* @return Boolean True if the query provider can handle ordered paging, false if POData should perform the paging |
53
|
|
|
*/ |
54
|
|
|
public function handlesOrderedPaging() |
55
|
|
|
{ |
56
|
|
|
return true; |
57
|
|
|
} |
58
|
|
|
|
59
|
|
|
/** |
60
|
|
|
* Gets the expression provider used by to compile OData expressions into expression used by this query provider. |
61
|
|
|
* |
62
|
|
|
* @return \POData\Providers\Expression\IExpressionProvider |
63
|
|
|
*/ |
64
|
|
|
public function getExpressionProvider() |
65
|
|
|
{ |
66
|
|
|
return $this->expression; |
67
|
|
|
} |
68
|
|
|
|
69
|
|
|
/** |
70
|
3 |
|
* Gets the LaravelReadQuery instance used to handle read queries (repetitious, nyet?) |
71
|
|
|
* |
72
|
|
|
* @return LaravelReadQuery |
73
|
|
|
*/ |
74
|
|
|
public function getReader() |
75
|
|
|
{ |
76
|
|
|
return $this->reader; |
77
|
|
|
} |
78
|
|
|
|
79
|
3 |
|
/** |
80
|
|
|
* Gets collection of entities belongs to an entity set |
81
|
|
|
* IE: http://host/EntitySet |
82
|
3 |
|
* http://host/EntitySet?$skip=10&$top=5&filter=Prop gt Value |
83
|
1 |
|
* |
84
|
1 |
|
* @param QueryType $queryType Is this is a query for a count, entities, or entities-with-count |
85
|
|
|
* @param ResourceSet $resourceSet The entity set containing the entities to fetch |
86
|
3 |
|
* @param FilterInfo|null $filterInfo The $filter parameter of the OData query. NULL if none specified |
87
|
3 |
|
* @param null|InternalOrderByInfo $orderBy sorted order if we want to get the data in some specific order |
88
|
3 |
|
* @param integer|null $top number of records which need to be retrieved |
89
|
|
|
* @param integer|null $skip number of records which need to be skipped |
90
|
3 |
|
* @param SkipTokenInfo|null $skipToken value indicating what records to skip |
91
|
|
|
* @param Model|Relation|null $sourceEntityInstance Starting point of query |
92
|
|
|
* |
93
|
|
|
* @return QueryResult |
94
|
|
|
*/ |
95
|
|
View Code Duplication |
public function getResourceSet( |
|
|
|
|
96
|
|
|
QueryType $queryType, |
97
|
1 |
|
ResourceSet $resourceSet, |
98
|
|
|
$filterInfo = null, |
99
|
|
|
$orderBy = null, |
100
|
3 |
|
$top = null, |
101
|
1 |
|
$skip = null, |
102
|
1 |
|
$skipToken = null, |
103
|
3 |
|
$sourceEntityInstance = null |
104
|
1 |
|
) { |
105
|
1 |
|
$source = $this->unpackSourceEntity($sourceEntityInstance); |
106
|
|
|
return $this->getReader()->getResourceSet( |
107
|
3 |
|
$queryType, |
108
|
|
|
$resourceSet, |
109
|
3 |
|
$filterInfo, |
110
|
|
|
$orderBy, |
111
|
|
|
$top, |
112
|
|
|
$skip, |
113
|
|
|
$skipToken, |
114
|
|
|
$source |
115
|
|
|
); |
116
|
|
|
} |
117
|
3 |
|
/** |
118
|
1 |
|
* Gets an entity instance from an entity set identified by a key |
119
|
1 |
|
* IE: http://host/EntitySet(1L) |
120
|
1 |
|
* http://host/EntitySet(KeyA=2L,KeyB='someValue') |
121
|
1 |
|
* |
122
|
1 |
|
* @param ResourceSet $resourceSet The entity set containing the entity to fetch |
123
|
3 |
|
* @param KeyDescriptor|null $keyDescriptor The key identifying the entity to fetch |
124
|
3 |
|
* |
125
|
|
|
* @return Model|null Returns entity instance if found else null |
126
|
|
|
*/ |
127
|
3 |
|
public function getResourceFromResourceSet( |
128
|
3 |
|
ResourceSet $resourceSet, |
129
|
3 |
|
KeyDescriptor $keyDescriptor = null |
130
|
|
|
) { |
131
|
|
|
return $this->getReader()->getResourceFromResourceSet($resourceSet, $keyDescriptor); |
132
|
|
|
} |
133
|
|
|
|
134
|
|
|
/** |
135
|
|
|
* Get related resource set for a resource |
136
|
|
|
* IE: http://host/EntitySet(1L)/NavigationPropertyToCollection |
137
|
|
|
* http://host/EntitySet?$expand=NavigationPropertyToCollection |
138
|
|
|
* |
139
|
|
|
* @param QueryType $queryType Is this is a query for a count, entities, or entities-with-count |
140
|
|
|
* @param ResourceSet $sourceResourceSet The entity set containing the source entity |
141
|
|
|
* @param object $sourceEntityInstance The source entity instance |
142
|
|
|
* @param ResourceSet $targetResourceSet The resource set pointed to by the navigation property |
143
|
|
|
* @param ResourceProperty $targetProperty The navigation property to retrieve |
144
|
|
|
* @param FilterInfo|null $filter The $filter parameter of the OData query. NULL if none specified |
145
|
|
|
* @param mixed|null $orderBy sorted order if we want to get the data in some specific order |
146
|
|
|
* @param integer|null $top number of records which need to be retrieved |
147
|
|
|
* @param integer|null $skip number of records which need to be skipped |
148
|
|
|
* @param SkipTokenInfo|null $skipToken value indicating what records to skip |
149
|
|
|
* |
150
|
|
|
* @return QueryResult |
151
|
|
|
* |
152
|
|
|
*/ |
153
|
|
View Code Duplication |
public function getRelatedResourceSet( |
|
|
|
|
154
|
|
|
QueryType $queryType, |
155
|
|
|
ResourceSet $sourceResourceSet, |
156
|
|
|
$sourceEntityInstance, |
157
|
|
|
ResourceSet $targetResourceSet, |
158
|
|
|
ResourceProperty $targetProperty, |
159
|
|
|
FilterInfo $filter = null, |
160
|
|
|
$orderBy = null, |
161
|
|
|
$top = null, |
162
|
|
|
$skip = null, |
163
|
|
|
$skipToken = null |
164
|
|
|
) { |
165
|
|
|
$source = $this->unpackSourceEntity($sourceEntityInstance); |
166
|
|
|
return $this->getReader()->getRelatedResourceSet( |
167
|
|
|
$queryType, |
168
|
|
|
$sourceResourceSet, |
169
|
|
|
$source, |
170
|
|
|
$targetResourceSet, |
171
|
|
|
$targetProperty, |
172
|
|
|
$filter, |
173
|
|
|
$orderBy, |
174
|
|
|
$top, |
175
|
|
|
$skip, |
176
|
|
|
$skipToken |
177
|
|
|
); |
178
|
|
|
} |
179
|
|
|
|
180
|
|
|
/** |
181
|
|
|
* Gets a related entity instance from an entity set identified by a key |
182
|
|
|
* IE: http://host/EntitySet(1L)/NavigationPropertyToCollection(33) |
183
|
|
|
* |
184
|
|
|
* @param ResourceSet $sourceResourceSet The entity set containing the source entity |
185
|
|
|
* @param object $sourceEntityInstance The source entity instance. |
186
|
|
|
* @param ResourceSet $targetResourceSet The entity set containing the entity to fetch |
187
|
|
|
* @param ResourceProperty $targetProperty The metadata of the target property. |
188
|
|
|
* @param KeyDescriptor $keyDescriptor The key identifying the entity to fetch |
189
|
|
|
* |
190
|
|
|
* @return Model|null Returns entity instance if found else null |
191
|
|
|
*/ |
192
|
|
|
public function getResourceFromRelatedResourceSet( |
193
|
|
|
ResourceSet $sourceResourceSet, |
194
|
|
|
$sourceEntityInstance, |
195
|
|
|
ResourceSet $targetResourceSet, |
196
|
|
|
ResourceProperty $targetProperty, |
197
|
|
|
KeyDescriptor $keyDescriptor |
198
|
|
|
) { |
199
|
3 |
|
$source = $this->unpackSourceEntity($sourceEntityInstance); |
200
|
|
|
return $this->getReader()->getResourceFromRelatedResourceSet( |
201
|
|
|
$sourceResourceSet, |
202
|
|
|
$source, |
203
|
|
|
$targetResourceSet, |
204
|
|
|
$targetProperty, |
205
|
|
|
$keyDescriptor |
206
|
|
|
); |
207
|
|
|
} |
208
|
|
|
|
209
|
|
|
/** |
210
|
3 |
|
* Get related resource for a resource |
211
|
3 |
|
* IE: http://host/EntitySet(1L)/NavigationPropertyToSingleEntity |
212
|
|
|
* http://host/EntitySet?$expand=NavigationPropertyToSingleEntity |
213
|
3 |
|
* |
214
|
3 |
|
* @param ResourceSet $sourceResourceSet The entity set containing the source entity |
215
|
3 |
|
* @param object $sourceEntityInstance The source entity instance. |
216
|
3 |
|
* @param ResourceSet $targetResourceSet The entity set containing the entity pointed to by the navigation property |
217
|
3 |
|
* @param ResourceProperty $targetProperty The navigation property to fetch |
218
|
3 |
|
* |
219
|
3 |
|
* @return object|null The related resource if found else null |
220
|
|
|
*/ |
221
|
3 |
|
public function getRelatedResourceReference( |
222
|
|
|
ResourceSet $sourceResourceSet, |
223
|
|
|
$sourceEntityInstance, |
224
|
|
|
ResourceSet $targetResourceSet, |
225
|
|
|
ResourceProperty $targetProperty |
226
|
|
|
) { |
227
|
|
|
$source = $this->unpackSourceEntity($sourceEntityInstance); |
228
|
|
|
|
229
|
|
|
$result = $this->getReader()->getRelatedResourceReference( |
230
|
|
|
$sourceResourceSet, |
231
|
|
|
$source, |
232
|
|
|
$targetResourceSet, |
233
|
|
|
$targetProperty |
234
|
|
|
); |
235
|
|
|
return $result; |
236
|
|
|
} |
237
|
|
|
|
238
|
|
|
/** |
239
|
|
|
* Updates a resource |
240
|
|
|
* |
241
|
|
|
* @param ResourceSet $sourceResourceSet The entity set containing the source entity |
242
|
|
|
* @param object $sourceEntityInstance The source entity instance |
243
|
|
|
* @param KeyDescriptor $keyDescriptor The key identifying the entity to fetch |
244
|
|
|
* @param object $data The New data for the entity instance. |
245
|
|
|
* @param bool $shouldUpdate Should undefined values be updated or reset to default |
246
|
|
|
* |
247
|
|
|
* @return object|null The new resource value if it is assignable or throw exception for null. |
248
|
|
|
*/ |
249
|
|
|
public function updateResource( |
250
|
|
|
ResourceSet $sourceResourceSet, |
251
|
|
|
$sourceEntityInstance, |
252
|
|
|
KeyDescriptor $keyDescriptor, |
253
|
|
|
$data, |
254
|
|
|
$shouldUpdate = false |
255
|
|
|
) { |
256
|
|
|
$source = $this->unpackSourceEntity($sourceEntityInstance); |
257
|
|
|
|
258
|
|
|
$verb = 'update'; |
259
|
|
|
return $this->createUpdateCoreWrapper($sourceResourceSet, $source, $data, $verb); |
260
|
|
|
} |
261
|
|
|
/** |
262
|
|
|
* Delete resource from a resource set. |
263
|
|
|
* @param ResourceSet $sourceResourceSet |
264
|
|
|
* @param object $sourceEntityInstance |
265
|
|
|
* |
266
|
|
|
* return bool true if resources sucessfully deteled, otherwise false. |
267
|
|
|
*/ |
268
|
|
|
public function deleteResource( |
269
|
|
|
ResourceSet $sourceResourceSet, |
270
|
|
|
$sourceEntityInstance |
271
|
|
|
) { |
272
|
|
|
$source = $this->unpackSourceEntity($sourceEntityInstance); |
273
|
|
|
|
274
|
|
|
$verb = 'delete'; |
275
|
|
|
if (!($source instanceof Model)) { |
276
|
|
|
throw new InvalidArgumentException('Source entity must be an Eloquent model.'); |
277
|
|
|
} |
278
|
|
|
|
279
|
|
|
$class = $sourceResourceSet->getResourceType()->getInstanceType()->getName(); |
280
|
|
|
$id = $source->getKey(); |
281
|
|
|
$name = $source->getKeyName(); |
282
|
|
|
$data = [$name => $id]; |
283
|
|
|
|
284
|
|
|
$data = $this->createUpdateDeleteCore($source, $data, $class, $verb); |
285
|
|
|
|
286
|
|
|
$success = isset($data['id']); |
287
|
|
|
if ($success) { |
288
|
|
|
return true; |
289
|
|
|
} |
290
|
|
|
throw new ODataException('Target model not successfully deleted', 422); |
291
|
|
|
} |
292
|
1 |
|
/** |
293
|
|
|
* @param ResourceSet $resourceSet The entity set containing the entity to fetch |
294
|
|
|
* @param object $sourceEntityInstance The source entity instance |
295
|
|
|
* @param object $data The New data for the entity instance. |
296
|
|
|
* |
297
|
|
|
* returns object|null returns the newly created model if sucessful or null if model creation failed. |
298
|
|
|
*/ |
299
|
1 |
|
public function createResourceforResourceSet( |
300
|
1 |
|
ResourceSet $resourceSet, |
301
|
|
|
$sourceEntityInstance, |
302
|
1 |
|
$data |
303
|
|
|
) { |
304
|
1 |
|
$source = $this->unpackSourceEntity($sourceEntityInstance); |
305
|
|
|
|
306
|
1 |
|
$verb = 'create'; |
307
|
|
|
return $this->createUpdateCoreWrapper($resourceSet, $source, $data, $verb); |
308
|
|
|
} |
309
|
1 |
|
|
310
|
|
|
/** |
311
|
|
|
* @param $sourceEntityInstance |
312
|
|
|
* @param $data |
313
|
|
|
* @param $class |
314
|
|
|
* @param string $verb |
315
|
|
|
* @return array|mixed |
316
|
|
|
* @throws ODataException |
317
|
|
|
* @throws InvalidOperationException |
318
|
1 |
|
*/ |
319
|
|
|
private function createUpdateDeleteCore($sourceEntityInstance, $data, $class, $verb) |
320
|
|
|
{ |
321
|
|
|
$raw = App::make('metadataControllers'); |
322
|
1 |
|
$map = $raw->getMetadata(); |
323
|
1 |
|
|
324
|
1 |
|
if (!array_key_exists($class, $map)) { |
325
|
1 |
|
throw new \POData\Common\InvalidOperationException('Controller mapping missing for class '.$class.'.'); |
326
|
1 |
|
} |
327
|
|
|
$goal = $raw->getMapping($class, $verb); |
328
|
1 |
|
if (null == $goal) { |
329
|
|
|
throw new \POData\Common\InvalidOperationException( |
330
|
1 |
|
'Controller mapping missing for '.$verb.' verb on class '.$class.'.' |
331
|
1 |
|
); |
332
|
|
|
} |
333
|
|
|
|
334
|
1 |
|
assert(null !== $data, 'Data must not be null'); |
335
|
|
|
if (is_object($data)) { |
336
|
|
|
$arrayData = (array) $data; |
337
|
|
|
} else { |
338
|
|
|
$arrayData = $data; |
339
|
|
|
} |
340
|
|
|
if (!is_array($arrayData)) { |
341
|
|
|
throw \POData\Common\ODataException::createPreConditionFailedError( |
342
|
|
|
'Data not resolvable to key-value array.' |
343
|
1 |
|
); |
344
|
|
|
} |
345
|
|
|
|
346
|
|
|
$controlClass = $goal['controller']; |
347
|
|
|
$method = $goal['method']; |
348
|
1 |
|
$paramList = $goal['parameters']; |
349
|
1 |
|
$controller = App::make($controlClass); |
350
|
|
|
$parms = $this->createUpdateDeleteProcessInput($sourceEntityInstance, $arrayData, $paramList); |
351
|
1 |
|
unset($data); |
352
|
|
|
|
353
|
1 |
|
$result = call_user_func_array(array($controller, $method), $parms); |
354
|
|
|
|
355
|
1 |
|
return $this->createUpdateDeleteProcessOutput($result); |
356
|
|
|
} |
357
|
|
|
|
358
|
1 |
|
/** |
359
|
|
|
* Puts an entity instance to entity set identified by a key. |
360
|
|
|
* |
361
|
|
|
* @param ResourceSet $resourceSet The entity set containing the entity to update |
362
|
|
|
* @param KeyDescriptor $keyDescriptor The key identifying the entity to update |
363
|
|
|
* @param $data |
364
|
|
|
* |
365
|
|
|
* @return bool|null Returns result of executing query |
366
|
|
|
*/ |
367
|
|
|
public function putResource( |
368
|
|
|
ResourceSet $resourceSet, |
369
|
|
|
KeyDescriptor $keyDescriptor, |
370
|
3 |
|
$data |
371
|
|
|
) { |
372
|
3 |
|
// TODO: Implement putResource() method. |
|
|
|
|
373
|
3 |
|
return true; |
374
|
|
|
} |
375
|
3 |
|
|
376
|
|
|
/** |
377
|
|
|
* @param ResourceSet $sourceResourceSet |
378
|
3 |
|
* @param $source |
379
|
3 |
|
* @param $data |
380
|
|
|
* @param $verb |
381
|
|
|
* @return mixed |
382
|
|
|
* @throws ODataException |
383
|
|
|
* @throws \POData\Common\InvalidOperationException |
384
|
|
|
*/ |
385
|
3 |
|
private function createUpdateCoreWrapper(ResourceSet $sourceResourceSet, Model $source = null, $data, $verb) |
|
|
|
|
386
|
|
|
{ |
387
|
|
|
$lastWord = 'update' == $verb ? 'updated' : 'created'; |
388
|
3 |
|
$class = $sourceResourceSet->getResourceType()->getInstanceType()->getName(); |
389
|
2 |
|
if (!$this->auth->canAuth($this->verbMap[$verb], $class, $source)) { |
390
|
2 |
|
throw new ODataException('Access denied', 403); |
391
|
3 |
|
} |
392
|
|
|
|
393
|
|
|
$data = $this->createUpdateDeleteCore($source, $data, $class, $verb); |
|
|
|
|
394
|
|
|
|
395
|
|
|
$success = isset($data['id']); |
396
|
|
|
|
397
|
3 |
|
if ($success) { |
398
|
3 |
|
try { |
399
|
3 |
|
return $class::findOrFail($data['id']); |
400
|
3 |
|
} catch (\Exception $e) { |
401
|
3 |
|
throw new ODataException($e->getMessage(), 500); |
402
|
|
|
} |
403
|
3 |
|
} |
404
|
3 |
|
throw new ODataException('Target model not successfully '.$lastWord, 422); |
405
|
3 |
|
} |
406
|
3 |
|
|
407
|
2 |
|
/** |
408
|
2 |
|
* @param $sourceEntityInstance |
409
|
2 |
|
* @param $data |
410
|
2 |
|
* @param $paramList |
411
|
2 |
|
* @return array |
412
|
|
|
*/ |
413
|
|
|
private function createUpdateDeleteProcessInput(Model $sourceEntityInstance, $data, $paramList) |
414
|
|
|
{ |
415
|
2 |
|
$parms = []; |
416
|
|
|
|
417
|
|
|
foreach ($paramList as $spec) { |
418
|
3 |
|
$varType = isset($spec['type']) ? $spec['type'] : null; |
419
|
3 |
|
$varName = $spec['name']; |
420
|
|
|
if (null == $varType) { |
421
|
3 |
|
$parms[] = ('id' == $varName) ? $sourceEntityInstance->getKey() : $sourceEntityInstance->$varName; |
422
|
|
|
continue; |
423
|
3 |
|
} |
424
|
|
|
// TODO: Give this smarts and actively pick up instantiation details |
|
|
|
|
425
|
|
|
$var = new $varType(); |
426
|
3 |
|
if ($spec['isRequest']) { |
427
|
3 |
|
$var->setMethod('POST'); |
428
|
3 |
|
$var->request = new \Symfony\Component\HttpFoundation\ParameterBag($data); |
429
|
3 |
|
} |
430
|
|
|
$parms[] = $var; |
431
|
3 |
|
} |
432
|
|
|
return $parms; |
433
|
|
|
} |
434
|
3 |
|
|
435
|
|
|
/** |
436
|
|
|
* @param $result |
437
|
|
|
* @return array|mixed |
438
|
|
|
* @throws ODataException |
439
|
3 |
|
*/ |
440
|
|
|
private function createUpdateDeleteProcessOutput($result) |
441
|
|
|
{ |
442
|
|
|
if (!($result instanceof \Illuminate\Http\JsonResponse)) { |
443
|
|
|
throw ODataException::createInternalServerError('Controller response not well-formed json.'); |
444
|
|
|
} |
445
|
|
|
$outData = $result->getData(); |
446
|
|
|
if (is_object($outData)) { |
447
|
|
|
$outData = (array)$outData; |
448
|
|
|
} |
449
|
|
|
|
450
|
|
|
if (!is_array($outData)) { |
451
|
|
|
throw ODataException::createInternalServerError('Controller response does not have an array.'); |
452
|
|
|
} |
453
|
|
|
if (!(key_exists('id', $outData) && key_exists('status', $outData) && key_exists('errors', $outData))) { |
454
|
|
|
throw ODataException::createInternalServerError( |
455
|
|
|
'Controller response array missing at least one of id, status and/or errors fields.' |
456
|
|
|
); |
457
|
|
|
} |
458
|
|
|
return $outData; |
459
|
|
|
} |
460
|
|
|
|
461
|
|
|
/** |
462
|
|
|
* @param $sourceEntityInstance |
463
|
|
|
* @return mixed|null|\object[] |
464
|
|
|
*/ |
465
|
|
|
private function unpackSourceEntity($sourceEntityInstance) |
466
|
|
|
{ |
467
|
|
|
if ($sourceEntityInstance instanceof QueryResult) { |
468
|
|
|
$sourceEntityInstance = $sourceEntityInstance->results; |
469
|
|
|
$sourceEntityInstance = (is_array($sourceEntityInstance)) |
|
|
|
|
470
|
|
|
? $sourceEntityInstance[0] : $sourceEntityInstance; |
471
|
|
|
} |
472
|
|
|
return $sourceEntityInstance; |
473
|
|
|
} |
474
|
|
|
} |
475
|
|
|
|
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.