Laravel 5.8 whereHasMorph "dot" syntax not supported? - laravel

Laravel 5.8 introduced whereHasMorph for querying polymorphic relationships. https://laravel.com/docs/5.8/eloquent-relationships#querying-relations
I might be missing something, but it doesn't seem to support dot syntax.
In a regular relationship, I would be able to do something like:
$comments->whereHasMorph(
'video.someRelationship', function ($query) {
$query->where(...);
});
But with whereHasMorph that doesn't seem to work:
$comments->whereHasMorph(
'commentable.someRelationship',
[Video::class, Audio::class],
function ($query) {
$query->where(...);
}
);
If it's indeed not supported, is there a way around it?

whereHasMorph() doesn't (and can't) support the "dot syntax".
Use whereHas() inside the closure for the nested relationship:
$comments->whereHasMorph(
'commentable',
[Video::class, Audio::class],
function ($query) {
$query->where(...) // Constraint on "commentable"
->whereHas('someRelationship', function ($query) {
$query->where(...); // Constraint on "someRelationship"
});
}
);

Related

Laravel prioritize or operator in relation query (hasMany). How to add parenthesis?

The events method in my model returns all related events from the database. The code below is working fine, the only problem is dat it don't prioritze the or. (See orWhereHas)
public function events()
{
return $this->hasMany(Event::class)
->orWhereHas('organisations', function(Builder $query){
$query->where('organisation_id', $this->id);
});
}
When I extend the query somewhere else in the code, it goes wrong:
$model->events()->whereNull('some_field')
Because it should prioritize the OR operator. But I don't know how to do that in this case because I am imitating the query from a model relation.
So the question is: how to add parenthesis in the query to prioritize the or operator?
You could move the logic outside the relationship method and use a where/orWhere Closure.
public function events()
{
return $this->hasMany(Event::class)
}
$model->events()
->where(function ($sub) {
$sub->orWhereHas('organisations', function(Builder $query){
$query->where('organisation_id', $this->id);
})
->orWhereNull('some_field');
})

WhereNotIn inside WhereHas

why whereNotIn doesn't work inside whereHas?
Model::whereHas('statuses', function ($query) {
$query->whereNotIn('title',['X,'Y','Z']);
})
I posted as answer workarounds but can someone explain it or it's BUG?
Laravel 6
Some workarounds:
->whereDoesntHave('statuses', function ($query) {
$query->whereIn('title',['X','Y','Z']);
})
or
->whereHas('statuses', function ($query) {
$query->whereIn('title', ['X,'Y','Z']);
$query->having(\DB::raw("COUNT(table_statuses.id)"), '=', 0);
})
It's not a bug, it only works if the relationship is one to one if it one to many you have to use whereDoesnHave

Return keyword in query callback

Is it necessary to write return keyword while using whereHas in laravel.
For eg. return $query->where('status', 1);
$posts = App\Post::whereHas('comments', function ($query) {
$query->whereHas('content', function ($query){
$query->where('status', 1);
});
})->get();
Do we need to write return in every query callback?
No, you're modifying the query builder instance passed to your closure by calling $query->where('status', 1);. Since objects are passed by reference and where() mutates this instance, there's no need to return anything.
There is no need. Also you can use whereHas with nested relationship.
Example:
$posts = App\Post::whereHas('comments.content', function ($query) {
$query->where('status', 1);
})->get();
No. Because you have the same object (and modify it) inside every function. No need to return.

use eloquent whereRaw($query) if $query not null

i wanna use whereRaw() in laravel app.
can i use laravel eloquent whereRaw($query) just when $query has exist?
Hard to say what exactly you want to achieve because you haven't showed a piece of code but you could use:
$yourQuery->when($query, function($q) use ($query) {
$q->whereRaw($query);
});
of course you can also use condition:
if ($query) {
$yourQuery->whereRaw($query);
}

Getting a relationship with a condition?

I have category and article tables, they are in a many to many relationship. i have the relationships set up on the models.
How can I get all articles where a category id is = 1?
I've tried:
Article::whereHas('category', function ($query) use ($id) {
$query->where('category_id', $id);
})->get();
The above works, but seems clunky, is there a more efficient way in eloquent to do this?
You can use eager loading technique.
Article::with(['category', function ($query) use ($id) {
$query->where('category_id', $id);
}])->get();
The following groupBy code is assuming that Category::find($id)->articles is not an option for whatever reason.
What about groupBy?
Article::groupBy('category')
->having('category', $id)
->get();
whereHas will return articles that match that condition, but won’t filter articles then fetched by the same conditions. You could therefore create an anonymous function that contains the constraints, and pass it to both the whereHas and with methods:
$filter = function ($query) use ($categoryId) {
$query->where('category_id', '=', $categoryId);
};
Article::whereHas('category', $filter)
->with(['category' => $filter])
->get();

Resources