Completed
Push — master ( 872a67...aae9a3 )
by Jonas
03:00
created

HasRelationships::hasOneOrManyDeepThroughParents()   A

Complexity

Conditions 3
Paths 1

Size

Total Lines 15
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 9
nc 1
nop 1
dl 0
loc 15
ccs 9
cts 9
cp 1
crap 3
rs 9.9666
c 0
b 0
f 0
1
<?php
2
3
namespace Staudenmeir\EloquentHasManyDeep;
4
5
use Illuminate\Database\Eloquent\Builder;
6
use Illuminate\Database\Eloquent\Model;
7
use Illuminate\Database\Eloquent\Relations\Pivot;
8
use Illuminate\Support\Str;
9
10
trait HasRelationships
11
{
12
    use ConcatenatesRelationships;
13
14
    /**
15
     * Define a has-many-deep relationship.
16
     *
17
     * @param  string  $related
18
     * @param  array  $through
19
     * @param  array  $foreignKeys
20
     * @param  array  $localKeys
21
     * @return \Staudenmeir\EloquentHasManyDeep\HasManyDeep
22
     */
23 34
    public function hasManyDeep($related, array $through, array $foreignKeys = [], array $localKeys = [])
24
    {
25 34
        return $this->newHasManyDeep(...$this->hasOneOrManyDeep($related, $through, $foreignKeys, $localKeys));
26
    }
27
28
    /**
29
     * Define a has-many-deep relationship from existing relationships.
30
     *
31
     * @param  \Illuminate\Database\Eloquent\Relations\Relation ...$relations
32
     * @return \Staudenmeir\EloquentHasManyDeep\HasManyDeep
33
     */
34 7
    public function hasManyDeepFromRelations(...$relations)
35
    {
36 7
        return $this->hasManyDeep(...$this->hasOneOrManyDeepFromRelations($relations));
37
    }
38
39
    /**
40
     * Define a has-one-deep relationship.
41
     *
42
     * @param  string  $related
43
     * @param  array  $through
44
     * @param  array  $foreignKeys
45
     * @param  array  $localKeys
46
     * @return \Staudenmeir\EloquentHasManyDeep\HasOneDeep
47
     */
48 5
    public function hasOneDeep($related, array $through, array $foreignKeys = [], array $localKeys = [])
49
    {
50 5
        return $this->newHasOneDeep(...$this->hasOneOrManyDeep($related, $through, $foreignKeys, $localKeys));
51
    }
52
53
    /**
54
     * Define a has-one-deep relationship from existing relationships.
55
     *
56
     * @param  \Illuminate\Database\Eloquent\Relations\Relation ...$relations
57
     * @return \Staudenmeir\EloquentHasManyDeep\HasOneDeep
58
     */
59 1
    public function hasOneDeepFromRelations(...$relations)
60
    {
61 1
        return $this->hasOneDeep(...$this->hasOneOrManyDeepFromRelations($relations));
62
    }
63
64
    /**
65
     * Prepare a has-one-deep or has-many-deep relationship.
66
     *
67
     * @param  string  $related
68
     * @param  array  $through
69
     * @param  array  $foreignKeys
70
     * @param  array  $localKeys
71
     * @return array
72
     */
73 39
    protected function hasOneOrManyDeep($related, array $through, array $foreignKeys, array $localKeys)
74
    {
75 39
        $relatedInstance = $this->newRelatedInstance($related);
0 ignored issues
show
Bug introduced by
It seems like newRelatedInstance() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

75
        /** @scrutinizer ignore-call */ 
76
        $relatedInstance = $this->newRelatedInstance($related);
Loading history...
76
77 39
        $throughParents = $this->hasOneOrManyDeepThroughParents($through);
78
79 39
        $foreignKeys = $this->hasOneOrManyDeepForeignKeys($relatedInstance, $throughParents, $foreignKeys);
80
81 39
        $localKeys = $this->hasOneOrManyDeepLocalKeys($relatedInstance, $throughParents, $localKeys);
82
83 39
        return [$relatedInstance->newQuery(), $this, $throughParents, $foreignKeys, $localKeys];
84
    }
85
86
    /**
87
     * Prepare the through parents for a has-one-deep or has-many-deep relationship.
88
     *
89
     * @param  array  $through
90
     * @return array
91
     */
92
    protected function hasOneOrManyDeepThroughParents(array $through)
93
    {
94 39
        return array_map(function ($class) {
95 39
            $segments = preg_split('/\s+as\s+/i', $class);
96
97 39
            $instance = Str::contains($segments[0], '\\')
98 39
                ? new $segments[0]
99 39
                : (new Pivot)->setTable($segments[0]);
100
101 39
            if (isset($segments[1])) {
102 2
                $instance->setTable($instance->getTable().' as '.$segments[1]);
103
            }
104
105 39
            return $instance;
106 39
        }, $through);
107
    }
108
109
    /**
110
     * Prepare the foreign keys for a has-one-deep or has-many-deep relationship.
111
     *
112
     * @param  \Illuminate\Database\Eloquent\Model $related
113
     * @param  \Illuminate\Database\Eloquent\Model[]  $throughParents
114
     * @param  array  $foreignKeys
115
     * @return array
116
     */
117 39
    protected function hasOneOrManyDeepForeignKeys(Model $related, array $throughParents, array $foreignKeys)
118
    {
119 39
        foreach (array_merge([$this], $throughParents) as $i => $instance) {
120 39
            if (! isset($foreignKeys[$i])) {
121 29
                if ($instance instanceof Pivot) {
122 7
                    $foreignKeys[$i] = ($throughParents[$i] ?? $related)->getKeyName();
123
                } else {
124 29
                    $foreignKeys[$i] = $instance->getForeignKey();
125
                }
126
            }
127
        }
128
129 39
        return $foreignKeys;
130
    }
131
132
    /**
133
     * Prepare the local keys for a has-one-deep or has-many-deep relationship.
134
     *
135
     * @param  \Illuminate\Database\Eloquent\Model $related
136
     * @param  \Illuminate\Database\Eloquent\Model[]  $throughParents
137
     * @param  array  $localKeys
138
     * @return array
139
     */
140 39
    protected function hasOneOrManyDeepLocalKeys(Model $related, array $throughParents, array $localKeys)
141
    {
142 39
        foreach (array_merge([$this], $throughParents) as $i => $instance) {
143 39
            if (! isset($localKeys[$i])) {
144 32
                if ($instance instanceof Pivot) {
145 7
                    $localKeys[$i] = ($throughParents[$i] ?? $related)->getForeignKey();
146
                } else {
147 32
                    $localKeys[$i] = $instance->getKeyName();
148
                }
149
            }
150
        }
151
152 39
        return $localKeys;
153
    }
154
155
    /**
156
     * Instantiate a new HasManyDeep relationship.
157
     *
158
     * @param  \Illuminate\Database\Eloquent\Builder  $query
159
     * @param  \Illuminate\Database\Eloquent\Model  $farParent
160
     * @param  \Illuminate\Database\Eloquent\Model[]  $throughParents
161
     * @param  array  $foreignKeys
162
     * @param  array  $localKeys
163
     * @return \Staudenmeir\EloquentHasManyDeep\HasManyDeep
164
     */
165 34
    protected function newHasManyDeep(Builder $query, Model $farParent, array $throughParents, array $foreignKeys, array $localKeys)
166
    {
167 34
        return new HasManyDeep($query, $farParent, $throughParents, $foreignKeys, $localKeys);
168
    }
169
170
    /**
171
     * Instantiate a new HasOneDeep relationship.
172
     *
173
     * @param  \Illuminate\Database\Eloquent\Builder  $query
174
     * @param  \Illuminate\Database\Eloquent\Model  $farParent
175
     * @param  \Illuminate\Database\Eloquent\Model[]  $throughParents
176
     * @param  array  $foreignKeys
177
     * @param  array  $localKeys
178
     * @return \Staudenmeir\EloquentHasManyDeep\HasOneDeep
179
     */
180 5
    protected function newHasOneDeep(Builder $query, Model $farParent, array $throughParents, array $foreignKeys, array $localKeys)
181
    {
182 5
        return new HasOneDeep($query, $farParent, $throughParents, $foreignKeys, $localKeys);
183
    }
184
}
185