5
5
use Closure ;
6
6
use Illuminate \Database \Eloquent \Relations \BelongsTo ;
7
7
use Illuminate \Database \Eloquent \Relations \HasOneOrMany ;
8
- use Illuminate \Database \Eloquent \Relations \Relation ;
9
- use Illuminate \Database \Eloquent \Builder as EloquentBuilder ;
8
+ use Jenssegers \Mongodb \Eloquent \Model ;
10
9
11
10
trait QueriesRelationships
12
11
{
@@ -28,9 +27,9 @@ public function has($relation, $operator = '>=', $count = 1, $boolean = 'and', C
28
27
29
28
$ relation = $ this ->getRelationWithoutConstraints ($ relation );
30
29
31
- // If this is a hybrid relation then we can not use an existence query
30
+ // If this is a hybrid relation then we can not use a normal whereExists() query that relies on a subquery
32
31
// We need to use a `whereIn` query
33
- if ($ relation -> getParent ()-> getConnectionName () !== $ relation -> getRelated ()-> getConnectionName ( )) {
32
+ if ($ this -> getModel () instanceof Model || $ this -> isAcrossConnections ( $ relation )) {
34
33
return $ this ->addHybridHas ($ relation , $ operator , $ count , $ boolean , $ callback );
35
34
}
36
35
@@ -57,6 +56,15 @@ public function has($relation, $operator = '>=', $count = 1, $boolean = 'and', C
57
56
);
58
57
}
59
58
59
+ /**
60
+ * @param $relation
61
+ * @return bool
62
+ */
63
+ protected function isAcrossConnections ($ relation )
64
+ {
65
+ return $ relation ->getParent ()->getConnectionName () !== $ relation ->getRelated ()->getConnectionName ();
66
+ }
67
+
60
68
/**
61
69
* Compare across databases
62
70
* @param $relation
@@ -65,6 +73,7 @@ public function has($relation, $operator = '>=', $count = 1, $boolean = 'and', C
65
73
* @param string $boolean
66
74
* @param Closure|null $callback
67
75
* @return mixed
76
+ * @throws \Exception
68
77
*/
69
78
public function addHybridHas ($ relation , $ operator = '>= ' , $ count = 1 , $ boolean = 'and ' , Closure $ callback = null )
70
79
{
@@ -73,23 +82,31 @@ public function addHybridHas($relation, $operator = '>=', $count = 1, $boolean =
73
82
$ hasQuery ->callScope ($ callback );
74
83
}
75
84
85
+ // If the operator is <, <= or !=, we will use whereNotIn.
86
+ $ not = in_array ($ operator , ['< ' , '<= ' , '!= ' ]);
87
+ // If we are comparing to 0, we need an additional $not flip.
88
+ if ($ count == 0 ) {
89
+ $ not = ! $ not ;
90
+ }
91
+
76
92
$ relations = $ hasQuery ->pluck ($ this ->getHasCompareKey ($ relation ));
77
- $ constraintKey = $ this ->getRelatedConstraintKey ($ relation );
78
93
79
- return $ this ->addRelatedCountConstraint ($ constraintKey , $ relations , $ operator , $ count , $ boolean );
94
+ $ relatedIds = $ this ->getConstrainedRelatedIds ($ relations , $ operator , $ count );
95
+
96
+ return $ this ->whereIn ($ this ->getRelatedConstraintKey ($ relation ), $ relatedIds , $ boolean , $ not );
80
97
}
81
98
82
99
83
100
/**
84
- * Returns key we are constraining this parent model's query witth
101
+ * Returns key we are constraining this parent model's query with
85
102
* @param $relation
86
103
* @return string
87
104
* @throws \Exception
88
105
*/
89
106
protected function getRelatedConstraintKey ($ relation )
90
107
{
91
108
if ($ relation instanceof HasOneOrMany) {
92
- return $ relation -> getQualifiedParentKeyName ();
109
+ return $ this -> model -> getKeyName ();
93
110
}
94
111
95
112
if ($ relation instanceof BelongsTo) {
@@ -105,47 +122,20 @@ protected function getRelatedConstraintKey($relation)
105
122
*/
106
123
protected function getHasCompareKey ($ relation )
107
124
{
108
- if ($ relation instanceof HasOneOrMany ) {
109
- return $ relation ->getForeignKeyName ();
125
+ if (method_exists ( $ relation, ' getHasCompareKey ' ) ) {
126
+ return $ relation ->getHasCompareKey ();
110
127
}
111
128
112
- $ keyMethods = ['getOwnerKey ' , 'getHasCompareKey ' ];
113
- foreach ($ keyMethods as $ method ) {
114
- if (method_exists ($ relation , $ method )) {
115
- return $ relation ->$ method ();
116
- }
117
- }
129
+ return $ relation instanceof HasOneOrMany ? $ relation ->getForeignKeyName () : $ relation ->getOwnerKey ();
118
130
}
119
131
120
132
/**
121
- * Add the "has" condition where clause to the query.
122
- *
123
- * @param \Illuminate\Database\Eloquent\Builder $hasQuery
124
- * @param \Illuminate\Database\Eloquent\Relations\Relation $relation
125
- * @param string $operator
126
- * @param int $count
127
- * @param string $boolean
128
- * @return \Illuminate\Database\Eloquent\Builder|static
129
- */
130
- protected function addHasWhere (EloquentBuilder $ hasQuery , Relation $ relation , $ operator , $ count , $ boolean )
131
- {
132
- $ query = $ hasQuery ->getQuery ();
133
- // Get the number of related objects for each possible parent.
134
- $ relations = $ query ->pluck ($ relation ->getHasCompareKey ());
135
-
136
- return $ this ->addRelatedCountConstraint ($ this ->model ->getKeyName (), $ relations , $ operator , $ count , $ boolean );
137
- }
138
-
139
- /**
140
- * Consta
141
- * @param $key
142
133
* @param $relations
143
134
* @param $operator
144
135
* @param $count
145
- * @param $boolean
146
- * @return mixed
136
+ * @return array
147
137
*/
148
- protected function addRelatedCountConstraint ( $ key , $ relations , $ operator , $ count, $ boolean )
138
+ protected function getConstrainedRelatedIds ( $ relations , $ operator , $ count )
149
139
{
150
140
$ relationCount = array_count_values (array_map (function ($ id ) {
151
141
return (string )$ id ; // Convert Back ObjectIds to Strings
@@ -169,16 +159,7 @@ protected function addRelatedCountConstraint($key, $relations, $operator, $count
169
159
}
170
160
});
171
161
172
- // If the operator is <, <= or !=, we will use whereNotIn.
173
- $ not = in_array ($ operator , ['< ' , '<= ' , '!= ' ]);
174
- // If we are comparing to 0, we need an additional $not flip.
175
- if ($ count == 0 ) {
176
- $ not = ! $ not ;
177
- }
178
162
// All related ids.
179
- $ relatedIds = array_keys ($ relationCount );
180
-
181
- // Add whereIn to the query.
182
- return $ this ->whereIn ($ key , $ relatedIds , $ boolean , $ not );
163
+ return array_keys ($ relationCount );
183
164
}
184
165
}
0 commit comments