AssociationStubFactory   A
last analyzed

Complexity

Total Complexity 15

Size/Duplication

Total Lines 224
Duplicated Lines 0 %

Importance

Changes 8
Bugs 0 Features 0
Metric Value
wmc 15
eloc 86
c 8
b 0
f 0
dl 0
loc 224
rs 10

12 Methods

Rating   Name   Duplication   Size   Complexity  
A getHandlerMethod() 0 14 1
A associationStubFromRelation() 0 10 1
A handleMorphMany() 0 9 1
A handleHasManyThrough() 0 8 1
A getKeyChain() 0 18 4
A handleBelongsToMany() 0 8 1
A handleHasMany() 0 8 1
A handleMorphTo() 0 9 1
A handleMorphToMany() 0 15 1
A handleMorphOne() 0 9 1
A handleHasOne() 0 8 1
A handleBelongsTo() 0 8 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace AlgoWeb\PODataLaravel\Models\ObjectMap\Entities\Associations;
6
7
use Illuminate\Database\Eloquent\Model;
8
use Illuminate\Database\Eloquent\Relations\BelongsTo;
9
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
10
use Illuminate\Database\Eloquent\Relations\HasMany;
11
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
12
use Illuminate\Database\Eloquent\Relations\HasOne;
13
use Illuminate\Database\Eloquent\Relations\MorphMany;
14
use Illuminate\Database\Eloquent\Relations\MorphOne;
15
use Illuminate\Database\Eloquent\Relations\MorphTo;
16
use Illuminate\Database\Eloquent\Relations\MorphToMany;
17
use Illuminate\Database\Eloquent\Relations\Relation;
18
use POData\Common\InvalidOperationException;
19
20
abstract class AssociationStubFactory
21
{
22
    /**
23
     * @param  Model                     $parent
24
     * @param  string                    $name
25
     * @throws InvalidOperationException
26
     * @return AssociationStubBase
27
     */
28
    public static function associationStubFromRelation(Model $parent, string $name): AssociationStubBase
29
    {
30
        $relation = $parent->{$name}();
31
        $handler  = self::getHandlerMethod($relation);
32
        /**
33
         * @var AssociationStubBase $stub
34
         */
35
        $stub = self::{'handle' . $handler}($name, $relation);
36
        $stub->setBaseType(get_class($parent));
37
        return $stub;
38
    }
39
40
    private static function getHandlerMethod(Relation $relation): string
41
    {
42
        $methods                                      = [];
43
        $methods[$relation instanceof BelongsTo]      = 'BelongsTo'; //DONE
44
        $methods[$relation instanceof MorphTo]        = 'MorphTo'; //DONE
45
        $methods[$relation instanceof BelongsToMany]  = 'BelongsToMany'; //DONE
46
        $methods[$relation instanceof MorphToMany]    = 'MorphToMany'; // DONE
47
        $methods[$relation instanceof HasOne]         = 'HasOne';
48
        $methods[$relation instanceof HasMany]        = 'HasMany';
49
        $methods[$relation instanceof HasManyThrough] = 'HasManyThrough'; //DONE
50
        $methods[$relation instanceof MorphMany]      = 'MorphMany';
51
        $methods[$relation instanceof MorphOne]       = 'MorphOne';
52
53
        return $methods[true];
54
    }
55
56
    /**
57
     * @param  string                     $name
58
     * @param  Relation                   $relation
59
     * @param  string                     $cacheKey
60
     * @return AssociationStubMonomorphic
61
     */
62
    protected static function handleBelongsTo(string $name, Relation $relation, $cacheKey = 'BelongsTo'): AssociationStubMonomorphic
63
    {
64
        /** @var string[] $keyChain */
65
        $keyChain = self::getKeyChain($relation, $cacheKey);
66
        $stub     = new AssociationStubMonomorphic($name, $keyChain[0], $keyChain, AssociationStubRelationType::ONE());
67
        $stub->setForeignFieldName($keyChain[1]);
68
        $stub->setTargType(get_class($relation->getRelated()));
69
        return $stub;
70
    }
71
72
    /**
73
     * @param  string                     $name
74
     * @param  Relation                   $relation
75
     * @param  string                     $cacheKey
76
     * @return AssociationStubPolymorphic
77
     */
78
    protected static function handleMorphTo(string $name, Relation $relation, $cacheKey = 'MorphTo'): AssociationStubPolymorphic
79
    {
80
        /** @var string[] $keyChain */
81
        $keyChain = self::getKeyChain($relation, $cacheKey);
82
        $stub     = new AssociationStubPolymorphic($name, $keyChain[0], $keyChain, AssociationStubRelationType::ONE());
83
        $stub->setForeignFieldName($keyChain[2]);
84
        $stub->setTargType(null);
85
        $stub->setMorphType($keyChain[1]);
86
        return $stub;
87
    }
88
89
90
    /**
91
     * @param  string                     $name
92
     * @param  Relation                   $relation
93
     * @param  string                     $cacheKey
94
     * @return AssociationStubMonomorphic
95
     */
96
    protected static function handleBelongsToMany(string $name, Relation $relation, $cacheKey = 'BelongsToMany'): AssociationStubMonomorphic
97
    {
98
        /** @var string[] $keyChain */
99
        $keyChain = self::getKeyChain($relation, $cacheKey);
100
        $stub     = new AssociationStubMonomorphic($name, $keyChain[0], $keyChain, AssociationStubRelationType::MANY());
101
        $stub->setTargType(get_class($relation->getRelated()));
102
        $stub->setForeignFieldName($keyChain[3]);
103
        return $stub;
104
    }
105
    /**
106
     * @param  string                     $name
107
     * @param  Relation                   $relation
108
     * @param  string                     $cacheKey
109
     * @return AssociationStubMonomorphic
110
     */
111
    protected static function handleHasManyThrough(string $name, Relation $relation, $cacheKey = 'HasManyThrough'): AssociationStubMonomorphic
112
    {
113
        /** @var string[] $keyChain */
114
        $keyChain = self::getKeyChain($relation, $cacheKey);
115
        $stub     = new AssociationStubMonomorphic($name, $keyChain[0], $keyChain, AssociationStubRelationType::MANY());
116
        $stub->setTargType(get_class($relation->getRelated()));
117
        $stub->setForeignFieldName($keyChain[3]);
118
        return $stub;
119
    }
120
121
    /**
122
     * @param  string                     $name
123
     * @param  Relation                   $relation
124
     * @param  string                     $cacheKey
125
     * @return AssociationStubPolymorphic
126
     */
127
    protected static function handleMorphToMany(string $name, Relation $relation, $cacheKey = 'MorphToMany'): AssociationStubPolymorphic
128
    {
129
        //return self::handleBelongsToMany($name,$relation);
130
        //TODO: investigate if this could be treated as a BelongsToMany Or more importantly a Monomorphic as we know both sides
131
        /** @var string[] $keyChain */
132
        $keyChain = self::getKeyChain($relation, $cacheKey);
133
        $stub     = new AssociationStubPolymorphic($name, $keyChain[0], $keyChain, AssociationStubRelationType::MANY());
134
        //$stub->setRelationName($name);
135
        //$stub->setThroughFieldChain($keyChain);
136
        //$stub->setKeyFieldName($keyChain[0]);
137
        $stub->setForeignFieldName($keyChain[4]);
138
        //$stub->setMultiplicity(AssociationStubRelationType::MANY());
139
        $stub->setMorphType($keyChain[2]);
140
        $stub->setTargType(get_class($relation->getRelated()));
141
        return $stub;
142
    }
143
144
    /**
145
     * @param  string                     $name
146
     * @param  Relation                   $relation
147
     * @param  string                     $cacheKey
148
     * @return AssociationStubMonomorphic
149
     */
150
    protected static function handleHasOne(string $name, Relation $relation, $cacheKey = 'HasOneOrMany'): AssociationStubMonomorphic
151
    {
152
        /** @var string[] $keyChain */
153
        $keyChain = self::getKeyChain($relation, $cacheKey);
154
        $stub     = new AssociationStubMonomorphic($name, $keyChain[0], $keyChain, AssociationStubRelationType::NULL_ONE());
155
        $stub->setForeignFieldName($keyChain[1]);
156
        $stub->setTargType(get_class($relation->getRelated()));
157
        return $stub;
158
    }
159
160
    /**
161
     * @param  string                     $name
162
     * @param  Relation                   $relation
163
     * @param  string                     $cacheKey
164
     * @return AssociationStubMonomorphic
165
     */
166
    protected static function handleHasMany(string $name, Relation $relation, $cacheKey = 'HasOneOrMany'): AssociationStubMonomorphic
167
    {
168
        /** @var string[] $keyChain */
169
        $keyChain = self::getKeyChain($relation, $cacheKey);
170
        $stub     = new AssociationStubMonomorphic($name, $keyChain[0], $keyChain, AssociationStubRelationType::MANY());
171
        $stub->setForeignFieldName($keyChain[1]);
172
        $stub->setTargType(get_class($relation->getRelated()));
173
        return $stub;
174
    }
175
176
    /**
177
     * @param  string                     $name
178
     * @param  Relation                   $relation
179
     * @param  string                     $cacheKey
180
     * @return AssociationStubPolymorphic
181
     */
182
    protected static function handleMorphOne(string $name, Relation $relation, $cacheKey = 'MorphOneOrMany'): AssociationStubPolymorphic
183
    {
184
        /** @var string[] $keyChain */
185
        $keyChain = self::getKeyChain($relation, $cacheKey);
186
        $stub     = new AssociationStubPolymorphic($name, $keyChain[0], $keyChain, AssociationStubRelationType::NULL_ONE());
187
        $stub->setForeignFieldName($keyChain[2]);
188
        $stub->setTargType(get_class($relation->getRelated()));
189
        $stub->setMorphType($keyChain[1]);
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 handleMorphMany(string $name, Relation $relation, $cacheKey = 'MorphOneOrMany'): AssociationStubPolymorphic
200
    {
201
        /** @var string[] $keyChain */
202
        $keyChain = self::getKeyChain($relation, $cacheKey);
203
        $stub     = new AssociationStubPolymorphic($name, $keyChain[0], $keyChain, AssociationStubRelationType::MANY());
204
        $stub->setMorphType($keyChain[1]);
205
        $stub->setForeignFieldName($keyChain[2]);
206
        $stub->setTargType(get_class($relation->getRelated()));
207
        return $stub;
208
    }
209
210
    /**
211
     * @param  Relation $relation
212
     * @param  string   $cacheKey
213
     * @return array<array|string>
214
     */
215
    private static function getKeyChain(Relation $relation, string $cacheKey): array
216
    {
217
        $fields = self::$fieldOrderCache[$cacheKey];
218
        $getter = function () use ($fields) {
219
            $carry = [];
220
            foreach ($fields as $item) {
221
                $v = $this->{$item};
222
                if (null == $v && 'ownerKey' == $item) {
223
                    $carry[] = null;
224
                    continue;
225
                }
226
                //TODO: investigate if this is needed can we use quailifed keys?
227
                $segments = explode('.', strval($this->{$item}));
228
                $carry[]  = end($segments);
229
            }
230
            return $carry;
231
        };
232
        return call_user_func($getter->bindTo($relation, Relation::class));
233
    }
234
235
    /** @var array<string, array> */
236
    private static $fieldOrderCache = [
237
        'BelongsTo' => ['foreignKey', 'ownerKey'],
238
        'BelongsToMany' => ['parentKey','foreignPivotKey','relatedPivotKey','relatedKey'],
239
        'HasOneOrMany' => ['localKey', 'foreignKey' ],
240
        'HasManyThrough' => ['localKey', 'firstKey', 'secondLocalKey', 'secondKey'],
241
        'MorphToMany' => ['parentKey','foreignPivotKey','morphType', 'relatedPivotKey','relatedKey'],
242
        'MorphTo' => ['foreignKey', 'morphType', 'ownerKey'],
243
        'MorphOneOrMany' => ['localKey', 'morphType', 'foreignKey'],
244
    ];
245
}
246