Skip to content

Commit 16ccf53

Browse files
committed
Improve error handling on unsupported hybrid queries
Hybrid belongs-to-many relationships are not supported for query constraints. However, the support check was done downstream of a bunch of Eloquent stuff, resulting in the user getting an exception that didn't tell them anything about the usage being unsupported. This moves that check further up the chain so that the user is alerted to the lack of support before we do anything else.
1 parent 7a0f0bc commit 16ccf53

File tree

2 files changed

+49
-8
lines changed

2 files changed

+49
-8
lines changed

src/Helpers/QueriesRelationships.php

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,8 @@ protected function isAcrossConnections(Relation $relation)
104104
*/
105105
public function addHybridHas(Relation $relation, $operator = '>=', $count = 1, $boolean = 'and', ?Closure $callback = null)
106106
{
107+
$this->assertHybridRelationSupported($relation);
108+
107109
$hasQuery = $relation->getQuery();
108110
if ($callback) {
109111
$hasQuery->callScope($callback);
@@ -128,6 +130,26 @@ public function addHybridHas(Relation $relation, $operator = '>=', $count = 1, $
128130
return $this->whereIn($this->getRelatedConstraintKey($relation), $relatedIds, $boolean, $not);
129131
}
130132

133+
/**
134+
* @param Relation $relation
135+
*
136+
* @return void
137+
*
138+
* @throws Exception
139+
*/
140+
public function assertHybridRelationSupported(Relation $relation): void
141+
{
142+
if (
143+
$relation instanceof HasOneOrMany
144+
|| $relation instanceof BelongsTo
145+
|| ($relation instanceof BelongsToMany && ! $this->isAcrossConnections($relation))
146+
) {
147+
return;
148+
}
149+
150+
throw new Exception(class_basename($relation) . ' is not supported for hybrid query constraints.');
151+
}
152+
131153
/**
132154
* @param Builder $hasQuery
133155
* @param Relation $relation
@@ -213,6 +235,8 @@ protected function getConstrainedRelatedIds($relations, $operator, $count)
213235
*/
214236
protected function getRelatedConstraintKey(Relation $relation)
215237
{
238+
$this->assertHybridRelationSupported($relation);
239+
216240
if ($relation instanceof HasOneOrMany) {
217241
return $relation->getLocalKeyName();
218242
}
@@ -221,7 +245,7 @@ protected function getRelatedConstraintKey(Relation $relation)
221245
return $relation->getForeignKeyName();
222246
}
223247

224-
if ($relation instanceof BelongsToMany && ! $this->isAcrossConnections($relation)) {
248+
if ($relation instanceof BelongsToMany) {
225249
return $this->model->getKeyName();
226250
}
227251

tests/HybridRelationsTest.php

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ public function testSqlRelations()
7878
$this->assertEquals('John Doe', $role->sqlUser->name);
7979

8080
// MongoDB User
81-
$user = new User();
81+
$user = new User();
8282
$user->name = 'John Doe';
8383
$user->save();
8484

@@ -105,7 +105,7 @@ public function testSqlRelations()
105105

106106
public function testHybridWhereHas()
107107
{
108-
$user = new SqlUser();
108+
$user = new SqlUser();
109109
$otherUser = new SqlUser();
110110
$this->assertInstanceOf(SqlUser::class, $user);
111111
$this->assertInstanceOf(SQLiteConnection::class, $user->getConnection());
@@ -114,11 +114,11 @@ public function testHybridWhereHas()
114114

115115
// SQL User
116116
$user->name = 'John Doe';
117-
$user->id = 2;
117+
$user->id = 2;
118118
$user->save();
119119
// Other user
120120
$otherUser->name = 'Other User';
121-
$otherUser->id = 3;
121+
$otherUser->id = 3;
122122
$otherUser->save();
123123
// Make sure they are created
124124
$this->assertIsInt($user->id);
@@ -159,7 +159,7 @@ public function testHybridWhereHas()
159159

160160
public function testHybridWith()
161161
{
162-
$user = new SqlUser();
162+
$user = new SqlUser();
163163
$otherUser = new SqlUser();
164164
$this->assertInstanceOf(SqlUser::class, $user);
165165
$this->assertInstanceOf(SQLiteConnection::class, $user->getConnection());
@@ -168,11 +168,11 @@ public function testHybridWith()
168168

169169
// SQL User
170170
$user->name = 'John Doe';
171-
$user->id = 2;
171+
$user->id = 2;
172172
$user->save();
173173
// Other user
174174
$otherUser->name = 'Other User';
175-
$otherUser->id = 3;
175+
$otherUser->id = 3;
176176
$otherUser->save();
177177
// Make sure they are created
178178
$this->assertIsInt($user->id);
@@ -268,6 +268,23 @@ public function testHybridBelongsToMany()
268268
$this->assertEquals(1, $check->skills->count());
269269
}
270270

271+
public function testQueryingHybridBelongsToManyRelationFails()
272+
{
273+
$user = new SqlUser();
274+
$this->assertInstanceOf(SQLiteConnection::class, $user->getConnection());
275+
276+
// Create Mysql Users
277+
$user->fill(['name' => 'John Doe'])->save();
278+
$skill = Skill::query()->create(['name' => 'MongoDB']);
279+
$user->skills()->save($skill);
280+
281+
$this->expectExceptionMessage('BelongsToMany is not supported for hybrid query constraints.');
282+
283+
SqlUser::whereHas('skills', function ($query) {
284+
return $query->where('name', 'LIKE', 'MongoDB');
285+
});
286+
}
287+
271288
public function testHybridMorphToManySqlModelToMongoModel()
272289
{
273290
// SqlModel -> MorphToMany -> MongoModel

0 commit comments

Comments
 (0)