Laravel : Search Query Within Relationship - laravel

When I am adding a new post in my app there is a 7 tables to affect when I add single post. To fetch all posts with all post data my simple query look like:
$userPost = Post::with(['product','postattribute.attribute.category','user.userDetails'])
->offset($offset)
->limit($limit)
->whereStatus("Active")
->whereIn('product_id', $userApprovalProductIDs)
->orderBy('id','desc')
->get();
So it is retrun all data which I want. Now I want to implement search query within all tables, currently I am able to search only posts table.
If I am doing search on category table with categoryTitle I am trying to code like
where('category.title','=', $serachTitle)
But it is not working in my case.
POST model relationship :
public function user() {
return $this->belongsTo(User::class);
}
public function product() {
return $this->belongsTo(Product::class);
}
public function postattribute() {
return $this->hasMany(PostAttribute::class);
}
POSTATTRIBUTES model relationship :
public function post() {
return $this->belongsTo(Post::class);
}
public function attribute() {
return $this->belongsTo(Attribute::class);
}
ATTRIBUTES model relationship :
public function category() {
return $this->belongsTo(Category::class);
}
public function attributes() {
return $this->belongsTo(Attribute::class);
}
How can I do this ?

To apply filter on your nested relations you could use whereHas
$userPost = Post::with(['product','postattribute.attribute.category','user.userDetails'])
->offset($offset)
->limit($limit)
->whereStatus("Active")
->whereIn('product_id', $userApprovalProductIDs)
->whereHas('postattribute.attribute.category', function ($query) use($serachTitle) {
$query->where('title', '=', $searchTitle);
})
->orderBy('id','desc')
->get();
Querying Relationship Existence
From comments what i understood is you want to know how to search within each relation for a post , I already added an example to search with category title
->whereHas('postattribute.attribute', function ($query) use($var) {
$query->where('some_field_of_attribute_table', '=', $var);
})
->whereHas('postattribute', function ($query) use($var) {
$query->where('some_field_of_postattribute_table', '=', $var);
})

Related

Laravel check hasMany of hasMany relationship if has IDs?

Hello I have the following relationship setup:
Product class:
public function attributes()
{
return $this->hasMany(ProductAttribute::class);
}
ProductAttribute class:
public function attribute()
{
return $this->belongsTo(Attribute::class);
}
public function values()
{
return $this->hasMany(ProductAttributeValue::class, 'product_attribute_id');
}
ProductAttributeValue class:
public function attributeValue()
{
return $this->belongsTo(AttributeValue::class, 'attribute_value_id');
}
How to check if Product has values with ids 5 and 15?
I am trying to make a query like this:
Product::whereHas('values', function($q) use ($product_values_ids) {
$q->whereIn('attribute_value_id', $product_values_ids);
})->get();
however it is not working. I cannot access directly $product->values.
Any suggestions on how to access directly the values of attributes from the Product?
Update:
I have just managed to make it work with a many to many trough relationship:
Product class:
public function values()
{
return $this->hasManyThrough(ProductAttributeValue::class, ProductAttribute::class);
}
is there a way to get only the results that have all the ids listed in the $product_values_ids array?
You have to add new relation to Product model:
public function values(): HasManyThrough
{
return $this->hasManyThrough(ProductAttributeValue::class, ProductAttribute::class);
}
and then:
$builder = Product::query();
foreach($product_values_ids as $id) {
$builder->whereHas('values', function($q) use ($id) {
$q->where('id', $id);
});
}
$product = $builder->get();

Sort eloquent model with relationships Laravel

I have a model that I want to sort based on a relationship property.
First model "DeviceType":
public function make()
{
return $this->hasMany(DeviceMake::class);
}
Second model: "DeviceMake":
public function type()
{
return $this->hasOne(DeviceType::class, 'id', 'device_type_id');
}
public function model()
{
return $this->hasMany(DeviceModel::class);
}
Controller:
$type = DeviceType::with(['make'])->where('id', '=', $device_type_id)->first();
Table name is device_makes and I want to sort it by name. How can I do this?
And what about?
$type = DeviceType::with(['make' => function ($query) {
$query->orderBy('name', 'asc');
}])->where('id', '=', $device_type_id)->first();
Please note that first() will only return the first model that matches your query whereas get() will return all of them.
Maybe you could try this instead in your Model:
public function make() {
return $this->hasMany(DeviceMake::class)->orderBy('name', 'asc');
}

Order on second degree relationship in Eloquent

I have two models in a many-to-many relationship: Fixture and Event.
Fixture:
public function events()
{
return $this->belongsToMany(Event::class, 'fixture_events')->withPivot('player_id');
}
Event:
public function fixtures()
{
return $this->belongsToMany(Fixture::class, 'fixture_events')->withPivot('player_id');
}
You will notice that the pivot table has an additional field player_id. This is because FixtureEvent also had a relationship to a model called Player.
FixtureEvent:
public function fixture()
{
return $this->hasOne(Fixture::class, 'id', 'fixture_id');
}
public function event()
{
return $this->hasOne(Event::class, 'id', 'event_id');
}
public function player()
{
return $this->belongsTo(Player::class, 'id', 'player_id');
}
And Player has:
public function events()
{
return $this->hasMany(FixtureEvent::class);
}
My problem arises when I want to get all the fixture_events for a player and sort them by a field in the events table. This field is named sequence.
However, whatever I do, the events always come out ordered by ID.
This is the query that I would like to order by events.sequence, whether by using some type of join or whatever works (this is inside the Player model so $this is a player object):
$events = $this->events()->whereHas('fixture', function ($query) use ($round, $competition_id) {
$query->where('fixtures.round', '=', $round)->where('competition_id', $competition_id);
})->get();
I've tried adding a join query here on fixture_events.event_id = events.id and then ordering by events.sequence but this doesn't work.
I've also tried adding orderBy directly in the model relationship, i.e. in the Fixture model:
public function events()
{
return $this->belongsToMany(Event::class, 'fixture_events')->orderBy('sequence')->withPivot('player_id');
}
But this does nothing for my problem.
How do I make this happen?
Update
At first I misread the relations, can you try with the below query?
$events = $this->events()->whereHas('fixture', function ($query) use ($round, $competition_id) {
$query->where('fixtures.round', '=', $round)->where('competition_id', $competition_id);
})->with(['events.event' => function ($query) {
$query->orderBy('sequence');
}])->get();
You have a couple of alternatives, but first I suggest you to edit your relationship to include the sequence field you are trying to load.
Then proceed with one of the following:
Order by on the relationship definition, but I think you have to load that field from the pivot table, otherwise you won't have its value, and prefix the relations table on the orderby field.
public function events() {
return $this->belongsToMany(Event::class, 'fixture_events')
->withPivot(['player_id', 'sequence'])
->orderBy('fixture_events.sequence');
}
or with:
public function events() {
return $this->belongsToMany(Event::class, 'fixture_events')
->withPivot(['player_id', 'sequence'])
->orderBy('pivot_sequence');
}
Order by a pivot field outside the relation can be done like this:
$events = $this->events()->whereHas('fixture', function ($query) use ($round, $competition_id) {
$query->where('fixtures.round', '=', $round)->where('competition_id', $competition_id);
})->with(['fixture' => function ($query) {
$query->orderBy('sequence');
}])->get();
or with:
$events = $this->events()->whereHas('fixture', function ($query) use ($round, $competition_id) {
$query->where('fixtures.round', '=', $round)->where('competition_id', $competition_id);
})
->orderBy('pivot_sequence')
->get();
Let me know if any of these methods works!

Relationships in Laravel Models

How can I write this without a join for a scope in a Laravel model as the 'id' field becomes ambiguous
/**
* Return events that social category name
*/
public function scopeWithSocialEvents($query)
{
return $query->join('categories', 'events.event_type_id', '=', 'categories.id')
->where('categories.name', 'social');
}
Use this:
public function eventType()
{
return $this->belongsTo(Category::class);
}
public function scopeWithSocialEvents($query)
{
return $query->whereHas('eventType', function($query) {
$query->where('name', 'social');
});
}

Eloquent hasMany filter and eager loading

I'm creating an application with Laravel and I'm trying to work with Eloquent. I have two tables : Orders and Items.
Each items has a type (int data) :
1 => book
2 => video
Each order has ONE book and many videos.
In my Order model, I would like to have a book and others items relationships. So, I have this code :
public function book()
{
return $this->hasMany('App\Item')->where('type', 1)->first();
}
public function others()
{
return $this->hasMany('App\Item')->where('type', '!=', 1)->get();
}
But, if I use eager loading with my relationship, I got an error :
Order::with(['book', 'others'])->get();
Can you help me to solve this problem ?
Thanks
Define relationships like this to make your code work:
public function book()
{
return $this->hasOne('App\Item')->where('type', 1);
}
public function others()
{
return $this->hasMany('App\Item')->where('type', '!=', 1);
}
But it's better to define relationships without where constraints:
public function book()
{
return $this->hasOne('App\Item');
}
public function others()
{
return $this->hasMany('App\Item');
}
And then do this:
Order::with(['book' => function ($q) {
$q->where('type', 1);
},
'others' => function ($q) {
$q->where('type', '!=', 1);
}])
->get();

Resources