Passed
Pull Request — master (#221)
by Christopher
10:14 queued 05:03
created

AssociationStubFactory::handleMorphToMany()   A

Complexity

Conditions 3
Paths 1

Size

Total Lines 16
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

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