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

AssociationStubFactory::getHandlerMethod()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 14
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

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