Passed
Pull Request — master (#171)
by Alex
04:02
created

LaravelQuery::getResourceSet()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 22
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
eloc 11
dl 0
loc 22
ccs 0
cts 15
cp 0
rs 9.9
c 0
b 0
f 0
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
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\BelongsTo;
12
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
13
use Illuminate\Database\Eloquent\Relations\HasOneOrMany;
14
use Illuminate\Database\Eloquent\Relations\Relation;
15
use Illuminate\Support\Facades\App;
16
use Illuminate\Support\Facades\DB;
17
use POData\Common\InvalidOperationException;
18
use POData\Common\ODataException;
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 implements IQueryProvider
31 5
{
32 5
    protected $expression;
33
    protected $auth;
34
    protected $reader;
35
    protected $modelHook;
36
    protected $bulk;
37
    public $queryProviderClassName;
38
    private $verbMap = [];
39
    protected $metadataProvider;
40
    protected $controllerContainer;
41
    private static $touchList = [];
42
    private static $inBatch;
43
44
    public function __construct(AuthInterface $auth = null)
45
    {
46
        /* MySQLExpressionProvider();*/
47
        $this->expression = new LaravelExpressionProvider(); //PHPExpressionProvider('expression');
48
        $this->queryProviderClassName = get_class($this);
49
        $this->auth = isset($auth) ? $auth : new NullAuthProvider();
50
        $this->reader = new LaravelReadQuery($this->auth);
51
        $this->modelHook = new LaravelHookQuery($this->auth);
52
        $this->bulk = new LaravelBulkQuery($this, $this->auth);
53
        $this->metadataProvider = new MetadataProvider(App::make('app'));
54
        $this->controllerContainer = App::make('metadataControllers');
55
        self::$touchList = [];
56
        self::$inBatch = false;
57
    }
58
59
    /**
60
     * Indicates if the QueryProvider can handle ordered paging, this means respecting order, skip, and top parameters
61
     * If the query provider can not handle ordered paging, it must return the entire result set and POData will
62
     * perform the ordering and paging.
63
     *
64
     * @return Boolean True if the query provider can handle ordered paging, false if POData should perform the paging
65
     */
66
    public function handlesOrderedPaging()
67
    {
68
        return true;
69
    }
70 3
71
    /**
72
     * Gets the expression provider used by to compile OData expressions into expression used by this query provider.
73
     *
74
     * @return \POData\Providers\Expression\IExpressionProvider
75
     */
76
    public function getExpressionProvider()
77
    {
78
        return $this->expression;
79 3
    }
80
81
    /**
82 3
     * Gets the LaravelReadQuery instance used to handle read queries (repetitious, nyet?).
83 1
     *
84 1
     * @return LaravelReadQuery
85
     */
86 3
    public function getReader()
87 3
    {
88 3
        return $this->reader;
89
    }
90 3
91
    /**
92
     * Gets the LaravelHookQuery instance used to handle hook/unhook queries (repetitious, nyet?).
93
     *
94
     * @return LaravelHookQuery
95
     */
96
    public function getModelHook()
97 1
    {
98
        return $this->modelHook;
99
    }
100 3
101 1
    /**
102 1
     * Gets the LaravelBulkQuery instance used to handle bulk queries (repetitious, nyet?).
103 3
     *
104 1
     * @return LaravelBulkQuery
105 1
     */
106
    public function getBulk()
107 3
    {
108
        return $this->bulk;
109 3
    }
110
111
    /**
112
     * Dig out local copy of POData-Laravel metadata provider.
113
     *
114
     * @return MetadataProvider
115
     */
116
    public function getMetadataProvider()
117 3
    {
118 1
        return $this->metadataProvider;
119 1
    }
120 1
121 1
    /**
122 1
     * Dig out local copy of controller metadata mapping.
123 3
     *
124 3
     * @return MetadataControllerContainer
125
     */
126
    public function getControllerContainer()
127 3
    {
128 3
        if (null === $this->controllerContainer) {
129 3
            throw new InvalidOperationException('Controller container must not be null');
130
        }
131
        return $this->controllerContainer;
132
    }
133
134
    public function getVerbMap()
135
    {
136
        if (0 == count($this->verbMap)) {
137
            $this->verbMap['create'] = ActionVerb::CREATE();
138
            $this->verbMap['update'] = ActionVerb::UPDATE();
139
            $this->verbMap['delete'] = ActionVerb::DELETE();
140
        }
141
        return $this->verbMap;
142
    }
143
144
    /**
145
     * Gets collection of entities belongs to an entity set
146
     * IE: http://host/EntitySet
147
     *  http://host/EntitySet?$skip=10&$top=5&filter=Prop gt Value.
148
     *
149
     * @param QueryType                $queryType            Is this is a query for a count, entities,
150
     *                                                       or entities-with-count?
151
     * @param ResourceSet              $resourceSet          The entity set containing the entities to fetch
152
     * @param FilterInfo|null          $filterInfo           The $filter parameter of the OData query.  NULL if absent
153
     * @param null|InternalOrderByInfo $orderBy              sorted order if we want to get the data in some
154
     *                                                       specific order
155
     * @param int|null                 $top                  number of records which need to be retrieved
156
     * @param int|null                 $skip                 number of records which need to be skipped
157
     * @param SkipTokenInfo|null       $skipToken            value indicating what records to skip
158
     * @param string[]|null            $eagerLoad            array of relations to eager load
159
     * @param Model|Relation|null      $sourceEntityInstance Starting point of query
160
     *
161
     * @return QueryResult
162
     */
163
    public function getResourceSet(
164
        QueryType $queryType,
165
        ResourceSet $resourceSet,
166
        $filterInfo = null,
167
        $orderBy = null,
168
        $top = null,
169
        $skip = null,
170
        $skipToken = null,
171
        array $eagerLoad = null,
172
        $sourceEntityInstance = null
173
    ) {
174
        $source = $this->unpackSourceEntity($sourceEntityInstance);
175
        return $this->getReader()->getResourceSet(
176
            $queryType,
177
            $resourceSet,
178
            $filterInfo,
179
            $orderBy,
180
            $top,
181
            $skip,
182
            $skipToken,
183
            $eagerLoad,
184
            $source
0 ignored issues
show
Bug introduced by
It seems like $source can also be of type object[]; however, parameter $sourceEntityInstance of AlgoWeb\PODataLaravel\Qu...Query::getResourceSet() does only seem to accept null|Illuminate\Database...uent\Relations\Relation, 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 ignore-type  annotation

184
            /** @scrutinizer ignore-type */ $source
Loading history...
185
        );
186
    }
187
    /**
188
     * Gets an entity instance from an entity set identified by a key
189
     * IE: http://host/EntitySet(1L)
190
     * http://host/EntitySet(KeyA=2L,KeyB='someValue').
191
     *
192
     * @param ResourceSet        $resourceSet   The entity set containing the entity to fetch
193
     * @param KeyDescriptor|null $keyDescriptor The key identifying the entity to fetch
194
     * @param string[]|null      $eagerLoad     array of relations to eager load
195
     *
196
     * @return Model|null Returns entity instance if found else null
197
     */
198
    public function getResourceFromResourceSet(
199 3
        ResourceSet $resourceSet,
200
        KeyDescriptor $keyDescriptor = null,
201
        array $eagerLoad = null
202
    ) {
203
        return $this->getReader()->getResourceFromResourceSet($resourceSet, $keyDescriptor, $eagerLoad);
204
    }
205
206
    /**
207
     * Get related resource set for a resource
208
     * IE: http://host/EntitySet(1L)/NavigationPropertyToCollection
209
     * http://host/EntitySet?$expand=NavigationPropertyToCollection.
210 3
     *
211 3
     * @param QueryType          $queryType            Is this is a query for a count, entities, or entities-with-count
212
     * @param ResourceSet        $sourceResourceSet    The entity set containing the source entity
213 3
     * @param object             $sourceEntityInstance The source entity instance
214 3
     * @param ResourceSet        $targetResourceSet    The resource set pointed to by the navigation property
215 3
     * @param ResourceProperty   $targetProperty       The navigation property to retrieve
216 3
     * @param FilterInfo|null    $filter               The $filter parameter of the OData query.  NULL if none specified
217 3
     * @param mixed|null         $orderBy              sorted order if we want to get the data in some specific order
218 3
     * @param int|null           $top                  number of records which need to be retrieved
219 3
     * @param int|null           $skip                 number of records which need to be skipped
220
     * @param SkipTokenInfo|null $skipToken            value indicating what records to skip
221 3
     *
222
     * @return QueryResult
223
     */
224
    public function getRelatedResourceSet(
225
        QueryType $queryType,
226
        ResourceSet $sourceResourceSet,
227
        $sourceEntityInstance,
228
        ResourceSet $targetResourceSet,
229
        ResourceProperty $targetProperty,
230
        FilterInfo $filter = null,
231
        $orderBy = null,
232
        $top = null,
233
        $skip = null,
234
        $skipToken = null
235
    ) {
236
        $source = $this->unpackSourceEntity($sourceEntityInstance);
237
        return $this->getReader()->getRelatedResourceSet(
238
            $queryType,
239
            $sourceResourceSet,
240
            $source,
241
            $targetResourceSet,
242
            $targetProperty,
243
            $filter,
244
            $orderBy,
245
            $top,
246
            $skip,
247
            $skipToken
248
        );
249
    }
250
251
    /**
252
     * Gets a related entity instance from an entity set identified by a key
253
     * IE: http://host/EntitySet(1L)/NavigationPropertyToCollection(33).
254
     *
255
     * @param ResourceSet      $sourceResourceSet    The entity set containing the source entity
256
     * @param object           $sourceEntityInstance the source entity instance
257
     * @param ResourceSet      $targetResourceSet    The entity set containing the entity to fetch
258
     * @param ResourceProperty $targetProperty       the metadata of the target property
259
     * @param KeyDescriptor    $keyDescriptor        The key identifying the entity to fetch
260
     *
261
     * @return Model|null Returns entity instance if found else null
262
     */
263
    public function getResourceFromRelatedResourceSet(
264
        ResourceSet $sourceResourceSet,
265
        $sourceEntityInstance,
266
        ResourceSet $targetResourceSet,
267
        ResourceProperty $targetProperty,
268
        KeyDescriptor $keyDescriptor
269
    ) {
270
        $source = $this->unpackSourceEntity($sourceEntityInstance);
271
        return $this->getReader()->getResourceFromRelatedResourceSet(
272
            $sourceResourceSet,
273
            $source,
274
            $targetResourceSet,
275
            $targetProperty,
276
            $keyDescriptor
277
        );
278
    }
279
280
    /**
281
     * Get related resource for a resource
282
     * IE: http://host/EntitySet(1L)/NavigationPropertyToSingleEntity
283
     * http://host/EntitySet?$expand=NavigationPropertyToSingleEntity.
284
     *
285
     * @param ResourceSet      $sourceResourceSet    The entity set containing the source entity
286
     * @param object           $sourceEntityInstance the source entity instance
287
     * @param ResourceSet      $targetResourceSet    The entity set containing the entity pointed to by the nav property
288
     * @param ResourceProperty $targetProperty       The navigation property to fetch
289
     *
290
     * @return Model|null The related resource if found else null
291
     */
292 1
    public function getRelatedResourceReference(
293
        ResourceSet $sourceResourceSet,
294
        $sourceEntityInstance,
295
        ResourceSet $targetResourceSet,
296
        ResourceProperty $targetProperty
297
    ) {
298
        $source = $this->unpackSourceEntity($sourceEntityInstance);
299 1
300 1
        $result = $this->getReader()->getRelatedResourceReference(
301
            $sourceResourceSet,
302 1
            $source,
303
            $targetResourceSet,
304 1
            $targetProperty
305
        );
306 1
        return $result;
307
    }
308
309 1
    /**
310
     * Updates a resource.
311
     *
312
     * @param ResourceSet   $sourceResourceSet    The entity set containing the source entity
313
     * @param object        $sourceEntityInstance The source entity instance
314
     * @param KeyDescriptor $keyDescriptor        The key identifying the entity to fetch
315
     * @param object        $data                 the New data for the entity instance
316
     * @param bool          $shouldUpdate         Should undefined values be updated or reset to default
317
     *
318 1
     * @return Model|null the new resource value if it is assignable or throw exception for null
319
     */
320
    public function updateResource(
321
        ResourceSet $sourceResourceSet,
322 1
        $sourceEntityInstance,
323 1
        KeyDescriptor $keyDescriptor,
324 1
        $data,
325 1
        $shouldUpdate = false
326 1
    ) {
327
        $verb = 'update';
328 1
        return $this->createUpdateMainWrapper($sourceResourceSet, $sourceEntityInstance, $data, $verb);
329
    }
330 1
    /**
331 1
     * Delete resource from a resource set.
332
     *
333
     * @param ResourceSet $sourceResourceSet
334 1
     * @param object      $sourceEntityInstance
335
     *
336
     * return bool true if resources sucessfully deteled, otherwise false
337
     */
338
    public function deleteResource(
339
        ResourceSet $sourceResourceSet,
340
        $sourceEntityInstance
341
    ) {
342
        $source = $this->unpackSourceEntity($sourceEntityInstance);
343 1
344
        $verb = 'delete';
345
        if (!($source instanceof Model)) {
346
            throw new InvalidArgumentException('Source entity must be an Eloquent model.');
347
        }
348 1
349 1
        $class = $sourceResourceSet->getResourceType()->getInstanceType()->getName();
350
        $id = $source->getKey();
351 1
        $name = $source->getKeyName();
352
        $data = [$name => $id];
353 1
354
        $data = $this->createUpdateDeleteCore($source, $data, $class, $verb);
355 1
356
        $success = isset($data['id']);
357
        if ($success) {
358 1
            return true;
359
        }
360
        throw new ODataException('Target model not successfully deleted', 422);
361
    }
362
    /**
363
     * @param ResourceSet $resourceSet          The entity set containing the entity to fetch
364
     * @param object      $sourceEntityInstance The source entity instance
365
     * @param object      $data                 the New data for the entity instance
366
     *
367
     * @returns Model|null                      returns the newly created model if successful,
368
     *                                          or null if model creation failed.
369
     */
370 3
    public function createResourceforResourceSet(
371
        ResourceSet $resourceSet,
372 3
        $sourceEntityInstance,
373 3
        $data
374
    ) {
375 3
        $verb = 'create';
376
        return $this->createUpdateMainWrapper($resourceSet, $sourceEntityInstance, $data, $verb);
377
    }
378 3
379 3
    /**
380
     * @param $sourceEntityInstance
381
     * @param $data
382
     * @param $class
383
     * @param string $verb
384
     *
385 3
     * @throws ODataException
386
     * @throws InvalidOperationException
387
     * @return array|mixed
388 3
     */
389 2
    private function createUpdateDeleteCore($sourceEntityInstance, $data, $class, $verb)
390 2
    {
391 3
        $raw = App::make('metadataControllers');
392
        $map = $raw->getMetadata();
393
394
        if (!array_key_exists($class, $map)) {
395
            throw new \POData\Common\InvalidOperationException('Controller mapping missing for class ' . $class . '.');
396
        }
397 3
        $goal = $raw->getMapping($class, $verb);
398 3
        if (null == $goal) {
399 3
            throw new \POData\Common\InvalidOperationException(
400 3
                'Controller mapping missing for ' . $verb . ' verb on class ' . $class . '.'
401 3
            );
402
        }
403 3
404 3
        if (null === $data) {
405 3
            $msg = 'Data must not be null';
406 3
            throw new InvalidOperationException($msg);
407 2
        }
408 2
        if (is_object($data)) {
409 2
            $arrayData = (array) $data;
410 2
        } else {
411 2
            $arrayData = $data;
412
        }
413
        if (!is_array($arrayData)) {
414
            throw \POData\Common\ODataException::createPreConditionFailedError(
415 2
                'Data not resolvable to key-value array.'
416
            );
417
        }
418 3
419 3
        $controlClass = $goal['controller'];
420
        $method = $goal['method'];
421 3
        $paramList = $goal['parameters'];
422
        $controller = App::make($controlClass);
423 3
        $parms = $this->createUpdateDeleteProcessInput($arrayData, $paramList, $sourceEntityInstance);
424
        unset($data);
425
426 3
        $result = call_user_func_array(array($controller, $method), $parms);
427 3
428 3
        return $this->createUpdateDeleteProcessOutput($result);
429 3
    }
430
431 3
    /**
432
     * Puts an entity instance to entity set identified by a key.
433
     *
434 3
     * @param ResourceSet   $resourceSet   The entity set containing the entity to update
435
     * @param KeyDescriptor $keyDescriptor The key identifying the entity to update
436
     * @param $data
437
     *
438
     * @return bool|null Returns result of executing query
439 3
     */
440
    public function putResource(
441
        ResourceSet $resourceSet,
442
        KeyDescriptor $keyDescriptor,
443
        $data
444
    ) {
445
        // TODO: Implement putResource() method.
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
446
        return true;
447
    }
448
449
    /**
450
     * @param ResourceSet $sourceResourceSet
451
     * @param $data
452
     * @param                            $verb
453
     * @param  Model|null                $source
454
     * @throws InvalidOperationException
455
     * @throws ODataException
456
     * @return Model|null
457
     */
458
    protected function createUpdateCoreWrapper(ResourceSet $sourceResourceSet, $data, $verb, Model $source = null)
459
    {
460
        $lastWord = 'update' == $verb ? 'updated' : 'created';
461
        $class = $sourceResourceSet->getResourceType()->getInstanceType()->getName();
462
        if (!$this->auth->canAuth($this->getVerbMap()[$verb], $class, $source)) {
463
            throw new ODataException('Access denied', 403);
464
        }
465
466
        $payload = $this->createUpdateDeleteCore($source, $data, $class, $verb);
467
468
        $success = isset($payload['id']);
469
470
        if ($success) {
471
            try {
472
                return $class::findOrFail($payload['id']);
473
            } catch (\Exception $e) {
474
                throw new ODataException($e->getMessage(), 500);
475
            }
476
        }
477
        throw new ODataException('Target model not successfully ' . $lastWord, 422);
478
    }
479
480
    /**
481
     * @param $data
482
     * @param $paramList
483
     * @param  Model|null $sourceEntityInstance
484
     * @return array
485
     */
486
    protected function createUpdateDeleteProcessInput($data, $paramList, Model $sourceEntityInstance = null)
487
    {
488
        $parms = [];
489
490
        foreach ($paramList as $spec) {
491
            $varType = isset($spec['type']) ? $spec['type'] : null;
492
            $varName = $spec['name'];
493
            if (null == $varType) {
494
                $parms[] = ('id' == $varName) ? $sourceEntityInstance->getKey() : $sourceEntityInstance->$varName;
0 ignored issues
show
Bug introduced by
The method getKey() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

494
                $parms[] = ('id' == $varName) ? $sourceEntityInstance->/** @scrutinizer ignore-call */ getKey() : $sourceEntityInstance->$varName;

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
495
                continue;
496
            }
497
            // TODO: Give this smarts and actively pick up instantiation details
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
498
            $var = new $varType();
499
            if ($spec['isRequest']) {
500
                $var->setMethod('POST');
501
                $var->request = new \Symfony\Component\HttpFoundation\ParameterBag($data);
502
            }
503
            $parms[] = $var;
504
        }
505
        return $parms;
506
    }
507
508
    /**
509
     * @param $result
510
     * @throws ODataException
511
     * @return array|mixed
512
     */
513
    private function createUpdateDeleteProcessOutput($result)
514
    {
515
        if (!($result instanceof \Illuminate\Http\JsonResponse)) {
516
            throw ODataException::createInternalServerError('Controller response not well-formed json.');
517
        }
518
        $outData = $result->getData();
519
        if (is_object($outData)) {
520
            $outData = (array) $outData;
521
        }
522
523
        if (!is_array($outData)) {
524
            throw ODataException::createInternalServerError('Controller response does not have an array.');
525
        }
526
        if (!(key_exists('id', $outData) && key_exists('status', $outData) && key_exists('errors', $outData))) {
527
            throw ODataException::createInternalServerError(
528
                'Controller response array missing at least one of id, status and/or errors fields.'
529
            );
530
        }
531
        return $outData;
532
    }
533
534
    /**
535
     * @param $sourceEntityInstance
536
     * @return mixed|null|\object[]
537
     */
538
    private function unpackSourceEntity($sourceEntityInstance)
539
    {
540
        if ($sourceEntityInstance instanceof QueryResult) {
541
            $source = $sourceEntityInstance->results;
542
            $source = (is_array($source)) ? $source[0] : $source;
543
            return $source;
544
        }
545
        return $sourceEntityInstance;
546
    }
547
548
    /**
549
     * Create multiple new resources in a resource set.
550
     *
551
     * @param ResourceSet $sourceResourceSet The entity set containing the entity to fetch
552
     * @param object[]    $data              The new data for the entity instance
553
     *
554
     * @return object[] returns the newly created model if successful, or throws an exception if model creation failed
555
     * @throw  \Exception
556
     */
557
    public function createBulkResourceforResourceSet(
558
        ResourceSet $sourceResourceSet,
559
        array $data
560
    ) {
561
        return $this->getBulk()->createBulkResourceForResourceSet($sourceResourceSet, $data);
562
    }
563
564
    /**
565
     * Updates a group of resources in a resource set.
566
     *
567
     * @param ResourceSet     $sourceResourceSet    The entity set containing the source entity
568
     * @param object          $sourceEntityInstance The source entity instance
569
     * @param KeyDescriptor[] $keyDescriptor        The key identifying the entity to fetch
570
     * @param object[]        $data                 The new data for the entity instances
571
     * @param bool            $shouldUpdate         Should undefined values be updated or reset to default
572
     *
573
     * @return object[] the new resource value if it is assignable, or throw exception for null
574
     * @throw  \Exception
575
     */
576
    public function updateBulkResource(
577
        ResourceSet $sourceResourceSet,
578
        $sourceEntityInstance,
579
        array $keyDescriptor,
580
        array $data,
581
        $shouldUpdate = false
582
    ) {
583
        return $this->getBulk()
584
            ->updateBulkResource(
585
                $sourceResourceSet,
586
                $sourceEntityInstance,
587
                $keyDescriptor,
588
                $data,
589
                $shouldUpdate
590
            );
591
    }
592
593
    /**
594
     * Attaches child model to parent model.
595
     *
596
     * @param ResourceSet $sourceResourceSet
597
     * @param object      $sourceEntityInstance
598
     * @param ResourceSet $targetResourceSet
599
     * @param object      $targetEntityInstance
600
     * @param $navPropName
601
     *
602
     * @return bool
603
     */
604
    public function hookSingleModel(
605
        ResourceSet $sourceResourceSet,
606
        $sourceEntityInstance,
607
        ResourceSet $targetResourceSet,
608
        $targetEntityInstance,
609
        $navPropName
610
    ) {
611
        return $this->getModelHook()->hookSingleModel(
612
            $sourceResourceSet,
613
            $sourceEntityInstance,
614
            $targetResourceSet,
615
            $targetEntityInstance,
616
            $navPropName
617
        );
618
    }
619
620
    /**
621
     * Removes child model from parent model.
622
     *
623
     * @param ResourceSet $sourceResourceSet
624
     * @param object      $sourceEntityInstance
625
     * @param ResourceSet $targetResourceSet
626
     * @param object      $targetEntityInstance
627
     * @param $navPropName
628
     *
629
     * @return bool
630
     */
631
    public function unhookSingleModel(
632
        ResourceSet $sourceResourceSet,
633
        $sourceEntityInstance,
634
        ResourceSet $targetResourceSet,
635
        $targetEntityInstance,
636
        $navPropName
637
    ) {
638
        return $this->getModelHook()->unhookSingleModel(
639
            $sourceResourceSet,
640
            $sourceEntityInstance,
641
            $targetResourceSet,
642
            $targetEntityInstance,
643
            $navPropName
644
        );
645
    }
646
647
    /**
648
     * Start database transaction.
649
     */
650
    public function startTransaction($isBulk = false)
651
    {
652
        self::$touchList = [];
653
        self::$inBatch = true === $isBulk;
654
        DB::beginTransaction();
655
    }
656
657
    /**
658
     * Commit database transaction.
659
     */
660
    public function commitTransaction()
661
    {
662
        // fire model save again, to give Laravel app final chance to finalise anything that needs finalising after
663
        // batch processing
664
        foreach (self::$touchList as $model) {
665
            $model->save();
666
        }
667
668
        DB::commit();
669
        self::$touchList = [];
670
        self::$inBatch = false;
671
    }
672
673
    /**
674
     * Abort database transaction.
675
     */
676
    public function rollBackTransaction()
677
    {
678
        DB::rollBack();
679
        self::$touchList = [];
680
        self::$inBatch = false;
681
    }
682
683
    public static function queueModel(Model &$model)
684
    {
685
        // if we're not processing a batch, don't queue anything
686
        if (!self::$inBatch) {
687
            return;
688
        }
689
        // if we are in a batch, add to queue to process on transaction commit
690
        self::$touchList[] = $model;
691
    }
692
693
    protected function createUpdateMainWrapper(ResourceSet $resourceSet, $sourceEntityInstance, $data, $verb)
694
    {
695
        $source = $this->unpackSourceEntity($sourceEntityInstance);
696
697
        $result = $this->createUpdateCoreWrapper($resourceSet, $data, $verb, $source);
0 ignored issues
show
Bug introduced by
It seems like $source can also be of type object[]; however, parameter $source of AlgoWeb\PODataLaravel\Qu...eateUpdateCoreWrapper() does only seem to accept null|Illuminate\Database\Eloquent\Model, 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 ignore-type  annotation

697
        $result = $this->createUpdateCoreWrapper($resourceSet, $data, $verb, /** @scrutinizer ignore-type */ $source);
Loading history...
698
        self::queueModel($result);
699
        return $result;
700
    }
701
}
702