LaravelHookQuery::hookSingleModel()   A
last analyzed

Complexity

Conditions 4
Paths 4

Size

Total Lines 23
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 11
c 0
b 0
f 0
dl 0
loc 23
rs 9.9
cc 4
nc 4
nop 5
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\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 POData\Common\InvalidOperationException;
17
use POData\Providers\Metadata\ResourceSet;
18
19
class LaravelHookQuery extends LaravelBaseQuery
20
{
21
    /**
22
     * Attaches child model to parent model.
23
     *
24
     * @param ResourceSet $sourceResourceSet
25
     * @param Model       $sourceEntityInstance
26
     * @param ResourceSet $targetResourceSet
27
     * @param Model       $targetEntityInstance
28
     * @param string      $navPropName
29
     *
30
     * @throws InvalidOperationException
31
     * @return bool
32
     */
33
    public function hookSingleModel(
34
        ResourceSet $sourceResourceSet,
35
        $sourceEntityInstance,
36
        ResourceSet $targetResourceSet,
37
        $targetEntityInstance,
38
        $navPropName
39
    ) {
40
        $relation = $this->isModelHookInputsOk($sourceEntityInstance, $targetEntityInstance, $navPropName);
41
42
        // in case the fake 'PrimaryKey' attribute got set inbound for a polymorphic-affected model, flatten it now
43
        unset($targetEntityInstance->PrimaryKey);
44
45
        if ($relation instanceof BelongsTo) {
46
            $relation->associate($targetEntityInstance);
47
        } elseif ($relation instanceof BelongsToMany) {
48
            $relation->attach($targetEntityInstance);
49
        } elseif ($relation instanceof HasOneOrMany) {
50
            $relation->save($targetEntityInstance);
51
        }
52
53
        LaravelQuery::queueModel($sourceEntityInstance);
54
        LaravelQuery::queueModel($targetEntityInstance);
55
        return true;
56
    }
57
58
    /**
59
     * Removes child model from parent model.
60
     *
61
     * @param ResourceSet $sourceResourceSet
62
     * @param Model       $sourceEntityInstance
63
     * @param ResourceSet $targetResourceSet
64
     * @param Model       $targetEntityInstance
65
     * @param string      $navPropName
66
     *
67
     * @throws InvalidOperationException
68
     * @return bool
69
     */
70
    public function unhookSingleModel(
71
        ResourceSet $sourceResourceSet,
72
        $sourceEntityInstance,
73
        ResourceSet $targetResourceSet,
74
        $targetEntityInstance,
75
        $navPropName
76
    ) {
77
        $relation = $this->isModelHookInputsOk($sourceEntityInstance, $targetEntityInstance, $navPropName);
78
79
        // in case the fake 'PrimaryKey' attribute got set inbound for a polymorphic-affected model, flatten it now
80
        unset($targetEntityInstance->PrimaryKey);
81
82
        $changed = false;
83
84
        if ($relation instanceof BelongsTo) {
85
            $relation->dissociate();
86
            $changed = true;
87
        } elseif ($relation instanceof BelongsToMany) {
88
            $relation->detach($targetEntityInstance);
89
            $changed = true;
90
        } elseif ($relation instanceof HasOneOrMany) {
91
            $keyName = $relation->getForeignKeyName();
92
            $relation->update([$keyName => null]);
93
        }
94
        if ($changed) {
95
            LaravelQuery::queueModel($sourceEntityInstance);
96
            LaravelQuery::queueModel($targetEntityInstance);
97
        }
98
        return true;
99
    }
100
101
    /**
102
     * @param Model $sourceEntityInstance
103
     * @param Model $targetEntityInstance
104
     * @param string $navPropName
105
     * @throws \InvalidArgumentException
106
     * @return Relation
107
     */
108
    protected function isModelHookInputsOk(
109
        Model $sourceEntityInstance,
110
        Model $targetEntityInstance,
111
        string $navPropName
112
    ) {
113
        $relation = $sourceEntityInstance->{$navPropName}();
114
        if (!$relation instanceof Relation) {
115
            $msg = 'Navigation property must be an Eloquent relation';
116
            throw new \InvalidArgumentException($msg);
117
        }
118
        $targType = $relation->getRelated();
119
        if (!$targetEntityInstance instanceof $targType) {
120
            $msg = 'Target instance must be of type compatible with relation declared in method ' . $navPropName;
121
            throw new \InvalidArgumentException($msg);
122
        }
123
        return $relation;
124
    }
125
}
126