LaravelQuery::getResourceSet()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 23
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
eloc 11
c 0
b 0
f 0
dl 0
loc 23
ccs 0
cts 5
cp 0
rs 9.9
cc 1
nc 1
nop 9
crap 2

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