Passed
Pull Request — master (#221)
by Christopher
05:11
created

AssociationStubFactory::handleBelongsTo()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 9
c 2
b 0
f 0
dl 0
loc 11
rs 9.9666
cc 1
nc 1
nop 3
1
<?php
2
declare(strict_types=1);
3
4
namespace AlgoWeb\PODataLaravel\Models\ObjectMap\Entities\Associations;
5
6
use Illuminate\Database\Eloquent\Model;
7
use Illuminate\Database\Eloquent\Relations\BelongsTo;
8
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
9
use Illuminate\Database\Eloquent\Relations\HasMany;
10
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
11
use Illuminate\Database\Eloquent\Relations\HasOne;
12
use Illuminate\Database\Eloquent\Relations\MorphMany;
13
use Illuminate\Database\Eloquent\Relations\MorphOne;
14
use Illuminate\Database\Eloquent\Relations\MorphTo;
15
use Illuminate\Database\Eloquent\Relations\MorphToMany;
16
use Illuminate\Database\Eloquent\Relations\Relation;
17
18
abstract class AssociationStubFactory
19
{
20
    /**
21
     * @param Model $parent
22
     * @param string $name
23
     * @param Relation $relation
24
     * @return AssociationStubBase
25
     */
26
    public static function associationStubFromRelation(Model $parent, string $name): AssociationStubBase
27
    {
28
        $relation = $parent->{$name}();
29
        $handler = self::getHandlerMethod($relation);
30
        /**
31
         * @var AssociationStubBase $stub
32
         */
33
        $stub = self::{'handle' . $handler}($name, $relation);
34
        $stub->setBaseType(get_class($parent));
35
        return $stub;
36
37
    }
38
    private static function getHandlerMethod(Relation $relation):string
39
    {
40
        $methods = [];
41
        $methods[$relation instanceof BelongsTo] = 'BelongsTo'; //DONE
42
        $methods[$relation instanceof MorphTo] = 'MorphTo'; //DONE
43
        $methods[$relation instanceof BelongsToMany] = 'BelongsToMany'; //DONE
44
        $methods[$relation instanceof MorphToMany] = 'MorphToMany'; // DONE
45
        $methods[$relation instanceof HasOne] = 'HasOne';
46
        $methods[$relation instanceof HasMany] = 'HasMany';
47
        $methods[$relation instanceof HasManyThrough] = 'HasManyThrough'; //DONE
48
        $methods[$relation instanceof MorphMany] = 'MorphMany';
49
        $methods[$relation instanceof MorphOne] = 'MorphOne';
50
51
        return $methods[true];
52
    }
53
54
    /**
55
     * @param  string              $name
56
     * @param  Relation            $relation
57
     * @param  string              $cacheKey
58
     * @return AssociationStubMonomorphic
59
     */
60
    protected static function handleBelongsTo(string $name, Relation $relation, $cacheKey = 'BelongsTo'): AssociationStubMonomorphic
61
    {
62
        $stub = new AssociationStubMonomorphic();
63
        $keyChain = self::getKeyChain($relation, $cacheKey);
64
        $stub->setRelationName($name);
65
        $stub->setThroughFieldChain($keyChain);
66
        $stub->setKeyField($keyChain[0]);
67
        $stub->setForeignField($keyChain[1]);
68
        $stub->setTargType(get_class($relation->getRelated()));
69
        $stub->setMultiplicity(AssociationStubRelationType::ONE());
70
        return $stub;
71
    }
72
73
    /**
74
     * @param  string              $name
75
     * @param  Relation            $relation
76
     * @param  string              $cacheKey
77
     * @return AssociationStubPolymorphic
78
     */
79
    protected static function handleMorphTo(string $name, Relation $relation, $cacheKey = 'MorphTo') : AssociationStubPolymorphic
80
    {
81
        $stub = new AssociationStubPolymorphic();
82
        $keyChain = self::getKeyChain($relation, $cacheKey);
83
        $stub->setRelationName($name);
84
        $stub->setThroughFieldChain($keyChain);
85
        $stub->setKeyField($keyChain[2] ?: $relation->getRelated()->getKeyName());
86
        $stub->setForeignField($keyChain[2]);
87
        $stub->setMultiplicity(AssociationStubRelationType::ONE());
88
        $stub->setTargType(null);
89
        $stub->setMorphType($keyChain[1]);
90
        return $stub;
91
    }
92
93
94
    /**
95
     * @param  string              $name
96
     * @param  Relation            $relation
97
     * @param  string              $cacheKey
98
     * @return AssociationStubMonomorphic
99
     */
100
    protected static function handleBelongsToMany(string $name, Relation $relation, $cacheKey = 'BelongsToMany'): AssociationStubMonomorphic
101
    {
102
        $stub = new AssociationStubMonomorphic();
103
        $keyChain = self::getKeyChain($relation, $cacheKey);
104
        $stub->setRelationName($name);
105
        $stub->setThroughFieldChain($keyChain);
106
        $stub->setMultiplicity(AssociationStubRelationType::MANY());
107
        $stub->setTargType(get_class($relation->getRelated()));
108
        $stub->setKeyField($keyChain[2]);
109
        $stub->setForeignField($keyChain[1]);
110
        return $stub;
111
    }
112
    /**
113
     * @param  string              $name
114
     * @param  Relation            $relation
115
     * @param  string              $cacheKey
116
     * @return AssociationStubMonomorphic
117
     */
118
    protected static function handleHasManyThrough(string $name, Relation $relation, $cacheKey = 'HasManyThrough'):AssociationStubMonomorphic
119
    {
120
        $keyChain = self::getKeyChain($relation, $cacheKey);
121
        $stub = new AssociationStubMonomorphic();
122
        $stub->setRelationName($name);
123
        $stub->setThroughFieldChain($keyChain);
124
        $stub->setMultiplicity(AssociationStubRelationType::MANY());
125
        $stub->setTargType(get_class($relation->getRelated()));
126
        $stub->setThroughField($keyChain[1]);
127
        $stub->setKeyField($keyChain[3]);
128
        $stub->setForeignField($keyChain[2]);
129
        return $stub;
130
    }
131
132
    /**
133
     * @param  string              $name
134
     * @param  Relation            $relation
135
     * @param  string              $cacheKey
136
     * @return AssociationStubPolymorphic
137
     */
138
    protected static function handleMorphToMany(string $name, Relation $relation, $cacheKey = 'MorphToMany'): AssociationStubBase
139
    {
140
        //return self::handleBelongsToMany($name,$relation);
141
        //TODO: investigate if this could be treated as a BelongsToMany Or more importantly a Monomorphic as we know both sides
142
        $inverseGetter = function () {
143
            return $this->inverse;
0 ignored issues
show
Bug Best Practice introduced by
The property inverse does not exist on AlgoWeb\PODataLaravel\Mo...\AssociationStubFactory. Did you maybe forget to declare it?
Loading history...
Comprehensibility Best Practice introduced by
The variable $this seems to be never defined.
Loading history...
144
        };
145
        $inverse = call_user_func($inverseGetter->bindTo($relation, MorphToMany::class));
146
        $stub = new AssociationStubPolymorphic();
147
        $keyChain = self::getKeyChain($relation, $cacheKey);
148
        $stub->setRelationName($name);
149
        $stub->setThroughFieldChain($keyChain);
150
        $stub->setKeyField($keyChain[3]);
151
        $stub->setForeignField($inverse ? null : $keyChain[1]);
152
        $stub->setMultiplicity(AssociationStubRelationType::MANY());
153
        $stub->setMorphType($keyChain[2]);
154
        $stub->setTargType($inverse ? null : get_class($relation->getRelated()));
155
        return $stub;
156
    }
157
158
    /**
159
     * @param string $name
160
     * @param Relation $relation
161
     * @param string $cacheKey
162
     * @return AssociationStubMonomorphic
163
     */
164
    protected static function handleHasOne(string $name, Relation $relation, $cacheKey = 'HasOneOrMany'): AssociationStubMonomorphic
165
    {
166
        $stub = new AssociationStubMonomorphic();
167
        $keyChain = self::getKeyChain($relation, $cacheKey);
168
        $stub->setRelationName($name);
169
        $stub->setThroughFieldChain($keyChain);
170
        $stub->setKeyField($keyChain[0]);
171
        $stub->setForeignField($keyChain[1]);
172
        $stub->setTargType(get_class($relation->getRelated()));
173
        $stub->setMultiplicity(AssociationStubRelationType::NULL_ONE());
174
        return $stub;
175
    }
176
177
    /**
178
     * @param string $name
179
     * @param Relation $relation
180
     * @param string $cacheKey
181
     * @return AssociationStubMonomorphic
182
     */
183
    protected static function handleHasMany(string $name, Relation $relation, $cacheKey = 'HasOneOrMany'): AssociationStubMonomorphic
184
    {
185
        $stub = new AssociationStubMonomorphic();
186
        $keyChain = self::getKeyChain($relation, $cacheKey);
187
        $stub->setRelationName($name);
188
        $stub->setThroughFieldChain($keyChain);
189
        $stub->setKeyField($keyChain[0]);
190
        $stub->setForeignField($keyChain[1]);
191
        $stub->setTargType(get_class($relation->getRelated()));
192
        $stub->setMultiplicity(AssociationStubRelationType::MANY());
193
        return $stub;
194
    }
195
196
    /**
197
     * @param  string                     $name
198
     * @param  Relation                   $relation
199
     * @param  string                     $cacheKey
200
     * @return AssociationStubPolymorphic
201
     */
202
    protected static function handleMorphOne(string $name, Relation $relation, $cacheKey = 'MorphOneOrMany'):AssociationStubPolymorphic
203
    {
204
        $stub = new AssociationStubPolymorphic();
205
        $keyChain = self::getKeyChain($relation, $cacheKey);
206
        $stub->setRelationName($name);
207
        $stub->setThroughFieldChain($keyChain);
208
        $stub->setKeyField($keyChain[0]);
209
        $stub->setForeignField($keyChain[2]);
210
        $stub->setTargType(get_class($relation->getRelated()));
211
        $stub->setMorphType($keyChain[1]);
212
        $stub->setMultiplicity(AssociationStubRelationType::NULL_ONE());
213
        return $stub;
214
    }
215
216
217
    /**
218
     * @param  string                     $name
219
     * @param  Relation                  $relation
220
     * @param  string                     $cacheKey
221
     * @return AssociationStubPolymorphic
222
     */
223
    protected static function handleMorphMany(string $name, Relation $relation, $cacheKey = 'MorphOneOrMany'): AssociationStubPolymorphic
224
    {
225
        $stub = new AssociationStubPolymorphic();
226
        $keyChain = self::getKeyChain($relation, $cacheKey);
227
        $stub->setRelationName($name);
228
        $stub->setThroughFieldChain($keyChain);
229
        $stub->setKeyField($keyChain[0]);
230
        $stub->setMorphType($keyChain[1]);
231
        $stub->setForeignField($keyChain[2]);
232
        $stub->setMultiplicity(AssociationStubRelationType::MANY());
233
        $stub->setTargType(get_class($relation->getRelated()));
234
        return $stub;
235
    }
236
237
    /**
238
     * @param Relation $relation
239
     * @param string $cacheKey
240
     * @return array
241
     */
242
    private static function getKeyChain(Relation $relation, string $cacheKey) : array
243
    {
244
        $fields = self::$fieldOrderCache[$cacheKey];
245
        $getter =  function () use ($fields) {
246
            $carry = [];
247
            foreach ($fields as $item) {
248
                $v = $this->{$item};
1 ignored issue
show
Comprehensibility Best Practice introduced by
The variable $this seems to be never defined.
Loading history...
249
                if ($v == null && $item == 'ownerKey') {
250
                    $carry[] = null;
251
                    continue;
252
                }
253
                $segments = explode('.', $this->{$item});
254
                $carry[] = end($segments);
255
            }
256
            return $carry;
257
        };
258
        return call_user_func($getter->bindTo($relation, Relation::class));
259
    }
260
261
    private static $fieldOrderCache = [
262
        'BelongsTo' => ['foreignKey', 'ownerKey'],
263
        'BelongsToMany' => ['parentKey','foreignPivotKey','relatedPivotKey','relatedKey'],
264
        'HasOneOrMany' => ['localKey', 'foreignKey' ],
265
        'HasManyThrough' => ['localKey', 'firstKey', 'secondLocalKey', 'secondKey'],
266
        'MorphToMany' => ['parentKey','foreignPivotKey','morphType', 'relatedPivotKey','relatedKey'],
267
        'MorphTo' => ['foreignKey', 'morphType', 'ownerKey'],
268
        'MorphOneOrMany' => ['foreignKey', 'morphType', 'localKey' ],
269
270
    ];
271
}
272