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

AssociationStubFactory::handleMorphMany()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 1 Features 0
Metric Value
eloc 10
c 3
b 1
f 0
dl 0
loc 12
rs 9.9332
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'): AssociationStubPolymorphic
139
    {
140
        $inverseGetter = function () {
141
            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...
142
        };
143
        $inverse = call_user_func($inverseGetter->bindTo($relation, MorphToMany::class));
144
        $stub = new AssociationStubPolymorphic();
145
        $keyChain = self::getKeyChain($relation, $cacheKey);
146
        $stub->setRelationName($name);
147
        $stub->setThroughFieldChain($keyChain);
148
        $stub->setKeyField($keyChain[3]);
149
        $stub->setForeignField($inverse ? null : $keyChain[1]);
150
        $stub->setMultiplicity(AssociationStubRelationType::MANY());
151
        $stub->setMorphType($keyChain[2]);
152
        $stub->setTargType($inverse ? null : get_class($relation->getRelated()));
153
        return $stub;
154
    }
155
156
    /**
157
     * @param string $name
158
     * @param Relation $relation
159
     * @param string $cacheKey
160
     * @return AssociationStubMonomorphic
161
     */
162
    protected static function handleHasOne(string $name, Relation $relation, $cacheKey = 'HasOneOrMany'): AssociationStubMonomorphic
163
    {
164
        $stub = new AssociationStubMonomorphic();
165
        $keyChain = self::getKeyChain($relation, $cacheKey);
166
        $stub->setRelationName($name);
167
        $stub->setThroughFieldChain($keyChain);
168
        $stub->setKeyField($keyChain[0]);
169
        $stub->setForeignField($keyChain[1]);
170
        $stub->setTargType(get_class($relation->getRelated()));
171
        $stub->setMultiplicity(AssociationStubRelationType::NULL_ONE());
172
        return $stub;
173
    }
174
175
    /**
176
     * @param string $name
177
     * @param Relation $relation
178
     * @param string $cacheKey
179
     * @return AssociationStubMonomorphic
180
     */
181
    protected static function handleHasMany(string $name, Relation $relation, $cacheKey = 'HasOneOrMany'): AssociationStubMonomorphic
182
    {
183
        $stub = new AssociationStubMonomorphic();
184
        $keyChain = self::getKeyChain($relation, $cacheKey);
185
        $stub->setRelationName($name);
186
        $stub->setThroughFieldChain($keyChain);
187
        $stub->setKeyField($keyChain[0]);
188
        $stub->setForeignField($keyChain[1]);
189
        $stub->setTargType(get_class($relation->getRelated()));
190
        $stub->setMultiplicity(AssociationStubRelationType::MANY());
191
        return $stub;
192
    }
193
194
    /**
195
     * @param  string                     $name
196
     * @param  Relation                   $relation
197
     * @param  string                     $cacheKey
198
     * @return AssociationStubPolymorphic
199
     */
200
    protected static function handleMorphOne(string $name, Relation $relation, $cacheKey = 'MorphOneOrMany'):AssociationStubPolymorphic
201
    {
202
        $stub = new AssociationStubPolymorphic();
203
        $keyChain = self::getKeyChain($relation, $cacheKey);
204
        $stub->setRelationName($name);
205
        $stub->setThroughFieldChain($keyChain);
206
        $stub->setKeyField($keyChain[0]);
207
        $stub->setForeignField($keyChain[2]);
208
        $stub->setTargType(get_class($relation->getRelated()));
209
        $stub->setMorphType($keyChain[1]);
210
        $stub->setMultiplicity(AssociationStubRelationType::NULL_ONE());
211
        return $stub;
212
    }
213
214
215
    /**
216
     * @param  string                     $name
217
     * @param  Relation                  $relation
218
     * @param  string                     $cacheKey
219
     * @return AssociationStubPolymorphic
220
     */
221
    protected static function handleMorphMany(string $name, Relation $relation, $cacheKey = 'MorphOneOrMany'): AssociationStubPolymorphic
222
    {
223
        $stub = new AssociationStubPolymorphic();
224
        $keyChain = self::getKeyChain($relation, $cacheKey);
225
        $stub->setRelationName($name);
226
        $stub->setThroughFieldChain($keyChain);
227
        $stub->setKeyField($keyChain[0]);
228
        $stub->setMorphType($keyChain[1]);
229
        $stub->setForeignField($keyChain[2]);
230
        $stub->setMultiplicity(AssociationStubRelationType::MANY());
231
        $stub->setTargType(get_class($relation->getRelated()));
232
        return $stub;
233
    }
234
235
    /**
236
     * @param Relation $relation
237
     * @param string $cacheKey
238
     * @return array
239
     */
240
    private static function getKeyChain(Relation $relation, string $cacheKey) : array
241
    {
242
        $fields = self::$fieldOrderCache[$cacheKey];
243
        $getter =  function () use ($fields) {
244
            $carry = [];
245
            foreach ($fields as $item) {
246
                $v = $this->{$item};
1 ignored issue
show
Comprehensibility Best Practice introduced by
The variable $this seems to be never defined.
Loading history...
247
                if ($v == null && $item == 'ownerKey') {
248
                    $carry[] = null;
249
                    continue;
250
                }
251
                $segments = explode('.', $this->{$item});
252
                $carry[] = end($segments);
253
            }
254
            return $carry;
255
        };
256
        return call_user_func($getter->bindTo($relation, Relation::class));
257
    }
258
259
    private static $fieldOrderCache = [
260
        'BelongsTo' => ['foreignKey', 'ownerKey'],
261
        'BelongsToMany' => ['parentKey','foreignPivotKey','relatedPivotKey','relatedKey'],
262
        'HasOneOrMany' => ['localKey', 'foreignKey' ],
263
        'HasManyThrough' => ['localKey', 'firstKey', 'secondLocalKey', 'secondKey'],
264
        'MorphToMany' => ['parentKey','foreignPivotKey','morphType', 'relatedPivotKey','relatedKey'],
265
        'MorphTo' => ['foreignKey', 'morphType', 'ownerKey'],
266
        'MorphOneOrMany' => ['foreignKey', 'morphType', 'localKey' ],
267
268
    ];
269
}
270