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

AssociationStubFactory::handleBelongsToMany()   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[1]);
67
        $stub->setForeignField($keyChain[0]);
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 = 'BelongsTo') : AssociationStubPolymorphic
80
    {
81
        $stub = new AssociationStubPolymorphic();
82
        $keyChain = self::getKeyChain($relation, $cacheKey);
83
        $stub->setRelationName($name);
84
        $stub->setThroughFieldChain($keyChain);
85
        $stub->setKeyField($keyChain[0] ?: $relation->getRelated()->getKeyName());
86
        $stub->setForeignField($keyChain[0]);
87
        $stub->setMultiplicity(AssociationStubRelationType::ONE());
88
        $stub->setTargType(null);
89
        return $stub;
90
    }
91
92
93
    /**
94
     * @param  string              $name
95
     * @param  Relation            $relation
96
     * @param  string              $cacheKey
97
     * @return AssociationStubMonomorphic
98
     */
99
    protected static function handleBelongsToMany(string $name, Relation $relation, $cacheKey = 'BelongsToMany'): AssociationStubMonomorphic
100
    {
101
        $stub = new AssociationStubMonomorphic();
102
        $keyChain = self::getKeyChain($relation, $cacheKey);
103
        $stub->setRelationName($name);
104
        $stub->setThroughFieldChain($keyChain);
105
        $stub->setMultiplicity(AssociationStubRelationType::MANY());
106
        $stub->setTargType(get_class($relation->getRelated()));
107
        $stub->setKeyField($keyChain[2]);
108
        $stub->setForeignField($keyChain[1]);
109
        return $stub;
110
    }
111
    /**
112
     * @param  string              $name
113
     * @param  Relation            $relation
114
     * @param  string              $cacheKey
115
     * @return AssociationStubMonomorphic
116
     */
117
    protected static function handleHasManyThrough(string $name, Relation $relation, $cacheKey = 'HasManyThrough'):AssociationStubMonomorphic
118
    {
119
        $keyChain = self::getKeyChain($relation, $cacheKey);
120
        $stub = new AssociationStubMonomorphic();
121
        $stub->setRelationName($name);
122
        $stub->setThroughFieldChain($keyChain);
123
        $stub->setMultiplicity(AssociationStubRelationType::MANY());
124
        $stub->setTargType(get_class($relation->getRelated()));
125
        $stub->setThroughField($keyChain[1]);
126
        $stub->setKeyField($keyChain[3]);
127
        $stub->setForeignField($keyChain[2]);
128
        return $stub;
129
    }
130
131
    /**
132
     * @param  string              $name
133
     * @param  Relation            $relation
134
     * @param  string              $cacheKey
135
     * @return AssociationStubPolymorphic
136
     */
137
    protected static function handleMorphToMany(string $name, Relation $relation, $cacheKey = 'BelongsToMany'): AssociationStubPolymorphic
138
    {
139
        $inverseGetter = function () {
140
            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...
141
        };
142
        $inverse = call_user_func($inverseGetter->bindTo($relation, MorphToMany::class));
143
        $stub = new AssociationStubPolymorphic();
144
        $keyChain = self::getKeyChain($relation, $cacheKey);
145
        $stub->setRelationName($name);
146
        $stub->setThroughFieldChain($keyChain);
147
        $stub->setKeyField($keyChain[2]);
148
        $stub->setForeignField($inverse ? null : $keyChain[1]);
149
        $stub->setMultiplicity(AssociationStubRelationType::MANY());
150
        $stub->setTargType($inverse ? null : get_class($relation->getRelated()));
151
        return $stub;
152
    }
153
154
    /**
155
     * @param string $name
156
     * @param Relation $relation
157
     * @param string $cacheKey
158
     * @return AssociationStubMonomorphic
159
     */
160
    protected static function handleHasOne(string $name, Relation $relation, $cacheKey = 'HasOneOrMany'): AssociationStubMonomorphic
161
    {
162
        $stub = new AssociationStubMonomorphic();
163
        $keyChain = self::getKeyChain($relation, $cacheKey);
164
        $stub->setRelationName($name);
165
        $stub->setThroughFieldChain($keyChain);
166
        $stub->setKeyField($keyChain[0]);
167
        $stub->setForeignField($keyChain[1]);
168
        $stub->setTargType(get_class($relation->getRelated()));
169
        $stub->setMultiplicity(AssociationStubRelationType::NULL_ONE());
170
        return $stub;
171
    }
172
173
    /**
174
     * @param string $name
175
     * @param Relation $relation
176
     * @param string $cacheKey
177
     * @return AssociationStubMonomorphic
178
     */
179
    protected static function handleHasMany(string $name, Relation $relation, $cacheKey = 'HasOneOrMany'): AssociationStubMonomorphic
180
    {
181
        $stub = new AssociationStubMonomorphic();
182
        $keyChain = self::getKeyChain($relation, $cacheKey);
183
        $stub->setRelationName($name);
184
        $stub->setThroughFieldChain($keyChain);
185
        $stub->setKeyField($keyChain[0]);
186
        $stub->setForeignField($keyChain[1]);
187
        $stub->setTargType(get_class($relation->getRelated()));
188
        $stub->setMultiplicity(AssociationStubRelationType::MANY());
189
        return $stub;
190
    }
191
192
    /**
193
     * @param  string                     $name
194
     * @param  Relation                   $relation
195
     * @param  string                     $cacheKey
196
     * @return AssociationStubPolymorphic
197
     */
198
    protected static function handleMorphOne(string $name, Relation $relation, $cacheKey = 'HasOneOrMany'):AssociationStubPolymorphic
199
    {
200
        $stub = new AssociationStubPolymorphic();
201
        $keyChain = self::getKeyChain($relation, $cacheKey);
202
        $stub->setRelationName($name);
203
        $stub->setThroughFieldChain($keyChain);
204
        $stub->setKeyField($keyChain[1]);
205
        $stub->setForeignField($keyChain[0]);
206
        $stub->setTargType(get_class($relation->getRelated()));
207
        $stub->setMultiplicity(AssociationStubRelationType::NULL_ONE());
208
        return $stub;
209
    }
210
211
212
    /**
213
     * @param  string                     $name
214
     * @param  Relation                  $relation
215
     * @param  string                     $cacheKey
216
     * @return AssociationStubPolymorphic
217
     */
218
    protected static function handleMorphMany(string $name, Relation $relation, $cacheKey = 'HasOneOrMany'): AssociationStubPolymorphic
219
    {
220
        $stub = new AssociationStubPolymorphic();
221
        $keyChain = self::getKeyChain($relation, $cacheKey);
222
        $stub->setRelationName($name);
223
        $stub->setThroughFieldChain($keyChain);
224
        $stub->setKeyField($keyChain[1]);
225
        $stub->setForeignField($keyChain[0]);
226
        $stub->setMultiplicity(AssociationStubRelationType::MANY());
227
        $stub->setTargType(get_class($relation->getRelated()));
228
        return $stub;
229
    }
230
231
    /**
232
     * @param Relation $relation
233
     * @param string $cacheKey
234
     * @return array
235
     */
236
    private static function getKeyChain(Relation $relation, string $cacheKey) : array
237
    {
238
        $fields = self::$fieldOrderCache[$cacheKey];
239
        $getter =  function () use ($fields) {
240
            $carry = [];
241
            foreach ($fields as $item) {
242
                $v = $this->{$item};
1 ignored issue
show
Comprehensibility Best Practice introduced by
The variable $this seems to be never defined.
Loading history...
243
                if ($v == null && $item == 'ownerKey') {
244
                    $carry[] = null;
245
                    continue;
246
                }
247
                $segments = explode('.', $this->{$item});
248
                $carry[] = end($segments);
249
            }
250
            return $carry;
251
        };
252
        return call_user_func($getter->bindTo($relation, Relation::class));
253
    }
254
255
    private static $fieldOrderCache = [
256
        'BelongsTo' => ['ownerKey', 'foreignKey'],
257
        'BelongsToMany' => ['parentKey','foreignPivotKey','relatedPivotKey','relatedKey'],
258
        'HasOneOrMany' => ['localKey', 'foreignKey' ],
259
        'HasManyThrough' => ['localKey', 'firstKey', 'secondLocalKey', 'secondKey'],
260
261
    ];
262
}
263