Passed
Pull Request — master (#221)
by Christopher
06:51 queued 45s
created

AssociationStubFactory::handleMorphOne()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 10
c 2
b 0
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[0]);
109
        $stub->setForeignField($keyChain[3]);
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[0]);
128
        $stub->setForeignField($keyChain[3]);
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
        $inverse = self::getKeyChain($relation, "inverse")[0];
143
        $stub = new AssociationStubPolymorphic();
144
        $keyChain = self::getKeyChain($relation, $cacheKey);
145
        $stub->setRelationName($name);
146
        $stub->setThroughFieldChain($keyChain);
147
        $stub->setKeyField($keyChain[3]);
148
        $stub->setForeignField($inverse ? null : $keyChain[1]);
149
        $stub->setMultiplicity(AssociationStubRelationType::MANY());
150
        $stub->setMorphType($keyChain[2]);
151
        $stub->setTargType($inverse ? null : get_class($relation->getRelated()));
152
        return $stub;
153
    }
154
155
    /**
156
     * @param string $name
157
     * @param Relation $relation
158
     * @param string $cacheKey
159
     * @return AssociationStubMonomorphic
160
     */
161
    protected static function handleHasOne(string $name, Relation $relation, $cacheKey = 'HasOneOrMany'): AssociationStubMonomorphic
162
    {
163
        $stub = new AssociationStubMonomorphic();
164
        $keyChain = self::getKeyChain($relation, $cacheKey);
165
        $stub->setRelationName($name);
166
        $stub->setThroughFieldChain($keyChain);
167
        $stub->setKeyField($keyChain[0]);
168
        $stub->setForeignField($keyChain[1]);
169
        $stub->setTargType(get_class($relation->getRelated()));
170
        $stub->setMultiplicity(AssociationStubRelationType::NULL_ONE());
171
        return $stub;
172
    }
173
174
    /**
175
     * @param string $name
176
     * @param Relation $relation
177
     * @param string $cacheKey
178
     * @return AssociationStubMonomorphic
179
     */
180
    protected static function handleHasMany(string $name, Relation $relation, $cacheKey = 'HasOneOrMany'): AssociationStubMonomorphic
181
    {
182
        $stub = new AssociationStubMonomorphic();
183
        $keyChain = self::getKeyChain($relation, $cacheKey);
184
        $stub->setRelationName($name);
185
        $stub->setThroughFieldChain($keyChain);
186
        $stub->setKeyField($keyChain[0]);
187
        $stub->setForeignField($keyChain[1]);
188
        $stub->setTargType(get_class($relation->getRelated()));
189
        $stub->setMultiplicity(AssociationStubRelationType::MANY());
190
        return $stub;
191
    }
192
193
    /**
194
     * @param  string                     $name
195
     * @param  Relation                   $relation
196
     * @param  string                     $cacheKey
197
     * @return AssociationStubPolymorphic
198
     */
199
    protected static function handleMorphOne(string $name, Relation $relation, $cacheKey = 'MorphOneOrMany'):AssociationStubPolymorphic
200
    {
201
        $stub = new AssociationStubPolymorphic();
202
        $keyChain = self::getKeyChain($relation, $cacheKey);
203
        $stub->setRelationName($name);
204
        $stub->setThroughFieldChain($keyChain);
205
        $stub->setKeyField($keyChain[0]);
206
        $stub->setForeignField($keyChain[2]);
207
        $stub->setTargType(get_class($relation->getRelated()));
208
        $stub->setMorphType($keyChain[1]);
209
        $stub->setMultiplicity(AssociationStubRelationType::NULL_ONE());
210
        return $stub;
211
    }
212
213
214
    /**
215
     * @param  string                     $name
216
     * @param  Relation                  $relation
217
     * @param  string                     $cacheKey
218
     * @return AssociationStubPolymorphic
219
     */
220
    protected static function handleMorphMany(string $name, Relation $relation, $cacheKey = 'MorphOneOrMany'): AssociationStubPolymorphic
221
    {
222
        $stub = new AssociationStubPolymorphic();
223
        $keyChain = self::getKeyChain($relation, $cacheKey);
224
        $stub->setRelationName($name);
225
        $stub->setThroughFieldChain($keyChain);
226
        $stub->setKeyField($keyChain[0]);
227
        $stub->setMorphType($keyChain[1]);
228
        $stub->setForeignField($keyChain[2]);
229
        $stub->setMultiplicity(AssociationStubRelationType::MANY());
230
        $stub->setTargType(get_class($relation->getRelated()));
231
        return $stub;
232
    }
233
234
    /**
235
     * @param Relation $relation
236
     * @param string $cacheKey
237
     * @return array
238
     */
239
    private static function getKeyChain(Relation $relation, string $cacheKey) : array
240
    {
241
        $fields = self::$fieldOrderCache[$cacheKey];
242
        $getter =  function () use ($fields) {
243
            $carry = [];
244
            foreach ($fields as $item) {
245
                $v = $this->{$item};
1 ignored issue
show
Comprehensibility Best Practice introduced by
The variable $this seems to be never defined.
Loading history...
246
                if ($v == null && $item == 'ownerKey') {
247
                    $carry[] = null;
248
                    continue;
249
                }
250
                //TODO: investigate if this is needed can we use quailifed keys?
251
                $segments = explode('.', strval($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
        'inverse' => ['inverse'], // TODO: currently used to get inverse, should be removed when morephtomany is fixed
268
269
    ];
270
}
271