Passed
Push — master ( 7e8483...c2c113 )
by Jonas
02:50
created

hasOneOrManyDeepFromMorphToMany()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 19
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 12
nc 2
nop 4
dl 0
loc 19
ccs 12
cts 12
cp 1
crap 2
rs 9.8666
c 1
b 0
f 0
1
<?php
2
3
namespace Staudenmeir\EloquentHasManyDeep;
4
5
use Illuminate\Database\Eloquent\Relations\BelongsTo;
6
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
7
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
8
use Illuminate\Database\Eloquent\Relations\HasOneOrMany;
9
use Illuminate\Database\Eloquent\Relations\MorphOneOrMany;
10
use Illuminate\Database\Eloquent\Relations\MorphToMany;
11
use Illuminate\Database\Eloquent\Relations\Pivot;
12
use Illuminate\Database\Eloquent\Relations\Relation;
13
use RuntimeException;
14
15
trait ConcatenatesRelationships
16
{
17
    /**
18
     * Prepare a has-one-deep or has-many-deep relationship from existing relationships.
19
     *
20
     * @param \Illuminate\Database\Eloquent\Relations\Relation[] $relations
21
     * @return array
22
     */
23 9
    protected function hasOneOrManyDeepFromRelations(array $relations)
24
    {
25 9
        if (is_array($relations[0])) {
0 ignored issues
show
introduced by
The condition is_array($relations[0]) is always false.
Loading history...
26 1
            $relations = $relations[0];
27
        }
28
29 9
        $related = null;
30 9
        $through = [];
31 9
        $foreignKeys = [];
32 9
        $localKeys = [];
33
34 9
        foreach ($relations as $i => $relation) {
35 9
            $method = $this->hasOneOrManyDeepRelationMethod($relation);
36
37 9
            [$through, $foreignKeys, $localKeys] = $this->$method($relation, $through, $foreignKeys, $localKeys);
38
39 9
            if ($i === count($relations) - 1) {
40 9
                $related = get_class($relation->getRelated());
41
            } else {
42 7
                $through[] = $this->hasOneOrManyThroughParent($relation, $relations[$i + 1]);
43
            }
44
        }
45
46 9
        return [$related, $through, $foreignKeys, $localKeys];
47
    }
48
49
    /**
50
     * Prepare a has-one-deep or has-many-deep relationship from an existing belongs-to relationship.
51
     *
52
     * @param \Illuminate\Database\Eloquent\Relations\BelongsTo $relation
53
     * @param \Illuminate\Database\Eloquent\Model[] $through
54
     * @param array $foreignKeys
55
     * @param array $localKeys
56
     * @return array
57
     */
58 1
    protected function hasOneOrManyDeepFromBelongsTo(BelongsTo $relation, array $through, array $foreignKeys, array $localKeys)
59
    {
60 1
        $foreignKeys[] = $relation->getOwnerKeyName();
61
62 1
        $localKeys[] = $relation->getForeignKeyName();
63
64 1
        return [$through, $foreignKeys, $localKeys];
65
    }
66
67
    /**
68
     * Prepare a has-one-deep or has-many-deep relationship from an existing belongs-to-many relationship.
69
     *
70
     * @param \Illuminate\Database\Eloquent\Relations\BelongsToMany $relation
71
     * @param \Illuminate\Database\Eloquent\Model[] $through
72
     * @param array $foreignKeys
73
     * @param array $localKeys
74
     * @return array
75
     */
76 1
    protected function hasOneOrManyDeepFromBelongsToMany(BelongsToMany $relation, array $through, array $foreignKeys, array $localKeys)
77
    {
78 1
        $through[] = $relation->getTable();
79
80 1
        $foreignKeys[] = $relation->getForeignPivotKeyName();
81 1
        $foreignKeys[] = $relation->getRelatedKeyName();
82
83 1
        $localKeys[] = $relation->getParentKeyName();
84 1
        $localKeys[] = $relation->getRelatedPivotKeyName();
85
86 1
        return [$through, $foreignKeys, $localKeys];
87
    }
88
89
    /**
90
     * Prepare a has-one-deep or has-many-deep relationship from an existing has-one or has-many relationship.
91
     *
92
     * @param \Illuminate\Database\Eloquent\Relations\HasOneOrMany $relation
93
     * @param \Illuminate\Database\Eloquent\Model[] $through
94
     * @param array $foreignKeys
95
     * @param array $localKeys
96
     * @return array
97
     */
98 6
    protected function hasOneOrManyDeepFromHasOneOrMany(HasOneOrMany $relation, array $through, array $foreignKeys, array $localKeys)
99
    {
100 6
        $foreignKeys[] = $relation->getQualifiedForeignKeyName();
101
102 6
        $localKeys[] = $relation->getLocalKeyName();
103
104 6
        return [$through, $foreignKeys, $localKeys];
105
    }
106
107
    /**
108
     * Prepare a has-one-deep or has-many-deep relationship from an existing has-many-through relationship.
109
     *
110
     * @param \Illuminate\Database\Eloquent\Relations\HasManyThrough $relation
111
     * @param \Illuminate\Database\Eloquent\Model[] $through
112
     * @param array $foreignKeys
113
     * @param array $localKeys
114
     * @return array
115
     */
116 2
    protected function hasOneOrManyDeepFromHasManyThrough(HasManyThrough $relation, array $through, array $foreignKeys, array $localKeys)
117
    {
118 2
        $through[] = get_class($relation->getParent());
119
120 2
        $foreignKeys[] = $relation->getFirstKeyName();
121 2
        $foreignKeys[] = $relation->getForeignKeyName();
122
123 2
        $localKeys[] = $relation->getLocalKeyName();
124 2
        $localKeys[] = $relation->getSecondLocalKeyName();
125
126 2
        return [$through, $foreignKeys, $localKeys];
127
    }
128
129
    /**
130
     * Prepare a has-one-deep or has-many-deep relationship from an existing has-many-deep relationship.
131
     *
132
     * @param \Staudenmeir\EloquentHasManyDeep\HasManyDeep $relation
133
     * @param \Illuminate\Database\Eloquent\Model[] $through
134
     * @param array $foreignKeys
135
     * @param array $localKeys
136
     * @return array
137
     */
138 2
    protected function hasOneOrManyDeepFromHasManyDeep(HasManyDeep $relation, array $through, array $foreignKeys, array $localKeys)
139
    {
140 2
        foreach ($relation->getThroughParents() as $throughParent) {
141 2
            $segments = explode(' as ', $throughParent->getTable());
142
143 2
            $class = get_class($throughParent);
144
145 2
            if (isset($segments[1])) {
146 1
                $class .= ' as '.$segments[1];
147 2
            } elseif ($throughParent instanceof Pivot) {
148 1
                $class = $throughParent->getTable();
149
            }
150
151 2
            $through[] = $class;
152
        }
153
154 2
        $foreignKeys = array_merge($foreignKeys, $relation->getForeignKeys());
155
156 2
        $localKeys = array_merge($localKeys, $relation->getLocalKeys());
157
158 2
        return [$through, $foreignKeys, $localKeys];
159
    }
160
161
    /**
162
     * Prepare a has-one-deep or has-many-deep relationship from an existing morph-one or morph-many relationship.
163
     *
164
     * @param \Illuminate\Database\Eloquent\Relations\MorphOneOrMany $relation
165
     * @param \Illuminate\Database\Eloquent\Model[] $through
166
     * @param array $foreignKeys
167
     * @param array $localKeys
168
     * @return array
169
     */
170 1
    protected function hasOneOrManyDeepFromMorphOneOrMany(MorphOneOrMany $relation, array $through, array $foreignKeys, array $localKeys)
171
    {
172 1
        $foreignKeys[] = [$relation->getQualifiedMorphType(), $relation->getQualifiedForeignKeyName()];
173
174 1
        $localKeys[] = $relation->getLocalKeyName();
175
176 1
        return [$through, $foreignKeys, $localKeys];
177
    }
178
179
    /**
180
     * Prepare a has-one-deep or has-many-deep relationship from an existing morph-to-many relationship.
181
     *
182
     * @param \Illuminate\Database\Eloquent\Relations\MorphToMany $relation
183
     * @param \Illuminate\Database\Eloquent\Model[] $through
184
     * @param array $foreignKeys
185
     * @param array $localKeys
186
     * @return array
187
     */
188 2
    protected function hasOneOrManyDeepFromMorphToMany(MorphToMany $relation, array $through, array $foreignKeys, array $localKeys)
189
    {
190 2
        $through[] = $relation->getTable();
191
192 2
        if ($relation->getInverse()) {
193 1
            $foreignKeys[] = $relation->getForeignPivotKeyName();
194 1
            $foreignKeys[] = $relation->getRelatedKeyName();
195
196 1
            $localKeys[] = $relation->getParentKeyName();
197 1
            $localKeys[] = [$relation->getMorphType(), $relation->getRelatedPivotKeyName()];
198
        } else {
199 1
            $foreignKeys[] = [$relation->getMorphType(), $relation->getForeignPivotKeyName()];
200 1
            $foreignKeys[] = $relation->getRelatedKeyName();
201
202 1
            $localKeys[] = $relation->getParentKeyName();
203 1
            $localKeys[] = $relation->getRelatedPivotKeyName();
204
        }
205
206 2
        return [$through, $foreignKeys, $localKeys];
207
    }
208
209
    /**
210
     * Get the relationship method name.
211
     *
212
     * @param \Illuminate\Database\Eloquent\Relations\Relation $relation
213
     * @return string
214
     */
215 9
    protected function hasOneOrManyDeepRelationMethod(Relation $relation)
216
    {
217
        $classes = [
218 9
            BelongsTo::class,
219
            HasManyDeep::class,
220
            HasManyThrough::class,
221
            MorphOneOrMany::class,
222
            HasOneOrMany::class,
223
            MorphToMany::class,
224
            BelongsToMany::class,
225
        ];
226
227 9
        foreach ($classes as $class) {
228 9
            if ($relation instanceof $class) {
229 9
                return 'hasOneOrManyDeepFrom'.class_basename($class);
230
            }
231
        }
232
233
        throw new RuntimeException('This relationship is not supported.'); // @codeCoverageIgnore
234
    }
235
236
    /**
237
     * Prepare the through parent class from an existing relationship and its successor.
238
     *
239
     * @param \Illuminate\Database\Eloquent\Relations\Relation $relation
240
     * @param \Illuminate\Database\Eloquent\Relations\Relation $successor
241
     * @return string
242
     */
243 7
    protected function hasOneOrManyThroughParent(Relation $relation, Relation $successor)
244
    {
245 7
        $through = get_class($relation->getRelated());
246
247 7
        if (get_class($relation->getRelated()) === get_class($successor->getParent())) {
248 7
            $table = $successor->getParent()->getTable();
249
250 7
            $segments = explode(' as ', $table);
251
252 7
            if (isset($segments[1])) {
253 1
                $through .= ' as '.$segments[1];
254
            }
255
        }
256
257 7
        return $through;
258
    }
259
}
260