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