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

AssociationStubFactory::handleHasManyThrough()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 16
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 14
c 1
b 0
f 0
dl 0
loc 16
rs 9.7998
cc 1
nc 1
nop 3
1
<?php
2
declare(strict_types=1);
3
4
namespace AlgoWeb\PODataLaravel\Models\ObjectMap\Entities\Associations;
5
6
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
    public static function associationStubFromRelation(string $name, Relation $relation): AssociationStubBase
21
    {
22
        $handler = self::getHandlerMethod($relation);
23
        return self::{'handle' . $handler}($name, $relation);
24
    }
25
    private static function getHandlerMethod(Relation $relation):string
26
    {
27
        $methods = [];
28
        $methods[$relation instanceof BelongsTo] = 'BelongsTo'; //DONE
29
        $methods[$relation instanceof MorphTo] = 'MorphTo'; //DONE
30
        $methods[$relation instanceof BelongsToMany] = 'BelongsToMany'; //DONE
31
        $methods[$relation instanceof MorphToMany] = 'MorphToMany'; // DONE
32
        $methods[$relation instanceof HasOne] = 'HasOne';
33
        $methods[$relation instanceof HasMany] = 'HasMany';
34
        $methods[$relation instanceof HasManyThrough] = 'HasManyThrough'; //DONE
35
        $methods[$relation instanceof MorphMany] = 'MorphMany';
36
        $methods[$relation instanceof MorphOne] = 'MorphOne';
37
38
        return $methods[true];
39
    }
40
41
    /**
42
     * @param string $name
43
     * @param Relation $relation
44
     * @param string $cacheKey
45
     * @return AssociationStubBase
46
     */
47
    protected static function handleBelongsTo(string $name, Relation $relation, $cacheKey = 'BelongsTo'): AssociationStubBase{
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);
0 ignored issues
show
Bug introduced by
The method setThroughFieldChain() does not exist on AlgoWeb\PODataLaravel\Mo...ociationStubMonomorphic. Did you maybe mean setThroughField()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

52
        $stub->/** @scrutinizer ignore-call */ 
53
               setThroughFieldChain($keyChain);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
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
        $stub = new AssociationStubPolymorphic();
68
        $keyChain = self::getKeyChain($relation, $cacheKey);
69
        $stub->setBaseType(get_class(self::getParent($relation)));
70
        $stub->setRelationName($name);
71
        $stub->setThroughFieldChain($keyChain);
0 ignored issues
show
Bug introduced by
The method setThroughFieldChain() does not exist on AlgoWeb\PODataLaravel\Mo...ociationStubPolymorphic. Did you maybe mean setThroughField()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

71
        $stub->/** @scrutinizer ignore-call */ 
72
               setThroughFieldChain($keyChain);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

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