Passed
Pull Request — master (#182)
by Alex
06:07
created

LaravelQuery::getRelatedResourceSet()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 24
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 12
c 0
b 0
f 0
dl 0
loc 24
rs 9.8666
ccs 5
cts 5
cp 1
cc 1
nc 1
nop 10
crap 1

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
namespace AlgoWeb\PODataLaravel\Query;
4
5
use AlgoWeb\PODataLaravel\Auth\NullAuthProvider;
6
use AlgoWeb\PODataLaravel\Controllers\MetadataControllerContainer;
7
use AlgoWeb\PODataLaravel\Enums\ActionVerb;
8
use AlgoWeb\PODataLaravel\Interfaces\AuthInterface;
9
use AlgoWeb\PODataLaravel\Providers\MetadataProvider;
10
use Illuminate\Database\Eloquent\Model;
11
use Illuminate\Database\Eloquent\Relations\Relation;
12
use Illuminate\Support\Facades\App;
13
use Illuminate\Support\Facades\DB;
14
use POData\Common\InvalidOperationException;
15
use POData\Common\ODataException;
16
use POData\Providers\Metadata\ResourceProperty;
17
use POData\Providers\Metadata\ResourceSet;
18
use POData\Providers\Query\IQueryProvider;
19
use POData\Providers\Query\QueryResult;
20
use POData\Providers\Query\QueryType;
21
use POData\UriProcessor\QueryProcessor\ExpressionParser\FilterInfo;
22
use POData\UriProcessor\QueryProcessor\OrderByParser\InternalOrderByInfo;
23
use POData\UriProcessor\QueryProcessor\SkipTokenParser\SkipTokenInfo;
24
use POData\UriProcessor\ResourcePathProcessor\SegmentParser\KeyDescriptor;
25
use Symfony\Component\Process\Exception\InvalidArgumentException;
26 5
27
class LaravelQuery extends LaravelBaseQuery implements IQueryProvider
28
{
29 5
    protected $expression;
30 5
    protected $reader;
31 5
    protected $modelHook;
32 5
    protected $bulk;
33
    protected $writer;
34
    public $queryProviderClassName;
35
    private static $touchList = [];
36
    private static $inBatch;
37
38
    public function __construct(AuthInterface $auth = null)
39
    {
40
        parent::__construct($auth);
41
        /* MySQLExpressionProvider();*/
42
        $this->expression = new LaravelExpressionProvider(); //PHPExpressionProvider('expression');
43
        $this->queryProviderClassName = get_class($this);
44
        $this->reader = new LaravelReadQuery($this->getAuth());
45
        $this->modelHook = new LaravelHookQuery($this->getAuth());
46
        $this->bulk = new LaravelBulkQuery($this, $this->getAuth());
47
        $this->writer = new LaravelWriteQuery($this->getAuth());
48
49
        self::$touchList = [];
50
        self::$inBatch = false;
51
    }
52
53
    /**
54
     * Indicates if the QueryProvider can handle ordered paging, this means respecting order, skip, and top parameters
55
     * If the query provider can not handle ordered paging, it must return the entire result set and POData will
56
     * perform the ordering and paging.
57
     *
58
     * @return Boolean True if the query provider can handle ordered paging, false if POData should perform the paging
59
     */
60
    public function handlesOrderedPaging()
61
    {
62
        return true;
63
    }
64
65
    /**
66
     * Gets the expression provider used by to compile OData expressions into expression used by this query provider.
67
     *
68
     * @return \POData\Providers\Expression\IExpressionProvider
69
     */
70 3
    public function getExpressionProvider()
71
    {
72
        return $this->expression;
73
    }
74
75
    /**
76
     * Gets the LaravelReadQuery instance used to handle read queries (repetitious, nyet?).
77
     *
78
     * @return LaravelReadQuery
79 3
     */
80
    public function getReader()
81
    {
82 3
        return $this->reader;
83 1
    }
84 1
85
    /**
86 3
     * Gets the LaravelHookQuery instance used to handle hook/unhook queries (repetitious, nyet?).
87 3
     *
88 3
     * @return LaravelHookQuery
89
     */
90 3
    public function getModelHook()
91
    {
92
        return $this->modelHook;
93
    }
94
95
    /**
96
     * Gets the LaravelBulkQuery instance used to handle bulk queries (repetitious, nyet?).
97 1
     *
98
     * @return LaravelBulkQuery
99
     */
100 3
    public function getBulk()
101 1
    {
102 1
        return $this->bulk;
103 3
    }
104 1
105 1
    /**
106
     * Gets collection of entities belongs to an entity set
107 3
     * IE: http://host/EntitySet
108
     *  http://host/EntitySet?$skip=10&$top=5&filter=Prop gt Value.
109 3
     *
110
     * @param QueryType                $queryType            Is this is a query for a count, entities,
111
     *                                                       or entities-with-count?
112
     * @param ResourceSet              $resourceSet          The entity set containing the entities to fetch
113
     * @param FilterInfo|null          $filterInfo           The $filter parameter of the OData query.  NULL if absent
114
     * @param null|InternalOrderByInfo $orderBy              sorted order if we want to get the data in some
115
     *                                                       specific order
116
     * @param int|null                 $top                  number of records which need to be retrieved
117 3
     * @param int|null                 $skip                 number of records which need to be skipped
118 1
     * @param SkipTokenInfo|null       $skipToken            value indicating what records to skip
119 1
     * @param string[]|null            $eagerLoad            array of relations to eager load
120 1
     * @param Model|Relation|null      $sourceEntityInstance Starting point of query
121 1
     *
122 1
     * @return QueryResult
123 3
     * @throws InvalidOperationException
124 3
     * @throws ODataException
125
     * @throws \ReflectionException
126
     */
127 3
    public function getResourceSet(
128 3
        QueryType $queryType,
129 3
        ResourceSet $resourceSet,
130
        $filterInfo = null,
131
        $orderBy = null,
132
        $top = null,
133
        $skip = null,
134
        $skipToken = null,
135
        array $eagerLoad = null,
136
        $sourceEntityInstance = null
137
    ) {
138
        /** @var Model|Relation|null $source */
139
        $source = $this->unpackSourceEntity($sourceEntityInstance);
140
        return $this->getReader()->getResourceSet(
141
            $queryType,
142
            $resourceSet,
143
            $filterInfo,
144
            $orderBy,
145
            $top,
146
            $skip,
147
            $skipToken,
148
            $eagerLoad,
149
            $source
150
        );
151
    }
152
    /**
153
     * Gets an entity instance from an entity set identified by a key
154
     * IE: http://host/EntitySet(1L)
155
     * http://host/EntitySet(KeyA=2L,KeyB='someValue').
156
     *
157
     * @param ResourceSet        $resourceSet   The entity set containing the entity to fetch
158
     * @param KeyDescriptor|null $keyDescriptor The key identifying the entity to fetch
159
     * @param string[]|null      $eagerLoad     array of relations to eager load
160
     *
161
     * @return Model|null Returns entity instance if found else null
162
     * @throws \Exception
163
     */
164
    public function getResourceFromResourceSet(
165
        ResourceSet $resourceSet,
166
        KeyDescriptor $keyDescriptor = null,
167
        array $eagerLoad = null
168
    ) {
169
        return $this->getReader()->getResourceFromResourceSet($resourceSet, $keyDescriptor, $eagerLoad);
170
    }
171
172
    /**
173
     * Get related resource set for a resource
174
     * IE: http://host/EntitySet(1L)/NavigationPropertyToCollection
175
     * http://host/EntitySet?$expand=NavigationPropertyToCollection.
176
     *
177
     * @param QueryType          $queryType            Is this is a query for a count, entities, or entities-with-count
178
     * @param ResourceSet        $sourceResourceSet    The entity set containing the source entity
179
     * @param object             $sourceEntityInstance The source entity instance
180
     * @param ResourceSet        $targetResourceSet    The resource set pointed to by the navigation property
181
     * @param ResourceProperty   $targetProperty       The navigation property to retrieve
182
     * @param FilterInfo|null    $filter               The $filter parameter of the OData query.  NULL if none specified
183
     * @param mixed|null         $orderBy              sorted order if we want to get the data in some specific order
184
     * @param int|null           $top                  number of records which need to be retrieved
185
     * @param int|null           $skip                 number of records which need to be skipped
186
     * @param SkipTokenInfo|null $skipToken            value indicating what records to skip
187
     *
188
     * @return QueryResult
189
     * @throws \Exception
190
     */
191
    public function getRelatedResourceSet(
192
        QueryType $queryType,
193
        ResourceSet $sourceResourceSet,
194
        $sourceEntityInstance,
195
        ResourceSet $targetResourceSet,
196
        ResourceProperty $targetProperty,
197
        FilterInfo $filter = null,
198
        $orderBy = null,
199 3
        $top = null,
200
        $skip = null,
201
        $skipToken = null
202
    ) {
203
        $source = $this->unpackSourceEntity($sourceEntityInstance);
204
        return $this->getReader()->getRelatedResourceSet(
205
            $queryType,
206
            $sourceResourceSet,
207
            $source,
208
            $targetResourceSet,
209
            $targetProperty,
210 3
            $filter,
211 3
            $orderBy,
212
            $top,
213 3
            $skip,
214 3
            $skipToken
215 3
        );
216 3
    }
217 3
218 3
    /**
219 3
     * Gets a related entity instance from an entity set identified by a key
220
     * IE: http://host/EntitySet(1L)/NavigationPropertyToCollection(33).
221 3
     *
222
     * @param ResourceSet      $sourceResourceSet    The entity set containing the source entity
223
     * @param object           $sourceEntityInstance the source entity instance
224
     * @param ResourceSet      $targetResourceSet    The entity set containing the entity to fetch
225
     * @param ResourceProperty $targetProperty       the metadata of the target property
226
     * @param KeyDescriptor    $keyDescriptor        The key identifying the entity to fetch
227
     *
228
     * @return Model|null Returns entity instance if found else null
229
     * @throws \Exception
230
     */
231
    public function getResourceFromRelatedResourceSet(
232
        ResourceSet $sourceResourceSet,
233
        $sourceEntityInstance,
234
        ResourceSet $targetResourceSet,
235
        ResourceProperty $targetProperty,
236
        KeyDescriptor $keyDescriptor
237
    ) {
238
        $source = $this->unpackSourceEntity($sourceEntityInstance);
239
        return $this->getReader()->getResourceFromRelatedResourceSet(
240
            $sourceResourceSet,
241
            $source,
242
            $targetResourceSet,
243
            $targetProperty,
244
            $keyDescriptor
245
        );
246
    }
247
248
    /**
249
     * Get related resource for a resource
250
     * IE: http://host/EntitySet(1L)/NavigationPropertyToSingleEntity
251
     * http://host/EntitySet?$expand=NavigationPropertyToSingleEntity.
252
     *
253
     * @param ResourceSet      $sourceResourceSet    The entity set containing the source entity
254
     * @param object           $sourceEntityInstance the source entity instance
255
     * @param ResourceSet      $targetResourceSet    The entity set containing the entity pointed to by the nav property
256
     * @param ResourceProperty $targetProperty       The navigation property to fetch
257
     *
258
     * @return Model|null The related resource if found else null
259
     * @throws \Exception
260
     */
261
    public function getRelatedResourceReference(
262
        ResourceSet $sourceResourceSet,
263
        $sourceEntityInstance,
264
        ResourceSet $targetResourceSet,
265
        ResourceProperty $targetProperty
266
    ) {
267
        $source = $this->unpackSourceEntity($sourceEntityInstance);
268
269
        $result = $this->getReader()->getRelatedResourceReference(
270
            $sourceResourceSet,
271
            $source,
272
            $targetResourceSet,
273
            $targetProperty
274
        );
275
        return $result;
276
    }
277
278
    /**
279
     * Updates a resource.
280
     *
281
     * @param ResourceSet       $sourceResourceSet    The entity set containing the source entity
282
     * @param Model|Relation    $sourceEntityInstance The source entity instance
283
     * @param KeyDescriptor     $keyDescriptor        The key identifying the entity to fetch
284
     * @param object            $data                 the New data for the entity instance
285
     * @param bool              $shouldUpdate         Should undefined values be updated or reset to default
286
     *
287
     * @return Model|null the new resource value if it is assignable or throw exception for null
288
     * @throws \Exception
289
     */
290
    public function updateResource(
291
        ResourceSet $sourceResourceSet,
292 1
        $sourceEntityInstance,
293
        KeyDescriptor $keyDescriptor,
294
        $data,
295
        $shouldUpdate = false
296
    ) {
297
        $verb = 'update';
298
        return $this->createUpdateMainWrapper($sourceResourceSet, $sourceEntityInstance, $data, $verb);
299 1
    }
300 1
    /**
301
     * Delete resource from a resource set.
302 1
     *
303
     * @param ResourceSet $sourceResourceSet
304 1
     * @param object      $sourceEntityInstance
305
     *
306 1
     * @return bool true if resources sucessfully deteled, otherwise false
307
     * @throws \Exception
308
     */
309 1
    public function deleteResource(
310
        ResourceSet $sourceResourceSet,
311
        $sourceEntityInstance
312
    ) {
313
        return $this->getWriter()->deleteResource($sourceResourceSet, $sourceEntityInstance);
314
    }
315
316
    /**
317
     * @param ResourceSet     $resourceSet          The entity set containing the entity to fetch
318 1
     * @param Model|Relation  $sourceEntityInstance The source entity instance
319
     * @param object          $data                 the New data for the entity instance
320
     *
321
     * @return Model|null                           returns the newly created model if successful,
322 1
     *                                              or null if model creation failed.
323 1
     * @throws \Exception
324 1
     */
325 1
    public function createResourceforResourceSet(
326 1
        ResourceSet $resourceSet,
327
        $sourceEntityInstance,
328 1
        $data
329
    ) {
330 1
        $verb = 'create';
331 1
        return $this->createUpdateMainWrapper($resourceSet, $sourceEntityInstance, $data, $verb);
332
    }
333
334 1
    /**
335
     * Puts an entity instance to entity set identified by a key.
336
     *
337
     * @param ResourceSet   $resourceSet   The entity set containing the entity to update
338
     * @param KeyDescriptor $keyDescriptor The key identifying the entity to update
339
     * @param $data
340
     *
341
     * @return bool|null Returns result of executing query
342
     */
343 1
    public function putResource(
344
        ResourceSet $resourceSet,
345
        KeyDescriptor $keyDescriptor,
346
        $data
347
    ) {
348 1
        // TODO: Implement putResource() method.
349 1
        return true;
350
    }
351 1
352
    /**
353 1
     * Create multiple new resources in a resource set.
354
     *
355 1
     * @param ResourceSet $sourceResourceSet The entity set containing the entity to fetch
356
     * @param object[]    $data              The new data for the entity instance
357
     *
358 1
     * @return object[] returns the newly created model if successful, or throws an exception if model creation failed
359
     * @throws InvalidOperationException
360
     * @throws \ReflectionException
361
     * @throw  \Exception
362
     */
363
    public function createBulkResourceforResourceSet(
364
        ResourceSet $sourceResourceSet,
365
        array $data
366
    ) {
367
        return $this->getBulk()->createBulkResourceForResourceSet($sourceResourceSet, $data);
368
    }
369
370 3
    /**
371
     * Updates a group of resources in a resource set.
372 3
     *
373 3
     * @param ResourceSet     $sourceResourceSet    The entity set containing the source entity
374
     * @param Model|Relation  $sourceEntityInstance The source entity instance
375 3
     * @param KeyDescriptor[] $keyDescriptor        The key identifying the entity to fetch
376
     * @param object[]        $data                 The new data for the entity instances
377
     * @param bool            $shouldUpdate         Should undefined values be updated or reset to default
378 3
     *
379 3
     * @return object[] the new resource value if it is assignable, or throw exception for null
380
     * @throw  \Exception
381
     * @throws InvalidOperationException
382
     */
383
    public function updateBulkResource(
384
        ResourceSet $sourceResourceSet,
385 3
        $sourceEntityInstance,
386
        array $keyDescriptor,
387
        array $data,
388 3
        $shouldUpdate = false
389 2
    ) {
390 2
        return $this->getBulk()
391 3
            ->updateBulkResource(
392
                $sourceResourceSet,
393
                $sourceEntityInstance,
394
                $keyDescriptor,
395
                $data,
396
                $shouldUpdate
397 3
            );
398 3
    }
399 3
400 3
    /**
401 3
     * Attaches child model to parent model.
402
     *
403 3
     * @param ResourceSet $sourceResourceSet
404 3
     * @param Model       $sourceEntityInstance
405 3
     * @param ResourceSet $targetResourceSet
406 3
     * @param Model       $targetEntityInstance
407 2
     * @param $navPropName
408 2
     *
409 2
     * @return bool
410 2
     * @throws InvalidOperationException
411 2
     */
412
    public function hookSingleModel(
413
        ResourceSet $sourceResourceSet,
414
        $sourceEntityInstance,
415 2
        ResourceSet $targetResourceSet,
416
        $targetEntityInstance,
417
        $navPropName
418 3
    ) {
419 3
        return $this->getModelHook()->hookSingleModel(
420
            $sourceResourceSet,
421 3
            $sourceEntityInstance,
422
            $targetResourceSet,
423 3
            $targetEntityInstance,
424
            $navPropName
425
        );
426 3
    }
427 3
428 3
    /**
429 3
     * Removes child model from parent model.
430
     *
431 3
     * @param ResourceSet $sourceResourceSet
432
     * @param Model       $sourceEntityInstance
433
     * @param ResourceSet $targetResourceSet
434 3
     * @param Model       $targetEntityInstance
435
     * @param $navPropName
436
     *
437
     * @return bool
438
     * @throws InvalidOperationException
439 3
     */
440
    public function unhookSingleModel(
441
        ResourceSet $sourceResourceSet,
442
        $sourceEntityInstance,
443
        ResourceSet $targetResourceSet,
444
        $targetEntityInstance,
445
        $navPropName
446
    ) {
447
        return $this->getModelHook()->unhookSingleModel(
448
            $sourceResourceSet,
449
            $sourceEntityInstance,
450
            $targetResourceSet,
451
            $targetEntityInstance,
452
            $navPropName
453
        );
454
    }
455
456
    /**
457
     * Start database transaction.
458
     * @param bool $isBulk
459
     */
460
    public function startTransaction($isBulk = false)
461
    {
462
        self::$touchList = [];
463
        self::$inBatch = true === $isBulk;
464
        DB::beginTransaction();
465
    }
466
467
    /**
468
     * Commit database transaction.
469
     */
470
    public function commitTransaction()
471
    {
472
        // fire model save again, to give Laravel app final chance to finalise anything that needs finalising after
473
        // batch processing
474
        foreach (self::$touchList as $model) {
475
            $model->save();
476
        }
477
478
        DB::commit();
479
        self::$touchList = [];
480
        self::$inBatch = false;
481
    }
482
483
    /**
484
     * Abort database transaction.
485
     */
486
    public function rollBackTransaction()
487
    {
488
        DB::rollBack();
489
        self::$touchList = [];
490
        self::$inBatch = false;
491
    }
492
493
    public static function queueModel(Model &$model)
494
    {
495
        // if we're not processing a batch, don't queue anything
496
        if (!self::$inBatch) {
497
            return;
498
        }
499
        // if we are in a batch, add to queue to process on transaction commit
500
        self::$touchList[] = $model;
501
    }
502
503
    /**
504
     * @param ResourceSet $resourceSet
505
     * @param Model|Relation|null $sourceEntityInstance
506
     * @param mixed $data
507
     * @param mixed $verb
508
     * @return Model|null
509
     * @throws InvalidOperationException
510
     * @throws ODataException
511
     */
512
    protected function createUpdateMainWrapper(ResourceSet $resourceSet, $sourceEntityInstance, $data, $verb)
513
    {
514
        /** @var Model|null $source */
515
        $source = $this->unpackSourceEntity($sourceEntityInstance);
516
517
        $result = $this->getWriter()->createUpdateCoreWrapper($resourceSet, $data, $verb, $source);
518
        if (null !== $result) {
519
            self::queueModel($result);
520
        }
521
        return $result;
522
    }
523
524
    /**
525
     * @return LaravelWriteQuery
526
     */
527
    public function getWriter()
528
    {
529
        return $this->writer;
530
    }
531
}
532