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

LaravelQuery::getResourceSet()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 23
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1.064

Importance

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

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
        return $this->getWriter()->updateResource(
298
            $sourceResourceSet,
299 1
            $sourceEntityInstance,
300 1
            $keyDescriptor,
301
            $data,
302 1
            $shouldUpdate
303
        );
304 1
    }
305
306 1
    /**
307
     * Delete resource from a resource set.
308
     *
309 1
     * @param ResourceSet $sourceResourceSet
310
     * @param object      $sourceEntityInstance
311
     *
312
     * @return bool true if resources sucessfully deteled, otherwise false
313
     * @throws \Exception
314
     */
315
    public function deleteResource(
316
        ResourceSet $sourceResourceSet,
317
        $sourceEntityInstance
318 1
    ) {
319
        return $this->getWriter()->deleteResource($sourceResourceSet, $sourceEntityInstance);
320
    }
321
322 1
    /**
323 1
     * @param ResourceSet     $resourceSet          The entity set containing the entity to fetch
324 1
     * @param Model|Relation  $sourceEntityInstance The source entity instance
325 1
     * @param object          $data                 the New data for the entity instance
326 1
     *
327
     * @return Model|null                           returns the newly created model if successful,
328 1
     *                                              or null if model creation failed.
329
     * @throws \Exception
330 1
     */
331 1
    public function createResourceforResourceSet(
332
        ResourceSet $resourceSet,
333
        $sourceEntityInstance,
334 1
        $data
335
    ) {
336
        return $this->getWriter()->createResourceforResourceSet($resourceSet, $sourceEntityInstance, $data);
337
    }
338
339
    /**
340
     * Puts an entity instance to entity set identified by a key.
341
     *
342
     * @param ResourceSet   $resourceSet   The entity set containing the entity to update
343 1
     * @param KeyDescriptor $keyDescriptor The key identifying the entity to update
344
     * @param $data
345
     *
346
     * @return bool|null Returns result of executing query
347
     */
348 1
    public function putResource(
349 1
        ResourceSet $resourceSet,
350
        KeyDescriptor $keyDescriptor,
351 1
        $data
352
    ) {
353 1
        return $this->getWriter()->putResource($resourceSet, $keyDescriptor, $data);
354
    }
355 1
356
    /**
357
     * Create multiple new resources in a resource set.
358 1
     *
359
     * @param ResourceSet $sourceResourceSet The entity set containing the entity to fetch
360
     * @param object[]    $data              The new data for the entity instance
361
     *
362
     * @return object[] returns the newly created model if successful, or throws an exception if model creation failed
363
     * @throws InvalidOperationException
364
     * @throws \ReflectionException
365
     * @throw  \Exception
366
     */
367
    public function createBulkResourceforResourceSet(
368
        ResourceSet $sourceResourceSet,
369
        array $data
370 3
    ) {
371
        return $this->getBulk()->createBulkResourceForResourceSet($sourceResourceSet, $data);
372 3
    }
373 3
374
    /**
375 3
     * Updates a group of resources in a resource set.
376
     *
377
     * @param ResourceSet     $sourceResourceSet    The entity set containing the source entity
378 3
     * @param Model|Relation  $sourceEntityInstance The source entity instance
379 3
     * @param KeyDescriptor[] $keyDescriptor        The key identifying the entity to fetch
380
     * @param object[]        $data                 The new data for the entity instances
381
     * @param bool            $shouldUpdate         Should undefined values be updated or reset to default
382
     *
383
     * @return object[] the new resource value if it is assignable, or throw exception for null
384
     * @throw  \Exception
385 3
     * @throws InvalidOperationException
386
     */
387
    public function updateBulkResource(
388 3
        ResourceSet $sourceResourceSet,
389 2
        $sourceEntityInstance,
390 2
        array $keyDescriptor,
391 3
        array $data,
392
        $shouldUpdate = false
393
    ) {
394
        return $this->getBulk()
395
            ->updateBulkResource(
396
                $sourceResourceSet,
397 3
                $sourceEntityInstance,
398 3
                $keyDescriptor,
399 3
                $data,
400 3
                $shouldUpdate
401 3
            );
402
    }
403 3
404 3
    /**
405 3
     * Attaches child model to parent model.
406 3
     *
407 2
     * @param ResourceSet $sourceResourceSet
408 2
     * @param Model       $sourceEntityInstance
409 2
     * @param ResourceSet $targetResourceSet
410 2
     * @param Model       $targetEntityInstance
411 2
     * @param $navPropName
412
     *
413
     * @return bool
414
     * @throws InvalidOperationException
415 2
     */
416
    public function hookSingleModel(
417
        ResourceSet $sourceResourceSet,
418 3
        $sourceEntityInstance,
419 3
        ResourceSet $targetResourceSet,
420
        $targetEntityInstance,
421 3
        $navPropName
422
    ) {
423 3
        return $this->getModelHook()->hookSingleModel(
424
            $sourceResourceSet,
425
            $sourceEntityInstance,
426 3
            $targetResourceSet,
427 3
            $targetEntityInstance,
428 3
            $navPropName
429 3
        );
430
    }
431 3
432
    /**
433
     * Removes child model from parent model.
434 3
     *
435
     * @param ResourceSet $sourceResourceSet
436
     * @param Model       $sourceEntityInstance
437
     * @param ResourceSet $targetResourceSet
438
     * @param Model       $targetEntityInstance
439 3
     * @param $navPropName
440
     *
441
     * @return bool
442
     * @throws InvalidOperationException
443
     */
444
    public function unhookSingleModel(
445
        ResourceSet $sourceResourceSet,
446
        $sourceEntityInstance,
447
        ResourceSet $targetResourceSet,
448
        $targetEntityInstance,
449
        $navPropName
450
    ) {
451
        return $this->getModelHook()->unhookSingleModel(
452
            $sourceResourceSet,
453
            $sourceEntityInstance,
454
            $targetResourceSet,
455
            $targetEntityInstance,
456
            $navPropName
457
        );
458
    }
459
460
    /**
461
     * Start database transaction.
462
     * @param bool $isBulk
463
     */
464
    public function startTransaction($isBulk = false)
465
    {
466
        self::$touchList = [];
467
        self::$inBatch = true === $isBulk;
468
        DB::beginTransaction();
469
    }
470
471
    /**
472
     * Commit database transaction.
473
     */
474
    public function commitTransaction()
475
    {
476
        // fire model save again, to give Laravel app final chance to finalise anything that needs finalising after
477
        // batch processing
478
        foreach (self::$touchList as $model) {
479
            $model->save();
480
        }
481
482
        DB::commit();
483
        self::$touchList = [];
484
        self::$inBatch = false;
485
    }
486
487
    /**
488
     * Abort database transaction.
489
     */
490
    public function rollBackTransaction()
491
    {
492
        DB::rollBack();
493
        self::$touchList = [];
494
        self::$inBatch = false;
495
    }
496
497
    public static function queueModel(Model &$model)
498
    {
499
        // if we're not processing a batch, don't queue anything
500
        if (!self::$inBatch) {
501
            return;
502
        }
503
        // if we are in a batch, add to queue to process on transaction commit
504
        self::$touchList[] = $model;
505
    }
506
507
    /**
508
     * @return LaravelWriteQuery
509
     */
510
    public function getWriter()
511
    {
512
        return $this->writer;
513
    }
514
}
515